AutoGen.NET 中使用 SemanticKernelAgent 实现简单聊天:流式与非流式消息处理全解析
本文聚焦 AutoGen.NET 的 AutoGen.SemanticKernel 包中的 SemanticKernelAgent,讲解如何基于 Semantic Kernel 的 Kernel 对象创建智能体,并以非流式和流式两种方式与其对话。读完后你将掌握:SemanticKernelAgent 构造函数的全部参数含义、SendAsync 与 GenerateStreamingReplyAsync 的完整调用方式、消息类型的封装与解封装(MessageEnvelope<ChatMessageContent>),以及默认执行参数(Temperature、MaxTokens 等)在源码层面的实际取值,帮助你把 Semantic Kernel 无缝接入 AutoGen 的代理式编程模型。
1. 前置准备:依赖与 Kernel 构建
SemanticKernelAgent 位于 dotnet/src/AutoGen.SemanticKernel/SemanticKernelAgent.cs,其所在包 AutoGen.SemanticKernel.csproj 引用了 Microsoft.SemanticKernel、Microsoft.SemanticKernel.Agents.Core 与 Microsoft.SemanticKernel.Connectors.AzureOpenAI 三个 NuGet 包,并依赖核心项目 AutoGen.Core。
使用它的前提是先在本地构建一个 Semantic Kernel 的 Kernel 实例,并为其注册一个 IChatCompletionService。以下示例以 OpenAI 连接器为例:
using AutoGen.Core;
using AutoGen.SemanticKernel;
using AutoGen.SemanticKernel.Extension;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
var openAIKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new Exception("Please set OPENAI_API_KEY environment variable.");
var modelId = "gpt-3.5-turbo";
var builder = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: modelId, apiKey: openAIKey);
var kernel = builder.Build();
上面取自示例工程 SemanticKernelCodeSnippet.cs 中的实际代码,运行前需要设置 OPENAI_API_KEY 环境变量。若使用 Azure OpenAI,测试代码 SemanticKernelAgentTest.cs 展示了对应的 AddAzureOpenAIChatCompletion(deploymentName, endpoint, key) 写法,需要 AZURE_OPENAI_API_KEY、AZURE_OPENAI_ENDPOINT、AZURE_OPENAI_DEPLOY_NAME 三个环境变量。
2. 创建 SemanticKernelAgent 并进行非流式聊天
2.1 构造函数参数说明
SemanticKernelAgent 的构造函数签名为(见 SemanticKernelAgent.cs):
| 参数 | 类型 | 说明 |
|---|---|---|
kernel |
Kernel |
Semantic Kernel 的 Kernel 对象,内部通过它解析 IChatCompletionService |
name |
string |
智能体名称,将作为回复消息的 from 字段 |
systemMessage |
string |
系统消息,默认值为 "You are a helpful AI assistant" |
modelServiceId |
string? |
可选。当 Kernel 注册了多个模型服务时,用该 ID 指定使用哪一个;为 null 时调用 GetRequiredService<IChatCompletionService>() 取默认服务 |
settings |
PromptExecutionSettings? |
可选。显式指定提示执行设置;传入后完全覆盖默认值 |
2.2 完整调用示例
创建智能体并发起一次非流式对话的完整代码(与官方文档 SemanticKernelAgent-simple-chat.md 中的 create_semantic_kernel_agent 代码块一致):
// create a semantic kernel agent
var semanticKernelAgent = new SemanticKernelAgent(
kernel: kernel,
name: "assistant",
systemMessage: "You are an assistant that help user to do some tasks.");
// SemanticKernelAgent supports the following message types:
// - IMessage<ChatMessageContent> where ChatMessageContent is from Azure.AI.OpenAI
var helloMessage = new ChatMessageContent(AuthorRole.User, "Hello");
// Use MessageEnvelope.Create to create an IMessage<ChatRequestMessage>
var chatMessageContent = MessageEnvelope.Create(helloMessage);
var reply = await semanticKernelAgent.SendAsync(chatMessageContent);
// The type of reply is MessageEnvelope<ChatResponseMessage> where ChatResponseMessage is from Azure.AI.OpenAI
reply.Should().BeOfType<MessageEnvelope<ChatMessageContent>>();
// You can un-envelop the reply to get the ChatResponseMessage
ChatMessageContent response = reply.As<MessageEnvelope<ChatMessageContent>>().Content;
response.Role.Should().Be(AuthorRole.Assistant);
几个关键调用点说明:
- 消息封装:
SemanticKernelAgent原生支持的消息类型是IMessage<ChatMessageContent>(ChatMessageContent来自Microsoft.SemanticKernel.ChatCompletion)。使用MessageEnvelope.Create(helloMessage)将裸的ChatMessageContent封装为符合 AutoGen 消息协议的IMessage<ChatMessageContent>,随后通过SendAsync发送。 - 回复解封装:
SendAsync返回的reply是IMessage基类型,需要用reply.As<MessageEnvelope<ChatMessageContent>>().Content取出内部的ChatMessageContent,其中Role应为AuthorRole.Assistant。
2.3 非流式路径的源码行为
从 SemanticKernelAgent.cs 的 GenerateReplyAsync 实现可以看出完整处理链:
- 构建聊天历史:
BuildChatHistory会先把所有入站消息通过ProcessMessage转换为ChatMessageContent列表,且严格校验消息类型——任何不是IMessage<ChatMessageContent>的入站消息都会抛出ArgumentException("Invalid message type"); - 系统消息兜底:若聊天历史中不存在任何
System角色的消息,会在开头自动插入构造时传入的_systemMessage,这就是systemMessage参数的实际生效逻辑; - 服务选择:
GetChatCompletionService根据_modelServiceId是否为空决定取默认服务还是按 key 取指定服务; - 结果约束:若
GetChatMessageContentsAsync返回多于 1 条结果(即ResultsPerPrompt > 1),会抛出InvalidOperationException,即该智能体不支持多候选结果; - 默认执行参数:当未传入
settings时,BuildOption会构造一个OpenAIPromptExecutionSettings,默认值为Temperature = 0.7f、MaxTokens = 1024、StopSequences取自options.StopSequence,并且固定设置ToolCallBehavior.AutoInvokeKernelFunctions——这意味着若 Kernel 中注册了插件函数,默认会启用自动调用 Kernel 函数的工具调用行为。
3. 流式聊天:GenerateStreamingReplyAsync
SemanticKernelAgent 实现了 IStreamingAgent 接口(类声明见 SemanticKernelAgent.cs),因此可通过 GenerateStreamingReplyAsync 进行流式对话。文档中的 create_semantic_kernel_agent_streaming 代码块(同样位于 SemanticKernelCodeSnippet.cs)演示了标准用法:
var streamingReply = semanticKernelAgent.GenerateStreamingReplyAsync(new[] { chatMessageContent });
await foreach (var streamingMessage in streamingReply)
{
streamingMessage.Should().BeOfType<MessageEnvelope<StreamingChatMessageContent>>();
streamingMessage.As<MessageEnvelope<StreamingChatMessageContent>>().From.Should().Be("assistant");
}
要点:
- 返回类型为异步流:
GenerateStreamingReplyAsync返回IAsyncEnumerable<IMessage>,每个元素都是MessageEnvelope<StreamingChatMessageContent>,需要await foreach逐条消费; From字段:每个流式片段的From是创建智能体时指定的name(示例中为"assistant"),便于在多智能体场景中区分消息来源;- 单候选约束:从 SemanticKernelAgent.cs 的源码看,若某个流式片段的
ChoiceIndex > 0,会抛出InvalidOperationException("Only one choice is supported in streaming response"),即流式响应只支持单一候选。
4. 消息类型体系与更丰富的消息支持
SemanticKernelAgent 原生只接受 IMessage<ChatMessageContent>。如果需要在多智能体工作流中使用 AutoGen 内建的 TextMessage、ImageMessage、MultiModalMessage 等消息类型,可以使用包内提供的连接中间件 RegisterMessageConnector()(见 SemanticKernelAgentExtension.cs)。该扩展方法会把 SemanticKernelChatMessageContentConnector 注册为流式中间件,返回一个 MiddlewareStreamingAgent<SemanticKernelAgent>。
示例代码中演示了注册后的用法:
// Register the connector middleware to the kernel agent
var semanticKernelAgentWithConnector = semanticKernelAgent
.RegisterMessageConnector();
// now semanticKernelAgentWithConnector supports more message types
IMessage[] messages = [
MessageEnvelope.Create(new ChatMessageContent(AuthorRole.User, "Hello")),
new TextMessage(Role.Assistant, "Hello", from: "user"),
new MultiModalMessage(Role.Assistant,
[
new TextMessage(Role.Assistant, "Hello", from: "user"),
],
from: "user"),
];
foreach (var message in messages)
{
var reply = await semanticKernelAgentWithConnector.SendAsync(message);
// SemanticKernelChatMessageContentConnector will convert the reply message to TextMessage
reply.Should().BeOfType<TextMessage>();
}
从 SemanticKernelChatMessageContentConnector.cs 的源码看,该中间件的转换规则是:
- 入站:
TextMessage、ImageMessage、MultiModalMessage会被转换为ChatMessageContent后再传给底层智能体;其中消息来源(From)等于智能体自身名称时按 assistant 视角处理(System角色映射为System,其余映射为Assistant),来自其他智能体的则映射为User角色; - 出站:
ChatMessageContent中的文本项转换为TextMessage,图片项(URI 或二进制数据)转换为ImageMessage,多项内容合并为MultiModalMessage;流式场景下每个流式片段被转换为TextMessageUpdate; - 限制:源自智能体自身的
MultiModalMessage以及函数调用类消息不被支持,会抛出InvalidOperationException,这是使用该中间件时需要留意的边界。
5. 测试用例与运行前提
- 单元测试 SemanticKernelAgentTest.cs 覆盖了基本对话(
BasicConversationTestAsync)、按modelServiceId注册 keyed 服务后指定服务(BasicConversationTestWithKeyedServiceAsync)以及RegisterMessageConnector()的多种消息类型转换(SemanticKernelChatMessageContentConnectorTestAsync)等场景,可对照源码验证本文所述行为; - 所有示例均以 OpenAI 或 Azure OpenAI 为后端,运行前必须配置相应环境变量(
OPENAI_API_KEY,或 Azure 的三件套环境变量); - 相关文档中,SemanticKernelAgent-support-more-messages.md 进一步讲解如何扩展更多消息类型,SemanticKernelChatAgent-simple-chat.md 则介绍功能相近的
SemanticKernelChatCompletionAgent,二者可与本文配合阅读。
6. 小结
SemanticKernelAgent 是 AutoGen.NET 接入 Semantic Kernel 的桥梁:构造函数接收 Kernel、name、systemMessage、modelServiceId、settings 五个参数,默认执行参数为 Temperature 0.7、MaxTokens 1024 并启用 AutoInvokeKernelFunctions;非流式调用经 SendAsync 返回 MessageEnvelope<ChatMessageContent>,流式调用经 GenerateStreamingReplyAsync 返回 MessageEnvelope<StreamingChatMessageContent> 异步流;如需与 AutoGen 内建消息类型互通,再叠加 RegisterMessageConnector() 中间件即可。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00