首页
/ AutoGen.NET:通过 SemanticKernelChatMessageContentConnector 让 SemanticKernelAgent 支持更多内置消息类型

AutoGen.NET:通过 SemanticKernelChatMessageContentConnector 让 SemanticKernelAgent 支持更多内置消息类型

2026-09-04 20:29:46作者:史锋燃Gardner

在 AutoGen.NET(.NET 版 AutoGen)中,SemanticKernelAgent 原生的消息通道只认一种类型:来自 Semantic Kernel 的 ChatMessageContent(即 IMessage<ChatMessageContent>)。当你的对话系统中同时存在 AutoGen 内置消息(如 TextMessageImageMessageMultiModalMessage)时,如何让它们与 Semantic Kernel Agent 无缝互通?本文基于官方文档 SemanticKernelAgent-support-more-messages 并结合仓库源码,完整讲解如何通过注册 SemanticKernelChatMessageContentConnector 中间件扩展 Agent 的消息兼容性:包括支持的消息类型清单、完整可运行代码、双向转换的底层实现细节,以及当前版本尚不支持的消息类型与验证方式。

一、SemanticKernelAgent 的默认消息限制

SemanticKernelAgent 是基于 Microsoft.SemanticKernelKernel 对象构建的流式 Agent(实现 IStreamingAgent 接口)。它接收 IEnumerable<IMessage> 作为输入,内部通过 BuildChatHistory 将消息列表拼装为 Semantic Kernel 的 ChatHistory

关键限制体现在它的消息处理逻辑中。从 SemanticKernelAgent.csProcessMessage 方法可以看到:

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 内置消息类型(TextMessageImageMessage 等)传入都会直接抛出 ArgumentException: Invalid message type。Agent 类注释(SemanticKernelAgent.cs)也明确说明:入站/回复消息均为 IMessage<ChatMessageContent>,流式回复为 IMessage<StreamingChatMessageContent>;"要支持更多 AutoGen 内置 IMessage,请注册 SemanticKernelChatMessageContentConnector"。

默认用法下,你需要用 MessageEnvelope.CreateChatMessageContent 包装成 IMessage<ChatMessageContent> 再发送,回复同样以 MessageEnvelope<ChatMessageContent> 形式返回。这是 AutoGen 与 Semantic Kernel 之间的"窄通道"。

二、SemanticKernelChatMessageContentConnector:双向消息转换器

SemanticKernelChatMessageContentConnector 是解决上述限制的核心组件,位于 Middleware/SemanticKernelChatMessageContentConnector.cs。它的职责是双向转换

  • 入站(Inbound):把调用方发来的 AutoGen 内置消息转换为 ChatMessageContent,再包上 MessageEnvelope<ChatMessageContent> 传给底层 Agent;
  • 出站(Outbound):把 Agent 返回的 ChatMessageContent(流式场景为 StreamingChatMessageContent)转换回 AutoGen 内置消息类型返回给调用方。

从类型声明看,它同时实现了 IMiddlewareIStreamingMiddleware 两个接口(SemanticKernelChatMessageContentConnector.cs),因此同步 SendAsync 与流式 GenerateStreamingReplyAsync 两条链路都能走转换逻辑——这是它与普通单一中间件的重要区别。

支持的消息类型清单

根据文档与中间件源码,当前阶段转换器的支持范围如下:

方向 支持的消息类型 说明
入站 TextMessage Role 映射为 System/User/Assistant
入站 ImageMessage 需带 URL 或可构造 Data URI 的二进制数据
入站 MultiModalMessage 内部元素仅支持 TextMessageImageMessage
出站(非流式) 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);
}

该扩展方法有两个重载(分别接收 SemanticKernelAgentMiddlewareStreamingAgent<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.SemanticKernelMicrosoft.SemanticKernel 等 NuGet 包(仓库 Directory.Packages.props 中当前锁定的 Semantic Kernel 稳定版为 1.45.0)。这段代码展示了三种入站消息混用:ChatMessageContent 信封消息(透传)、AutoGen TextMessage、AutoGen MultiModalMessage,且回复统一被转换器还原为 AutoGen 的 TextMessage

对比:未注册连接器时的基线用法

同一示例文件中的 CreateSemanticKernelAgentAsyncSemanticKernelCodeSnippet.cs)演示了不注册连接器时的用法:只能发送 IMessage<ChatMessageContent>,回复需用 reply.As<MessageEnvelope<ChatMessageContent>>().Content 解包;流式则通过 GenerateStreamingReplyAsync 拿到 MessageEnvelope<StreamingChatMessageContent>。两段示例放在一起,可以直观看到连接器带来的能力差异。

四、转换逻辑源码剖析

4.1 入站转换:区分"自己发的"与"别人发的"

中间件的 ProcessMessageSemanticKernelChatMessageContentConnector.cs)按 m.From == agent.Name 把消息分为两类分别处理,这决定了 AutoGen 的 Role 到 Semantic Kernel AuthorRole 的映射规则:

  • 来自 Agent 自身ProcessMessageForSelf,即消息在对话历史中是 Agent 自己之前的回复):Role.SystemAuthorRole.System,其余一律 → AuthorRole.Assistant
  • 来自其他参与者ProcessMessageForOthers,即用户或第三方 Agent):Role.SystemAuthorRole.System,其余一律 → AuthorRole.User
  • ImageMessage(他人):优先使用 message.Url 构造 ImageContent(new Uri(...));若无 URL 但持有二进制 Data,则调用 BuildDataUri() 生成 base64 Data URI 再包装为 ImageContent;两者皆无时抛出 InvalidOperationException: ImageMessage must have Url or DataUriImageMessage 的 Data URI 构造与 MIME 类型推断逻辑见 ImageMessage.cs(支持 png/jpg/jpeg/gif/bmp/webp/svg 等扩展名自动推断);
  • MultiModalMessage(他人):遍历内部 Content,逐项转换为 TextContentImageContent 后装入 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)完成:

  • TextContentTextMessage(Role.Assistant, ...)
  • ImageContent(带 UriReadOnlyMemory<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_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_DEPLOY_NAME 环境变量):

  • SemanticKernelChatMessageContentConnectorTestAsync测试代码):注册连接器后,对 ChatMessageContent 信封、TextMessageMultiModalMessage 三种入站消息逐一 SendAsync,断言回复均为 TextMessageFrom == "assistant";随后用同样的消息列表验证流式路径,断言每个增量块都是 TextMessageUpdate。这与本文第三节的示例完全对应;
  • SemanticKernelPluginTestAsync 还验证了注册连接器后 Kernel 插件(函数)仍可正常工作:向 Kernel 注入 GetWeatherAsync 插件函数并发送 "What is the weather in Seattle?",断言回复包含 "seattle" 与 "sunny"——说明连接器只转换消息通道,不影响 Kernel 自身通过 ToolCallBehavior.AutoInvokeKernelFunctions(见 SemanticKernelAgent.cs 的默认设置)完成的函数调用闭环;
  • SkChatCompletionAgentChatMessageContentConnectorTestAsync 则展示了同一连接器也可用于 SemanticKernelChatCompletionAgent(包装 Semantic Kernel ChatCompletionAgent另一种封装),通过 .RegisterMiddleware(new SemanticKernelChatMessageContentConnector()) 注册,行为一致。

需要说明:这些测试标注了 [ApiKeyFact(...)],属于依赖密钥的集成测试;仓库只读环境下你主要参考其断言逻辑即可。

六、限制与注意事项

  1. 函数调用消息暂不支持ToolCallMessageToolCallResultMessage 无法通过该连接器传递,携带函数调用信息的旧式 Message 也会抛出 "Function call is not supported" 异常。如果你需要在 Semantic Kernel Agent 上使用 AutoGen 侧的函数调用编排,当前应从源码结构看只能依赖 Kernel 原生插件机制(ToolCallBehavior.AutoInvokeKernelFunctions),而非 AutoGen 的 ToolCallMessage 通道;
  2. 多模态消息不能来自 Agent 自身:对话历史中 Agent 自己产生的 MultiModalMessage 会直接抛异常,回放多轮多模态历史时需注意这一点;
  3. 仅支持单一 choice:非流式场景 ResultsPerPrompt > 1 与流式场景 ChoiceIndex > 0 均会抛异常,这与 Semantic Kernel 后端配置相关;
  4. 注册返回新实例RegisterMessageConnector() 基于 AutoGen 的中间件机制返回新的 MiddlewareStreamingAgent<SemanticKernelAgent>,原 Agent 实例的消息行为不变,请在后续代码中使用返回的新实例。

七、小结

当 Semantic Kernel Agent 需要融入 AutoGen 的多 Agent 编排体系时,注册 SemanticKernelChatMessageContentConnector 是打通消息模型的唯一推荐路径:一行 RegisterMessageConnector() 即可让 TextMessageImageMessageMultiModalMessage 等 AutoGen 内置消息在入站时转为 ChatMessageContent、出站时还原为 AutoGen 消息(流式场景还原为 TextMessageUpdate),且同步/流式两条链路同时生效。实现细节可在 SemanticKernelChatMessageContentConnector.cs 中逐方法核对,行为验证可参考 SemanticKernelAgentTest.cs,完整可运行示例见 SemanticKernelCodeSnippet.cs

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
docsdocs
暂无描述
Markdown
889
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341