C# 中集成 AI 工具调用(Tool Calling)功能
本文包含AI辅助创作内容
背景
部分 AI 平台的 API 不支持原生联网搜索功能,需要自行通过 Web Search 接口查询实时信息,再将结果反馈给 AI 进行回答。本文以 DeepSeek 接口为例,演示如何在 C# 中为 AI 接口添加 web_search 工具调用能力。
基础调用:不带工具
在 C# 中使用 AI 接口,可以借助 Microsoft.Extensions.AI.OpenAI 库构建调用:
var clientOptions = new OpenAIClientOptions
{
Endpoint = new Uri("https://api.deepseek.com"),
};
var openAIClient = new OpenAIClient(
new ApiKeyCredential(configuration.GetSection("DeepSeekApiKey").Value ?? ""),
clientOptions);
var chatClient = openAIClient.GetChatClient("deepseek-v4-pro").AsIChatClient();
var userPrompt = "杭州哪里的菜最好吃";
List<ChatMessage> messages =
[
new(ChatRole.User, userPrompt),
];
var chatOptions = new ChatOptions()
{
AdditionalProperties = new AdditionalPropertiesDictionary()
{
["thinking"] = new { type = "disabled" }
},
};
var response = await chatClient.GetResponseAsync(messages, chatOptions);
Console.WriteLine(response.Messages[0]);
⚠️ 上述方式返回的结果取决于模型训练数据的截止时间,无法获取实时信息。
进阶调用:添加搜索工具
为了让 AI 能够获取实时信息,我们需要:
web_search 工具
1 定义 System Prompt
通过 System Prompt 强制 AI 在回答前调用搜索工具:
var systemPrompt = @"# 角色与目标
你是一个AI助手。你的目标是提供准确、有用且思考缜密的回答。
# 工具使用
用户的问题**你必须**调用 web_search 工具进行搜索
# 核心行为准则
1. **思考先行**:在回答前,先进行深度、严谨的逻辑推导。
2. **精准与深度**:回答要直击要害,优先提供最具价值的核心信息。
3. **诚实与谦逊**:如果问题超出知识范围或无法确定,请明确告知。
4. **避免重复与冗余**:不要复述用户的问题,直接给出解答。
# 语言与风格
1. **语言**:使用与用户提问相同的语言进行回复。
2. **风格**:专业、清晰、冷静、精炼。
3. **格式**:优先使用 Markdown 格式,善用标题和列表。";
2 构建消息与注册工具
List<ChatMessage> messages =
[
new(ChatRole.System, systemPrompt),
new(ChatRole.User, userPrompt),
];
// 定义搜索工具
var searchToolName = "web_search";
var searchTool = AIFunctionFactory.Create(
SearchWeb,
searchToolName,
"当用户需要实时、最新的网络信息时,使用此工具进行搜索");
var chatOptions = new ChatOptions()
{
Tools = [searchTool],
AdditionalProperties = new AdditionalPropertiesDictionary()
{
["thinking"] = new { type = "disabled" }
},
};
3 处理工具调用流程
var response = await chatClient.GetResponseAsync(messages, chatOptions);
var message = response.Messages[0];
// 检查 AI 是否返回了工具调用请求
var functionCalls = message.Contents.OfType<FunctionCallContent>().ToList();
if (functionCalls.Count > 0)
{
// 将 AI 的工具调用消息加入对话历史
var assistantMsg = new ChatMessage(ChatRole.Assistant, message.Contents);
messages.Add(assistantMsg);
foreach (var toolCall in functionCalls)
{
if (toolCall.Name == searchToolName
&& toolCall.Arguments?.TryGetValue("query", out object? value) == true)
{
var query = value?.ToString() ?? "";
// 执行搜索
var searchResult = await SearchWeb(query);
// 构建工具调用结果消息,回传给 AI
var resultMessage = new ChatMessage(
ChatRole.Tool,
[new FunctionResultContent(toolCall.CallId, searchResult)]);
messages.Add(resultMessage);
}
}
// 携带搜索结果,重新请求 AI 生成最终回答
var finalResponse = await chatClient.GetResponseAsync(messages, chatOptions);
message = finalResponse.Messages[0];
}
Console.WriteLine(message);
搜索接口实现
Web Search 接口可以使用博查 API,以下为 SearchWeb 方法的实现:
async Task<string> SearchWeb(string query)
{
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(20);
httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "YOUR_API_KEY");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
var payload = new
{
query = query,
freshness = "noLimit",
summary = true,
count = 10
};
var jsonPayload = Newtonsoft.Json.JsonConvert.SerializeObject(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(
"https://api.bochaai.com/v1/web-search", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync() ?? "";
}
完整流程示意
通过 Tool Calling 机制,AI 会自动判断是否需要调用搜索工具,再结合搜索结果给出准确的实时回答,有效弥补了模型训练数据时效性的不足。
请先 登录后发表评论 ~