记得三年前, .NET开发者想尝试AI应用,第一步往往是先搭建一个Python环境。看着别人在PyCharm里轻松运行LangChain项目,自己只能在Visual Studio里望洋兴叹。那时候用C#搞AI,感觉就像用菜刀做手术——理论上可行,但实际操作起来处处别扭。
但时至今日,局面已彻底不同。微软携Semantic Kernel 1.6、Microsoft.Extensions.AI与原生集成AI能力的.NET 9强势回归。现在的C#不仅能跑AI,甚至在稳定性、性能与资源利用效率上,都展现出了独特的优势。这篇文章不讲空泛的概念,只分享从开发到上线过程中,那些用真金白银和时间换来的实战经验与避坑指南。
一、技术选型:三条核心路线剖析
当前C#的AI生态主要围绕三大技术路线展开,初始选择至关重要,选错了后续开发会步履维艰。
路线A:Microsoft.Extensions.AI(现代标准)
这是微软在2025年力推的“官方答案”,你可以将其理解为AI领域的Entity Framework。它的核心理念是提供一套统一的抽象API,让你在不同模型提供商之间切换时,无需重写业务逻辑。通过NuGet包Microsoft.Extensions.AI(最新预览版为9.3.0-preview),你可以使用IChatClient这样的接口,无论是调用OpenAI、Azure OpenAI还是本地的Ollama,代码结构都保持一致。
它的优势在于对依赖注入(DI)支持极佳,中间件生态完善,特别适合集成到现有的ASP.NET Core应用中。其缺点是目前仍处于preview阶段,API存在变动的风险(例如,近期CompleteAsync方法就改名为GetResponseAsync)。
路线B:Semantic Kernel(成熟稳定)
如果你要构建真正的智能体(Agent)——即能够调用函数、具备记忆和任务规划能力的AI应用——Semantic Kernel是目前C#生态中唯一达到生产级成熟度的选择。SK 1.6版本已正式发布(GA),支持Ollama、Azure、OpenAI等多种连接器,甚至能与Python的AutoGen框架进行互通。
它的插件(Plugin)系统是一大亮点:只需给你的C#方法标记一个[KernelFunction]特性,AI就能自动识别并调用它,这比在Python中定义工具(Tool)要直观得多。
路线C:ONNX Runtime(极致性能与离线)
追求完全离线运行?不想依赖任何外部服务(包括Ollama)?那么可以直接使用Microsoft.ML.OnnxRuntimeGenAI来加载如Phi-4、Llama 3.2等模型的ONNX格式。这种方式内存占用最低,并且能通过DirectML直接调用NPU或显卡进行硬件加速。代价是,模型的转换、预处理和后处理都需要开发者自己处理。
避坑建议:快速构建原型验证选路线A;开发企业级智能体应用选路线B;面向边缘设备或对隐私有极致要求的场景选路线C。切记不要混合使用不同路线的核心包,否则极易陷入依赖地狱。
二、快速实战:30秒搭建本地AI对话应用
让我们从一个可立即运行的Demo开始。请确保已安装.NET 9 SDK和Ollama(Windows用户可直接从官网下载安装包)。
2.1 初始化项目
dotnet new console -n LocalAI
cd LocalAI
dotnet add package Microsoft.Extensions.AI --version 9.3.0-preview.1.25161.3
dotnet add package Microsoft.Extensions.AI.Ollama --version 9.3.0-preview.1.25161.3
请注意版本号必须写准确。目前Microsoft.Extensions.AI仍处于预览阶段,不同小版本间的API可能存在较大差异。
2.2 完整可运行代码
using Microsoft.Extensions.AI;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 配置Ollama客户端,使用llama3.2:1b模型(约1.3GB,支持函数调用)
IChatClient client = new OllamaChatClient(
new Uri(“http://localhost:11434”),
“llama3.2:1b”
);
Console.WriteLine(“本地AI已启动,输入问题(输入exit退出):”);
while (true)
{
Console.Write(“> “);
var input = Console.ReadLine();
if (input?.ToLower() == “exit”) break;
// 获取流式响应,体验更顺滑
await foreach (var update in client.GetStreamingResponseAsync(input))
{
Console.Write(update.Text);
}
Console.WriteLine(“\n”);
}
}
}
运行前,请确保Ollama服务已启动并拉取了对应模型:
ollama pull llama3.2:1b
ollama serve
关键避坑点:Ollama默认监听11434端口,但Windows防火墙可能会拦截此连接。如果遇到“Connection refused”错误,可以先在终端中使用 curl http://localhost:11434 测试端口连通性。
三、智能体实战:让AI具备执行能力
只会对话的AI是玩具,能调用外部函数、完成具体任务的才是生产力工具。在Semantic Kernel中实现函数调用是目前C#生态中最稳定的方案。
3.1 支持函数调用的智能体代码
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.Ollama;
using System.ComponentModel;
var builder = Kernel.CreateBuilder();
// 使用Ollama连接器,SK 1.6版本支持流式Function Calling
builder.AddOllamaChatCompletion(“llama3.2:3b”, new Uri(“http://localhost:11434”));
var kernel = builder.Build();
// 定义工具函数:模拟获取天气
kernel.ImportPluginFromFunctions(“WeatherPlugin”,
[
KernelFunctionFactory.CreateFromMethod(
[Description(“获取指定城市的天气”)]
(string city) => $"今天{city}多云,25℃”,
“GetWeather”
)
]);
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage(“你是一个助手,可以查询天气。需要时调用工具。”);
while (true)
{
Console.Write(“User: “);
var input = Console.ReadLine();
if (string.IsNullOrEmpty(input)) break;
history.AddUserMessage(input);
// 关键配置:启用自动工具调用
var response = await chatService.GetChatMessageContentAsync(
history,
new PromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() },
kernel
);
Console.WriteLine($"Assistant: {response.Content}”);
history.AddMessage(response.Role, response.Content ?? string.Empty);
}
避坑重点:并非所有模型都支持函数调用(Function Calling)。根据实测,Gemma 3:1b完全无法工作,而Llama 3.2:1b/3b是现阶段参数量较小且能稳定支持工具调用的模型。如果你的AI不调用函数,首要排查对象就是模型选择。
3.2 生产环境中的致命陷阱
上述Demo代码在本地运行顺畅,但直接部署到生产环境几乎必然崩溃:
- 内存泄漏:
ChatHistory对象如果不设置长度限制,在长对话场景下会持续增长,最终撑爆内存。必须实现滑动窗口或对话摘要机制。
- 并发阻塞:Ollama默认以单线程处理推理请求。在高并发场景下,必须启动多个Ollama实例进行负载均衡,或转而使用
ONNX Runtime GenAI直接管理推理会话。
- 异常处理:模型推理过程可能抛出
OnnxRuntimeException或网络超时。必须集成Polly等重试库,制定完善的降级和重试策略。
四、硬核方案:使用ONNX Runtime进行离线部署
对于需要完全离线(如军工、金融内网),或追求极致性能的场景,ONNX Runtime是首选。这里以微软最新开源的轻量级模型Phi-4-mini(3.8B参数,性能接近GPT-3.5)为例。
4.1 环境准备
dotnet add package Microsoft.ML.OnnxRuntimeGenAI.DirectML --version 0.4.0
dotnet add package Microsoft.ML.OnnxRuntimeGenAI --version 0.4.0
你需要从Hugging Face下载Phi-4-mini的ONNX版本(约2.8GB),使用git-lfs拉取:
git lfs install
git clone https://huggingface.co/microsoft/Phi-4-mini-instruct-onnx
4.2 原生C#推理代码
using Microsoft.ML.OnnxRuntimeGenAI;
using System;
using System.Linq;
class OnnxInference
{
static void Main()
{
// 加载模型,DirectML后端支持AMD/Intel/NVIDIA显卡
using var model = new Model(“Phi-4-mini-instruct-onnx/directml”);
using var tokenizer = new Tokenizer(model);
var prompt = “<|user|>\n写一段C#快速排序代码<|end|>\n<|assistant|>\n”;
// 编码输入文本
using var tokens = tokenizer.Encode(prompt);
// 配置生成参数
var generatorParams = new GeneratorParams(model);
generatorParams.SetSearchOption(“max_length”, 2048);
generatorParams.SetSearchOption(“temperature”, 0.7);
generatorParams.SetInputSequences(tokens);
using var generator = new Generator(model, generatorParams);
Console.Write(“生成中:”);
while (!generator.IsDone())
{
generator.ComputeLogits();
generator.GenerateNextToken();
// 解码并输出新生成的token
var newToken = generator.GetSequence(0)[^1];
var text = tokenizer.Decode(new ReadOnlySpan<int>(newToken));
Console.Write(text);
}
}
}
避坑指南:
- 显存管理:Phi-4-mini的INT4量化版本需要约4GB显存/内存。如果遇到
OutOfMemoryException,可尝试使用CPU版本(将模型路径中的directml文件夹替换为cpu文件夹)。
- 输入格式:Phi系列模型对提示词(Prompt)模板非常敏感,必须严格使用
<|user|>、<|assistant|>等特定标记,否则会导致输出乱码。
- 批量处理:避免在循环中单条生成。
ONNX Runtime支持批量推理,能大幅提升吞吐量,效率可能提升五倍以上。
五、生产环境部署检查清单
从演示原型到稳定可用的生产服务,还需要跨过以下几道关键关卡。
5.1 模型选型切勿盲目跟风
模型 适用场景 C#生态支持度 显存/内存需求
Llama 3.2:1b 快速原型、工具调用 ⭐⭐⭐⭐⭐ 约 1.5GB
Phi-4-mini 代码生成、逻辑推理 ⭐⭐⭐⭐ 约 4GB (INT4量化)
Qwen2.5-7B 中文场景、复杂指令 ⭐⭐⭐ 约 8GB
Gemma 3 多模态(图文理解) ⭐⭐ 约 6GB
经验之谈:Qwen系列虽然中文能力出色,但其在Semantic Kernel中的连接器稳定性目前不如Llama,遇到复杂的函数调用逻辑时容易出错。
5.2 监控与日志不可或缺
AI应用必须监控其核心性能指标,尤其是Token生成速度(tokens/second)。可以使用System.Diagnostics简单包装:
var stopwatch = Stopwatch.StartNew();
int tokenCount = 0;
await foreach (var update in client.GetStreamingResponseAsync(prompt))
{
tokenCount++;
// 原有的业务逻辑...
}
Console.WriteLine($"生成性能:{tokenCount / stopwatch.Elapsed.TotalSeconds:F2} tokens/秒”);
如果该速度持续低于10 tokens/s,用户就会感到明显卡顿,此时需要考虑更换更小的模型或启用GPU加速。
5.3 必须严守的安全红线
- 提示词注入(Prompt Injection):永远将用户输入视为不可信的。建议使用
Microsoft.Extensions.AI.Evaluation等库进行内容安全过滤和检测。
- 密钥与访问控制:即使使用本地Ollama,如果将其11434端口暴露在公网,任何人都可随意调用。生产环境务必通过反向代理(如Nginx)进行封装,并添加API Key验证层。
- 模型版权合规:Phi-4和Llama 3.2通常采用MIT或Apache 2.0协议,可安全商用。但许多基于它们进行微调的衍生模型可能有不同的许可证限制,引入前需经过法务审核。
六、写在最后
三年前,C#在AI领域还只是“能用”;今天,它已经变得“好用”甚至“强大”。Microsoft.Extensions.AI的统一抽象、Semantic Kernel成熟的智能体能力、ONNX Runtime带来的原生性能,这三者共同作用,让Python在AI领域的绝对统治地位出现了真实的裂痕。
对于广大.NET开发者而言,最大的优势在于技术栈的统一:你可以用Blazor构建前端,用ASP.NET Core实现后端业务,再用Semantic Kernel集成AI能力,全程使用C#。这带来了无与伦比的类型安全、便捷的重构以及简单的部署流程,无需再为了一个AI功能而强行引入一个Python微服务,从而避免制造出“微服务地狱”。
当然,挑战依然存在:模型的整体生态丰富度仍不及Python;一些最前沿的学术成果可能只有PyTorch实现;社区积累的解决方案(如Stack Overflow上的回答)也相对较少。但这恰恰也是机遇所在。现在投身于C# AI生态的开发者,当这个生态全面爆发时,将成为最具经验的那一批人。
更新你的Visual Studio,安装好.NET 9 SDK,今晚就可以开始你的第一个C# AI项目。在云栈社区的.NET和人工智能板块,你可以找到更多同行的分享与讨论。毕竟,在写代码和解决问题这件事上,.NET开发者从来都不缺乏勇气和智慧。