AutoGen.NET 0.1.0 版本解读:Azure AI Inference 新包、双 Agent 分步会话与 Claude 提示缓存
本文基于 AutoGen 仓库的 .NET 侧发布说明 release_note/0.1.0.md,系统梳理 AutoGen.NET 0.1.0 版本的三项新特性、三项缺陷修复与一项文档更新。读完后,你将了解如何引入 AutoGen.AzureAIInference 包创建聊天 Agent、如何用返回 IAsyncEnumerable<IMessage> 的 SendAsync 逐步驱动两个 Agent 的对话,以及如何为 Claude 会话开启提示缓存(Prompt Caching)并理解其最小可缓存 token 门槛。
一、新增 NuGet 包:AutoGen.AzureAIInference
0.1.0 版本发布了 AutoGen.AzureAIInference 包,其核心组件是 ChatCompletionsClientAgent。该 Agent 是对 Azure.AI.Inference 库中 ChatCompletionsClient 的轻量封装,实现了 IStreamingAgent 接口,既支持一次性回复,也支持流式回复:
- 输入消息:
MessageEnvelope<ChatRequestMessage>类型(聊天请求消息); - 输出消息:非流式返回
MessageEnvelope<ChatCompletions>,流式返回MessageEnvelope<StreamingChatCompletionsUpdate>(见 ChatCompletionsClientAgent.cs 的类注释)。
构造函数提供了两条常用创建路径(ChatCompletionsClientAgent.cs):
// 路径一:显式参数,便于快速上手
public ChatCompletionsClientAgent(
ChatCompletionsClient chatCompletionsClient,
string name,
string modelName, // 例如 gpt-4o-mini
string systemMessage = "You are a helpful AI assistant",
float temperature = 0.7f,
int maxTokens = 1024,
int? seed = null, // 设置后可获得确定性输出
ChatCompletionsResponseFormat? responseFormat = null, // 设为 JSON 格式可启用 JSON 模式
IEnumerable<FunctionDefinition>? functions = null)
另一条路径直接传入 ChatCompletionsOptions 对象,适合需要精细控制请求参数的场景;注意源码在构造时会校验 options.Messages 不能非空(消息必须通过 GenerateReplyAsync 的参数传入,而不是预置在选项里):
if (options.Messages is { Count: > 0 })
{
throw new ArgumentException("Messages should not be provided in options");
}
回复与流式回复的实现分别在 GenerateReplyAsync(调用 chatCompletionsClient.CompleteAsync)和 GenerateStreamingReplyAsync(调用 CompleteStreamingAsync 并逐块 yield)中(ChatCompletionsClientAgent.cs)。由于 Azure.AI.Inference SDK 是 Azure AI 推理端点的统一客户端,这一包使得 AutoGen.NET 用户可以以与 OpenAI Agent 一致的心智模型接入 Azure AI Inference 平台上的各类模型。
二、新特性 1:两个 Agent 的聊天可以逐步执行
0.1.0 对双 Agent 会话 API 做了重要增强:AgentExtension.SendAsync 现在返回 IAsyncEnumerable<IMessage>,允许调用方像消费 GroupChatExtension.SendAsync 一样逐步驱动两个 Agent 的对话,而不是等整轮对话结束后一次性拿到结果。
2.1 核心实现:内部构建临时 RoundRobin 群聊
从源码(AgentExtension.cs)可以看到,该重载的工作机制非常清晰:
public static IAsyncEnumerable<IMessage> SendAsync(
this IAgent agent,
IAgent receiver,
IEnumerable<IMessage> chatHistory,
int maxRound = 10,
CancellationToken ct = default)
{
if (receiver is GroupChatManager manager)
{
var gc = manager.GroupChat;
return gc.SendAsync(chatHistory, maxRound, ct);
}
var groupChat = new RoundRobinGroupChat(
agents:
[
agent,
receiver,
]);
return groupChat.SendAsync(chatHistory, maxRound, cancellationToken: ct);
}
要点:
- 若
receiver本身是GroupChatManager(群聊管理器),则直接把会话交给其内部的IGroupChat执行; - 否则,用发送方和接收方临时构造一个
RoundRobinGroupChat(轮询群聊,即两个 Agent 交替发言),再复用GroupChatExtension.SendAsync的异步枚举管道; maxRound默认为 10,控制对话最多执行的轮数,与群聊 API 保持一致。
还有一个字符串便捷重载(AgentExtension.cs):直接传 string message,内部会把它包装成 From = agent.Name 的 TextMessage 追加到历史末尾后走同样的管道。
2.2 用法示例
// agentA 与 agentB 之间的分步对话
var chatHistory = new List<IMessage> { new TextMessage(Role.User, "start chat") };
await foreach (var msg in agentA.SendAsync(agentB, chatHistory, maxRound: 5))
{
// 每产生一条新消息就执行一次这里,可逐条打印、落库或做终止判断
Console.WriteLine($"{msg.From}: {msg.GetContent()}");
}
如果需要"发送并等待全部结束"的快捷行为,仓库同时提供了 InitiateChatAsync 快捷 API(AgentExtension.cs),它内部消费上述异步枚举并返回完整聊天历史。原来的 SendMessageToGroupAsync 两个重载已被标记 [Obsolete],官方提示统一改用 GroupChatExtension.SendAsync(AgentExtension.cs)。
三、新特性 2:AutoGen.DotnetInteractive 支持 Python 代码执行
0.1.0 中 AutoGen.DotnetInteractive 通过 dotnet-interactive 的 Jupyter 内核连接能力,扩展了对 Python 代码执行的支持——此前该包只能运行 C# 代码。
从项目文件(AutoGen.DotnetInteractive.csproj)可以看到实现方式:
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.DotNet.Interactive.Jupyter" />
<PackageReference Include="Microsoft.DotNet.Interactive.PackageManagement" />
</ItemGroup>
从源码结构看,Jupyter 相关依赖被条件性地限定在 net8.0 目标框架下引入(另外的 dotnet-tools.json 与 RestoreInteractive.config 作为嵌入资源随包分发,用于初始化交互式内核环境),这意味着 Jupyter 内核连接能力在 net8.0 构建中可用,而低版本目标框架则仅保留核心的 .NET 交互式能力。这一点对需要在多目标框架下使用 AutoGen.NET 的开发者是一个明确的适用前提。
四、新特性 3:Claude 支持提示缓存(Prompt Caching)
0.1.0 为 Claude 客户端加入了提示缓存支持。缓存命中时,重复的上下文部分无需重新完整计费,对长系统提示、长文档问答等场景的成本影响显著。仓库中的实现分布在三层:
4.1 客户端层:请求头声明缓存特性
AnthropicClient 在每次请求时都会附加启用提示缓存的 beta 请求头(AnthropicClient.cs):
httpRequestMessage.Headers.Add("anthropic-beta", "prompt-caching-2024-07-31");
同时在 JSON 序列化选项中注册了 JsonPropertyNameEnumConverter<CacheControlType> 转换器,保证 cache_control 字段按 Anthropic API 约定序列化(AnthropicClient.cs)。
4.2 DTO 层:CacheControl 类型与便捷工厂方法
- Content.cs 中
TextContent带有CacheControl属性(JSON 名cache_control),并提供工厂方法TextContent.CreateTextWithCacheControl(text),创建类型标记为CacheControlType.Ephemeral(临时缓存)的文本块; - ChatCompletionRequest.cs 中
SystemMessage同样支持CacheControl,并提供SystemMessage.CreateSystemMessageWithCacheControl(systemMessage)工厂方法; - 工具定义 Tool.cs 也支持缓存标记,说明工具 schema 这类"长且稳定"的前缀内容同样可以纳入缓存。
4.3 实战示例:带缓存的群聊翻译场景
仓库自带完整示例 Anthropic_Agent_With_Prompt_Caching.cs,值得注意的两点:
- 最小可缓存 token 数有硬性门槛。示例注释(L13-L16)明确说明:对 Claude 3.5 Sonnet 与 Claude 3 Opus,上下文需超过 1024 token 才可缓存;Claude 3.0 Haiku 需 2048 token。短于门槛的提示即使打了
cache_control标记也不会被缓存。因此示例使用了一段很长的故事文本作为可缓存上下文。 - 缓存块的构造与群聊结合:
var messageEnvelope = MessageEnvelope.Create(
new ChatMessage("user", [TextContent.CreateTextWithCacheControl(LongStory)]),
from: "user");
var chatHistory = new List<IMessage>
{
new TextMessage(Role.User, "translate this text for me", from: userProxyAgent.Name),
messageEnvelope,
};
var groupChat = new RoundRobinGroupChat(
agents: [userProxyAgent, frenchTranslatorAgent, germanTranslatorAgent]);
await groupChat.SendAsync(chatHistory).ToArrayAsync();
在这个双翻译 Agent 的轮询群聊中,长故事作为缓存块只会被完整计费一次,后续 Agent 轮次命中缓存。
五、缺陷修复(Bug Fixes)
5.1 #3306:IOrchestrator 返回 null 时群聊无法终止
问题:此前 GroupChatExtension.SendAsync 在 IOrchestrator 返回 null 作为下一位发言者时不会结束循环,会一直空转到 max_round 耗尽。
修复:当前实现(GroupChatExtension.cs)在每一轮调用 groupChat.CallAsync 后,先比较返回的消息集合与输入历史长度:
while (maxRound-- > 0)
{
var messages = await groupChat.CallAsync(chatHistory, maxRound: 1, cancellationToken);
// if no new messages, break the loop
if (messages.Count() == chatHistory.Count())
{
yield break;
}
...
}
即"本轮没有产生任何新消息"时立即 yield break 终止——这覆盖了编排器无法选出下一位发言者的情形。此外,若最后一条消息包含 [GROUPCHAT_TERMINATE] 标记,同样会提前终止(GroupChatExtension.cs)。
5.2 #3268:初始化消息被重复追加
问题:群聊的 initialized messages 在 SendAsync 的每次迭代中被重复加入,导致历史膨胀、上下文错乱。
修复:由于 CallAsync 返回的 messages 已包含完整聊天历史(含初始化消息),循环中只需把最后一轮新增的消息追加到历史即可。源码中保留了明确的修复注释(GroupChatExtension.cs):
// messages will contain the complete chat history, include initalize messages
// but we only need to add the last message to the chat history
// fix #3268
chatHistory = chatHistory.Append(lastMessage);
5.3 #3273:移除 AutoGen.DotnetInteractive 对 Azure.AI.OpenAI 的依赖
AutoGen.DotnetInteractive 原有一个与自身功能无关的 Azure.AI.OpenAI 依赖。当前项目文件(AutoGen.DotnetInteractive.csproj)中已不存在该引用,包仅保留 Microsoft.DotNet.Interactive 及前述条件引入的 Jupyter/包管理组件,依赖面更简洁,也降低了版本冲突的概率。
六、文档更新:Python AutoGen 与 AutoGen.NET 功能对比页
0.1.0 还新增了一篇跨语言功能对比文档(function-comparison-page-between-python-AutoGen-and-autogen.net.md),从三个维度对比两个实现:
- Agent 模式:单 Agent 聊天、双 Agent 聊天、群聊(.NET 侧用 workflow 实现 FSM 群聊、用中间件模式实现嵌套聊天)、工具调用在两侧均支持;代码解释器方面,Python 侧可在 local/docker/notebook 执行器中运行 Python,.NET 侧运行 C# 代码(结合 0.1.0 的 Jupyter 内核连接能力后,.NET 侧也具备了执行 Python 的路径);Sequential chat 目前 Python 侧支持、.NET 侧需在代码中手动创建任务。
- LLM 平台支持:OpenAI(含第三方端点)、Mistral、Ollama、Claude、Gemini(含 Vertex)在两侧均支持;文档还注明 AutoGen.NET 可通过
AutoGen.SemanticKernel桥接 Semantic Kernel 支持的全部平台。 - 社区贡献 Agent:RAG Agent、Web surfer 等目前仅 Python 侧提供。
这张对比表对从 Python AutoGen 迁移到 AutoGen.NET 的开发者有直接的选型参考价值。
七、升级要点小结
结合以上源码与发布说明,使用 0.1.0 时值得记住的要点:
| 变更项 | 影响面 | 验证位置 |
|---|---|---|
新增 AutoGen.AzureAIInference 包 |
新增包,接入 Azure AI Inference 平台 | ChatCompletionsClientAgent.cs |
双 Agent SendAsync 返回 IAsyncEnumerable<IMessage> |
可逐条消费对话消息;maxRound 默认 10 |
AgentExtension.cs |
| DotnetInteractive 支持 Python(Jupyter 内核) | 依赖仅在 net8.0 目标下引入 | AutoGen.DotnetInteractive.csproj |
| Claude 提示缓存 | 需满足最小可缓存 token 门槛;通过 cache_control 标记 |
AnthropicClient.cs、示例 |
| 群聊空转/重复消息修复 | 群聊终止与历史管理行为修正 | GroupChatExtension.cs |
以上条目均以当前仓库代码为事实依据;涉及具体 API 行为时,建议以对应源码文件的最新内容为准。
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 StartedRust0624
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