AutoGen.NET:通过 SemanticKernelChatMessageContentConnector 让 SemanticKernelAgent 支持更多内置消息类型
【免费下载链接】autogenA programming framework for agentic AI项目地址: https://gitcode.com/GitHub_Trending/au/autogen
在 AutoGen.NET(.NET 版 AutoGen)中,SemanticKernelAgent 原生的消息通道只认一种类型:来自 Semantic Kernel 的ChatMessageContent(即IMessage<ChatMessageContent>)。当你的对话系统中同时存在 AutoGen 内置消息(如TextMessage、ImageMessage、MultiModalMessage)时,如何让它们与 Semantic Kernel Agent 无缝互通?本文基于官方文档 SemanticKernelAgent-support-more-messages 并结合仓库源码,完整讲解如何通过注册SemanticKernelChatMessageContentConnector中间件扩展 Agent 的消息兼容性:包括支持的消息类型清单、完整可运行代码、双向转换的底层实现细节,以及当前版本尚不支持的消息类型与验证方式。
一、SemanticKernelAgent 的默认消息限制
SemanticKernelAgent是基于Microsoft.SemanticKernel的Kernel对象构建的流式 Agent(实现IStreamingAgent接口)。它接收IEnumerable<IMessage>作为输入,内部通过BuildChatHistory将消息列表拼装为 Semantic Kernel 的ChatHistory。
关键限制体现在它的消息处理逻辑中。从 SemanticKernelAgent.cs 的ProcessMessage方法可以看到:
private IEnumerable<ChatMessageContent> ProcessMessage(IEnumerable<IMessage> messages) { return messages.Select(m => m switch { IMessage<ChatMessageContent> cmc => cmc.Content, _ => throw new ArgumentException("Invalid message type") }); }也就是说,只有IMessage<ChatMessageContent>能通过类型匹配,任何 AutoGen 内置消息类型(TextMessage、ImageMessage等)传入都会直接抛出ArgumentException: Invalid message type。Agent 类注释(SemanticKernelAgent.cs)也明确说明:入站/回复消息均为IMessage<ChatMessageContent>,流式回复为IMessage<StreamingChatMessageContent>;"要支持更多 AutoGen 内置IMessage,请注册SemanticKernelChatMessageContentConnector"。
默认用法下,你需要用MessageEnvelope.Create把ChatMessageContent包装成IMessage<ChatMessageContent>再发送,回复同样以MessageEnvelope<ChatMessageContent>形式返回。这是 AutoGen 与 Semantic Kernel 之间的"窄通道"。
二、SemanticKernelChatMessageContentConnector:双向消息转换器
SemanticKernelChatMessageContentConnector是解决上述限制的核心组件,位于 Middleware/SemanticKernelChatMessageContentConnector.cs。它的职责是双向转换:
- 入站(Inbound):把调用方发来的 AutoGen 内置消息转换为
ChatMessageContent,再包上MessageEnvelope<ChatMessageContent>传给底层 Agent; - 出站(Outbound):把 Agent 返回的
ChatMessageContent(流式场景为StreamingChatMessageContent)转换回 AutoGen 内置消息类型返回给调用方。
从类型声明看,它同时实现了IMiddleware与IStreamingMiddleware两个接口(SemanticKernelChatMessageContentConnector.cs),因此同步SendAsync与流式GenerateStreamingReplyAsync两条链路都能走转换逻辑——这是它与普通单一中间件的重要区别。
支持的消息类型清单
根据文档与中间件源码,当前阶段转换器的支持范围如下:
| 方向 | 支持的消息类型 | 说明 |
|---|---|---|
| 入站 | TextMessage | 按Role映射为 System/User/Assistant |
| 入站 | ImageMessage | 需带 URL 或可构造 Data URI 的二进制数据 |
| 入站 | MultiModalMessage | 内部元素仅支持TextMessage与ImageMessage |
| 出站(非流式) | TextMessage/ImageMessage/MultiModalMessage | 单内容项返回单条消息,多内容项打包为MultiModalMessage |
| 出站(流式) | TextMessageUpdate | 流式增量文本更新 |
| 不支持 | ToolCallMessage/ToolCallResultMessage | 函数调用类消息,当前版本尚未支持 |
此外,IMessage<ChatMessageContent>本身会被直接透传(原样解包),因此注册连接器后,原有 Semantic Kernel 风格的用法依然兼容。
三、注册方式与完整可运行示例
注册操作通过扩展方法RegisterMessageConnector()完成,定义在 Extension/SemanticKernelAgentExtension.cs:
public static MiddlewareStreamingAgent<SemanticKernelAgent> RegisterMessageConnector( this SemanticKernelAgent agent, SemanticKernelChatMessageContentConnector? connector = null) { if (connector == null) { connector = new SemanticKernelChatMessageContentConnector(); } return agent.RegisterStreamingMiddleware(connector); }该扩展方法有两个重载(分别接收SemanticKernelAgent与MiddlewareStreamingAgent<SemanticKernelAgent>),连接器实例可以缺省——不传时自动new一个默认实例;返回值是注册了流式中间件的新 Agent 实例(AutoGen 的中间件机制采用"注册即返回新 Agent"的不可变风格)。
下面是官方示例工程 SemanticKernelCodeSnippet.cs 中的完整代码(对应文档引用的register_semantic_kernel_chat_message_content_connector代码块):
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(); // 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."); // 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>(); }运行前提:需要设置OPENAI_API_KEY环境变量;项目需引用AutoGen.SemanticKernel、Microsoft.SemanticKernel等 NuGet 包(仓库 Directory.Packages.props 中当前锁定的 Semantic Kernel 稳定版为 1.45.0)。这段代码展示了三种入站消息混用:ChatMessageContent信封消息(透传)、AutoGenTextMessage、AutoGenMultiModalMessage,且回复统一被转换器还原为 AutoGen 的TextMessage。
对比:未注册连接器时的基线用法
同一示例文件中的CreateSemanticKernelAgentAsync(SemanticKernelCodeSnippet.cs)演示了不注册连接器时的用法:只能发送IMessage<ChatMessageContent>,回复需用reply.As<MessageEnvelope<ChatMessageContent>>().Content解包;流式则通过GenerateStreamingReplyAsync拿到MessageEnvelope<StreamingChatMessageContent>。两段示例放在一起,可以直观看到连接器带来的能力差异。
四、转换逻辑源码剖析
4.1 入站转换:区分"自己发的"与"别人发的"
中间件的ProcessMessage(SemanticKernelChatMessageContentConnector.cs)按m.From == agent.Name把消息分为两类分别处理,这决定了 AutoGen 的Role到 Semantic KernelAuthorRole的映射规则:
- 来自 Agent 自身(
ProcessMessageForSelf,即消息在对话历史中是 Agent 自己之前的回复):Role.System→AuthorRole.System,其余一律 →AuthorRole.Assistant; - 来自其他参与者(
ProcessMessageForOthers,即用户或第三方 Agent):Role.System→AuthorRole.System,其余一律 →AuthorRole.User; ImageMessage(他人):优先使用message.Url构造ImageContent(new Uri(...));若无 URL 但持有二进制Data,则调用BuildDataUri()生成 base64 Data URI 再包装为ImageContent;两者皆无时抛出InvalidOperationException: ImageMessage must have Url or DataUri。ImageMessage的 Data URI 构造与 MIME 类型推断逻辑见 ImageMessage.cs(支持 png/jpg/jpeg/gif/bmp/webp/svg 等扩展名自动推断);MultiModalMessage(他人):遍历内部Content,逐项转换为TextContent或ImageContent后装入ChatMessageContentItemCollection,打包为单条AuthorRole.User消息;MultiModalMessage(自己):明确抛出InvalidOperationException("MultiModalMessage is not supported in the semantic kernel if it's from self.")——即 Agent 自己历史中的多模态消息暂不支持回放;- 旧版
Message类型(已标记[Obsolete])仍有兼容分支,但其中携带函数调用字段(FunctionName/FunctionArguments)的消息会抛出 "Function call is not supported" 异常。
不支持的类型一律抛InvalidOperationException("unsupported message type, only support TextMessage, ImageMessage, MultiModalMessage and Message."),错误信息直接给出了支持清单,排错成本很低。
4.2 出站转换:按内容项数量选择消息类型
回复方向由PostProcessMessage(IMessage<ChatMessageContent>)(SemanticKernelChatMessageContentConnector.cs)完成:
TextContent→TextMessage(Role.Assistant, ...);ImageContent(带Uri或ReadOnlyMemory<byte>二进制)→ImageMessage;- 转换后的内容项若只有 1 个,直接返回该单条消息;否则打包为
MultiModalMessage(Role.Assistant, items, ...)——这解释了为何多模态回复会自动升级类型; - 遇到其他
KernelContent子类型抛Unsupported content type。
流式回复走PostProcessMessage(IMessage<StreamingChatMessageContent>):校验ChoiceIndex必须为 0(多 choice 抛异常),然后把每个增量块包装为TextMessageUpdate(Role.Assistant, content, from)。TextMessageUpdate的定义见 TextMessage.cs,它与TextMessage的区别在于Content可为空且用于增量累积。
4.3 为什么这样设计
AutoGen 的消息模型以IMessage接口为统一抽象,各后端(OpenAI、Ollama、Gemini、Semantic Kernel 等)有自己的原生消息类型。连接器中间件本质上是"适配器":让上层编排代码(如 GroupChat)只操作 AutoGen 原生消息,而由中间件屏蔽后端的类型差异。这一"注册中间件即扩展能力"的模式在 AutoGen.NET 的中间件体系中是通用设计,SemanticKernelChatMessageContentConnector只是 Semantic Kernel 后端的具体实现。
五、测试用例中的行为验证
SemanticKernelAgentTest.cs 提供了对上述能力的端到端验证(基于 Azure OpenAI,需AZURE_OPENAI_API_KEY、AZURE_OPENAI_ENDPOINT、AZURE_OPENAI_DEPLOY_NAME环境变量):
SemanticKernelChatMessageContentConnectorTestAsync(测试代码):注册连接器后,对ChatMessageContent信封、TextMessage、MultiModalMessage三种入站消息逐一SendAsync,断言回复均为TextMessage且From == "assistant";随后用同样的消息列表验证流式路径,断言每个增量块都是TextMessageUpdate。这与本文第三节的示例完全对应;SemanticKernelPluginTestAsync还验证了注册连接器后 Kernel 插件(函数)仍可正常工作:向 Kernel 注入GetWeatherAsync插件函数并发送"What is the weather in Seattle?",断言回复包含 "seattle" 与 "sunny"——说明连接器只转换消息通道,不影响 Kernel 自身通过ToolCallBehavior.AutoInvokeKernelFunctions(见 SemanticKernelAgent.cs 的默认设置)完成的函数调用闭环;SkChatCompletionAgentChatMessageContentConnectorTestAsync则展示了同一连接器也可用于SemanticKernelChatCompletionAgent(包装 Semantic KernelChatCompletionAgent的 另一种封装),通过.RegisterMiddleware(new SemanticKernelChatMessageContentConnector())注册,行为一致。
需要说明:这些测试标注了[ApiKeyFact(...)],属于依赖密钥的集成测试;仓库只读环境下你主要参考其断言逻辑即可。
六、限制与注意事项
- 函数调用消息暂不支持:
ToolCallMessage与ToolCallResultMessage无法通过该连接器传递,携带函数调用信息的旧式Message也会抛出 "Function call is not supported" 异常。如果你需要在 Semantic Kernel Agent 上使用 AutoGen 侧的函数调用编排,当前应从源码结构看只能依赖 Kernel 原生插件机制(ToolCallBehavior.AutoInvokeKernelFunctions),而非 AutoGen 的ToolCallMessage通道; - 多模态消息不能来自 Agent 自身:对话历史中 Agent 自己产生的
MultiModalMessage会直接抛异常,回放多轮多模态历史时需注意这一点; - 仅支持单一 choice:非流式场景
ResultsPerPrompt > 1与流式场景ChoiceIndex > 0均会抛异常,这与 Semantic Kernel 后端配置相关; - 注册返回新实例:
RegisterMessageConnector()基于 AutoGen 的中间件机制返回新的MiddlewareStreamingAgent<SemanticKernelAgent>,原 Agent 实例的消息行为不变,请在后续代码中使用返回的新实例。
七、小结
当 Semantic Kernel Agent 需要融入 AutoGen 的多 Agent 编排体系时,注册SemanticKernelChatMessageContentConnector是打通消息模型的唯一推荐路径:一行RegisterMessageConnector()即可让TextMessage、ImageMessage、MultiModalMessage等 AutoGen 内置消息在入站时转为ChatMessageContent、出站时还原为 AutoGen 消息(流式场景还原为TextMessageUpdate),且同步/流式两条链路同时生效。实现细节可在 SemanticKernelChatMessageContentConnector.cs 中逐方法核对,行为验证可参考 SemanticKernelAgentTest.cs,完整可运行示例见 SemanticKernelCodeSnippet.cs。
【免费下载链接】autogenA programming framework for agentic AI项目地址: https://gitcode.com/GitHub_Trending/au/autogen
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考