想象一下,你正在为公司开发一个智能客服系统,产品经理突然提出需求:"用户问天气的时候,系统能不能自动调用天气API,而不是只会说'请稍等,我帮您查询'?"
本文将通过实战代码,教你如何让C#应用获得**"函数调用"**这一AI时代的核心能力,让你的程序不再是简单的问答机器人,而是真正具备执行能力的智能助手。
传统的AI对话系统存在一个致命缺陷:只能"说"不能"做"。
用户问:"明天需要穿雨衣吗?"
传统AI回答:"抱歉,我无法获取实时天气信息,请您查询天气预报。"
这种体验让用户感觉AI"很傻",明明知道用户需要什么,却无法主动帮助解决问题。而**Function Calling(函数调用)**技术的出现,彻底改变了这一现状。
让我们先看看如何创建一个能够主动获取天气信息的AI助手:
C#using System.ComponentModel;
using System.Text;
using Microsoft.Extensions.AI;
using OllamaSharp;
namespace SmartWeatherAssistant
{
internal class Program
{
static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
// 🎯 关键点1:使用Description特性让AI理解函数用途
[Description("获取指定城市的当前天气情况,返回晴天或雨天")]
string GetCurrentWeather(
[Description("城市名称,如:北京、上海、广州")]
string city = "当前位置")
{
// 🔧 实际项目中,这里应该调用真实的天气API
var weather = Random.Shared.NextDouble() > 0.5 ? "晴天" : "雨天";
Console.WriteLine($"[系统] 正在获取{city}的天气信息...");
Console.WriteLine($"[结果] {city}当前天气:{weather}");
return $"{city}现在是{weather}";
}
// 🚀 初始化Ollama客户端(需要本地运行Ollama服务)
IChatClient client = new OllamaApiClient(
new Uri("http://localhost:11434"),
"qwen2.5:3b"); // 使用轻量级的3B模型
// 🔥 关键点2:启用函数调用功能
client = ChatClientBuilderChatClientExtensions
.AsBuilder(client)
.UseFunctionInvocation() // 这一行是魔法所在!
.Build();
// 🛠️ 配置可用的工具函数
ChatOptions options = new()
{
Tools = [AIFunctionFactory.Create(GetCurrentWeather)]
};
Console.WriteLine("🤖 智能天气助手已启动,请输入您的问题:");
// 💬 处理用户输入
var userInput = "明天北京需要穿雨衣吗?";
Console.WriteLine($"👤 用户:{userInput}");
Console.WriteLine("🤖 助手:");
// 🎬 流式响应,实时显示AI思考过程
var response = client.GetStreamingResponseAsync(userInput, options);
await foreach (var update in response)
{
Console.Write(update);
}
}
}
}

💡 核心原理解析:
在实际项目中,我们通常需要为AI提供多个功能函数:
C#using System.ComponentModel;
using System.Text;
using Microsoft.Extensions.AI;
using OllamaSharp;
namespace EnterpriseAIAssistant
{
internal class Program
{
static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
// 🌤️ 天气查询功能
[Description("查询指定城市的天气状况")]
string GetWeather([Description("城市名称")] string city)
{
var conditions = new[] { "晴天", "多云", "小雨", "大雨" };
var weather = conditions[Random.Shared.Next(conditions.Length)];
return $"{city}当前天气:{weather},温度:{Random.Shared.Next(15, 35)}°C";
}
// 📊 股票查询功能
[Description("获取股票的当前价格信息")]
string GetStockPrice([Description("股票代码,如:AAPL, MSFT")] string symbol)
{
var price = (Random.Shared.NextDouble() * 1000).ToString("F2");
var change = (Random.Shared.NextDouble() - 0.5) * 20;
var changeStr = change > 0 ? $"+{change:F2}" : $"{change:F2}";
return $"{symbol} 当前价格:${price} ({changeStr})";
}
// ⏰ 时间提醒功能
[Description("设置提醒任务")]
string SetReminder(
[Description("提醒内容")] string content,
[Description("提醒时间,格式:HH:mm")] string time)
{
Console.WriteLine($"[系统] 已设置提醒:{time} - {content}");
return $"提醒已设置:将在{time}提醒您{content}";
}
// 🔧 初始化AI客户端
IChatClient client = new OllamaApiClient(
new Uri("http://localhost:11434"),
"qwen2.5:3b");
client = ChatClientBuilderChatClientExtensions
.AsBuilder(client)
.UseFunctionInvocation()
.Build();
// 🎯 注册所有可用工具
ChatOptions options = new()
{
Tools = [
AIFunctionFactory.Create(GetWeather),
AIFunctionFactory.Create(GetStockPrice),
AIFunctionFactory.Create(SetReminder)
]
};
// 💼 模拟企业级对话场景
var queries = new[]
{
"帮我查一下上海的天气,顺便看看苹果股票怎么样",
"提醒我下午3点开会",
"北京明天适合户外活动吗?"
};
foreach (var query in queries)
{
Console.WriteLine($"\n👤 用户:{query}");
Console.WriteLine("🤖 助手:");
var response = client.GetStreamingResponseAsync(query, options);
await foreach (var update in response)
{
Console.Write(update);
}
Console.WriteLine("\n" + new string('-', 50));
}
}
}
}

Bash# 确保Ollama服务正在运行
ollama serve
C#// ❌ 错误:使用不支持函数调用的模型
"llama2:7b"
// ✅ 正确:使用支持函数调用的模型
"qwen2.5:3b"
"llama3.1:8b"
C#// ❌ 错误:复杂类型参数
[Description("查询用户信息")]
string GetUserInfo(UserModel user) { } // AI无法理解自定义类型
// ✅ 正确:基础类型参数
[Description("查询用户信息")]
string GetUserInfo(string userId, string userName) { }
AI时代的C#开发不再是简单的CRUD操作,而是要让代码具备**"理解 → 决策 → 执行"的完整智能链路。通过Function Calling**技术,我们可以:
💬 互动话题:
如果这篇文章对你有帮助,请转发给更多同行!让我们一起拥抱AI时代的C#开发新范式! 🚀
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!