.NET+AI | MEAI | Function Caling 实操(4)
.NET+AI | MEAI | Function Caling 实操
TL;DR
- ✅ 注册你的方法为工具(Tool)
- ✅ 启用中间件
UseFunctionInvocation() - ✅ 设置
ChatOptions.ToolMode = Auto - ✅ 发起对话,MEAI 自动完成:请求 → 调用 → 回填 → 作答

🏢 场景与价值
- 💬 智能助理需要可控访问后端:天气/库存/知识库/工单
- 📦 MEAI 用统一“工具”抽象,屏蔽模型/厂商差异
- 🛡️ 可控、可观测、可扩展(日志/缓存/限流易接入)
🌏 核心概念速记
- 📦 ToolCollection/AITool:把你的方法包装成“可被调用的工具”
- 🎚️ ChatOptions.ToolMode:控制模型是否/如何调用工具(None/Auto/Require)
- 💬 FunctionCallContent / FunctionResultContent:调用意图与函数结果的消息载体
- 📦 FunctionInvokingChatClient:自动完成调用循环的中间件
🚀 快速上手(4 步)
1)获取 ChatClient
// 方式 A:课程辅助类(推荐)
var chatClient = AIClientHelper.GetDefaultChatClient();
// 方式 B:自行创建(示意)
// var chatClient = new OpenAIChatClient(apiKey: "...", model: "gpt-4o-...");
2)注册工具(Tool)
using Microsoft.Extensions.AI;
// 最小示例:无入参,返回字符串
string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
var tools = AIFunctionFactory.Create(GetCurrentWeather, name: "GetCurrentWeather", description: "查询当前天气");
稍复杂(带描述/类型)
using System.ComponentModel;
public record WeatherReport(string City, int TemperatureCelsius, bool WillRain);
public class TravelToolset
{
[Description("查询指定城市的实时天气")]
public WeatherReport QueryWeather(string city)
=> new(city, 25, willRain: false);
}
var travelTools = AIFunctionFactory.CreateFromMethods(new TravelToolset());
3)启用函数调用中间件
var client = chatClient.AsBuilder()
.UseFunctionInvocation() // 🔧 关键:启用自动函数调用
.Build();
4)配置并对话
var messages = new List<ChatMessage>
{
new(ChatRole.System, "你是出行助手,善于调用工具给出穿搭建议。"),
new(ChatRole.User, "帮我查看今天北京的天气,要不要带伞?")
};
var options = new ChatOptions
{
ToolMode = ChatToolMode.Auto,
Tools = [ tools ] // 或 travelTools
};
var response = await client.GetResponseAsync(messages, options);
Console.WriteLine(response.Text);
💻 可运行最小示例
依赖:Microsoft.Extensions.AI(以及选用的提供方实现,如 Microsoft.Extensions.AI.OpenAI 或 Azure.AI.OpenAI)
using System;
using System.Collections.Generic;
using Microsoft.Extensions.AI;
class Program
{
static async System.Threading.Tasks.Task Main()
{
// 1) 获取 ChatClient
var chatClient = AIClientHelper.GetDefaultChatClient();
// 2) 注册工具
string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
var tools = AIFunctionFactory.Create(GetCurrentWeather, name: "GetCurrentWeather", description: "查询当前天气");
// 3) 启用函数调用
var client = chatClient.AsBuilder().UseFunctionInvocation().Build();
// 4) 配置与对话
var messages = new List<ChatMessage>
{
new(ChatRole.System, "你是出行助手,善于调用工具给出穿搭建议。"),
new(ChatRole.User, "帮我查看今天北京的天气,要不要带伞?")
};
var options = new ChatOptions { ToolMode = ChatToolMode.Auto, Tools = [ tools ] };
var result = await client.GetResponseAsync(messages, options);
Console.WriteLine(result.Text);
}
}
🔄 执行流程图(Mermaid)

📊 ToolMode 速查表
| 模式 | 含义 | 适用场景 |
|---|---|---|
| None | 禁用工具调用 | 只对话,不走工具 |
| Auto | 模型自行决定是否调用 | 通用推荐,灵活强 |
| RequireAny | 必须调用任意一个工具 | 强制走工具流程 |
| RequireSpecific("name") | 必须调用指定工具 | 固定关键步骤 |
❓ 常见问题与解决
- 模型没调用工具?
- 🔍 检查
ToolMode是否为Auto/Require* - 🔍 工具名称/描述/参数是否清晰、可推断
- 🔍 检查
- 传参不匹配/解析失败?
- 📝 明确参数类型与描述,避免模糊命名
- 🛡️ 约束输入(枚举/范围),必要时抛出可读异常
- 多次工具调用链过长?
- 🎯 收敛任务目标,提供清晰系统提示与结果格式
- 🎚️ 需要一步到位时,用
RequireSpecific强制关键工具
✅ 最佳实践
- ✍️ 工具命名与描述精炼,面向“模型读者”
- 🧩 工具只做一件事;返回结构化结果(record/class)更稳
- 📦 基于
UseFunctionInvocation叠加中间件:日志/缓存/限流 - ♻️ 通用能力注册到全局
AdditionalTools,场景内复用 - 🧯 设置兜底回答与失败重试,提升健壮性
✨ 总结
MEAI 的函数调用把“模型 + 你的业务能力”无缝拼起来:声明工具、打开开关、开始对话,剩下的交给中间件自动编排。
👆面向.NET开发者的AI Agent 开发课程【.NET+AI | 智能体开发进阶】已上线,欢迎扫码加入学习。👆
关注我的公众号『向 AI 而行』,我们微信不见不散。
阅罢此文,如果您觉得本文不错并有所收获,请【打赏】或【推荐】,也可【评论】留下您的问题或建议与我交流。 你的支持是我不断创作和分享的不竭动力!
作者:『圣杰』
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号