AutoGen.Net v0.2.0 版本解析:OpenAI 结构化输出、Azure.AI.OpenAI v2 迁移与 GPTAgent 弃用指南
AutoGen.Net v0.2.0 是 AutoGen(一个用于构建 Agentic AI 的编程框架).NET 端的重要版本:它引入了基于 JSON Schema 的 OpenAI 结构化输出(Structural Output)、将 AutoGen.OpenAI 包底层切换为 OpenAI .NET SDK v2,并正式弃用 GPTAgent。读完本文,你将掌握这三个变化的具体用法与迁移方式,并能对照仓库中的源码与示例验证每一项变更的实际落地情况。
版本总览
v0.2.0 的官方发布说明位于 0.2.0.md,内容可分为四类:
| 类别 | 变更 | 对应 PR/Issue |
|---|---|---|
| 新特性 | OpenAI 集成支持结构化输出格式(Structural Format Output) | #3482 |
| 新特性 | GenerateReplyOption 新增属性,允许在生成回复时覆盖结构化输出 schema |
#3436 |
| Bug 修复 | 修复消息历史中包含多个不同 name 字段的 tool call 时报错(Error Code 500)的问题 |
#3437 |
| 改进 | AutoGen.OpenAI 包改用 OpenAI v2.0 SDK;原 AutoGen.OpenAI 保留为 AutoGen.OpenAI.V1 供继续使用 Azure.AI.OpenAI v1 的用户 |
#3193 |
| 改进 | GPTAgent 被弃用,改用 OpenAIChatAgent + OpenAIMessageConnector |
#3404 |
| 文档 | 新增使用 ollama 与 OpenAIChatAgent 进行 tool call 的详细文档 |
#3248 |
其中对开发者影响最大的是三项:结构化输出、OpenAI SDK v1 → v2 的包迁移、GPTAgent 弃用。下面逐一展开。
新特性一:OpenAI 结构化输出(Structural Output)
GenerateReplyOptions.OutputSchema 属性
v0.2.0 在核心消息生成选项 GenerateReplyOptions 中新增了 OutputSchema 属性(类型为 JsonSchema?),可以在每次调用 GenerateReplyAsync 时按调用粒度覆盖结构化输出 schema,而不必修改 Agent 本身的构造配置。该属性的定义见 IAgent.cs 中的 GenerateReplyOptions 类:
public JsonSchema? OutputSchema { get; set; }
完整的结构化输出示例
仓库中 Structural_Output.cs 提供了可直接运行的完整示例,演示了如何用 C# 类型自动生成 JSON Schema、将其作为输出约束传给 OpenAI,并把模型回复反序列化为强类型对象。
第一步:定义输出类型并生成 JSON Schema。 使用 JsonSchemaBuilder(来自 Json.Schema 库)从 Person 类构建 schema,类的特性([JsonPropertyName]、[Description]、[Required] 等)会被带入 schema 中,成为对模型的字段级约束:
var schemaBuilder = new JsonSchemaBuilder().FromType<Person>();
var schema = schemaBuilder.Build();
[Title("Person")]
public class Person
{
[JsonPropertyName("name")]
[Description("Name of the person")]
[Required]
public string Name { get; set; }
[JsonPropertyName("age")]
[Description("Age of the person")]
[Required]
public int Age { get; set; }
[JsonPropertyName("city")]
[Description("City of the person")]
public string? City { get; set; }
[JsonPropertyName("address")]
[Description("Address of the person")]
public string? Address { get; set; }
[JsonPropertyName("hobbies")]
[Description("Hobbies of the person")]
public List<string>? Hobbies { get; set; }
}
注意类上的 [Title("Person")] 特性——后文会看到,它是 v0.2.0 中 OutputSchema 生效的硬性前提。
第二步:创建 Agent 并发起结构化回复。 Agent 通过 OpenAI v2 的 ChatClient 创建(详见后文迁移章节),并通过 GenerateReplyOptions.OutputSchema 传入 schema:
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
?? throw new Exception("Please set OPENAI_API_KEY environment variable.");
var openAIClient = new OpenAIClient(apiKey);
var openAIClientAgent = new OpenAIChatAgent(
chatClient: openAIClient.GetChatClient("gpt-4o-mini"),
name: "assistant",
systemMessage: "You are a helpful assistant")
.RegisterMessageConnector()
.RegisterPrintMessage();
var prompt = new TextMessage(Role.User, """
My name is John, I am 25 years old, and I live in Seattle.
I like to play soccer and read books.
""");
var reply = await openAIClientAgent.GenerateReplyAsync(
messages: [prompt],
options: new GenerateReplyOptions
{
OutputSchema = schema,
});
// 回复内容即为符合 schema 的 JSON,可直接反序列化
var person = JsonSerializer.Deserialize<Person>(reply.GetContent());
示例末尾还带有断言(person.Name.Should().Be("John") 等),验证模型返回的 JSON 完全落在 schema 约束之内。运行该示例需设置 OPENAI_API_KEY 环境变量。
源码层面:OutputSchema 是如何生效的
从源码结构看,OutputSchema 的消费逻辑位于新版 OpenAIChatAgent.cs 的 CreateChatCompletionsOptions 私有方法中:
if (options?.OutputSchema is not null)
{
option.ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
jsonSchemaFormatName: options.OutputSchema.GetTitle() ?? throw new ArgumentException("Output schema must have a title"),
jsonSchema: BinaryData.FromObjectAsJson(options.OutputSchema),
jsonSchemaFormatDescription: options.OutputSchema.GetDescription());
}
这里可以读出两个关键实现细节:
- schema 的
Title是必需的。OpenAI v2 SDK 的CreateJsonSchemaFormat要求传入jsonSchemaFormatName,源码直接用options.OutputSchema.GetTitle()填充,取不到会抛出ArgumentException("Output schema must have a title")。这就是示例中Person类必须标注[Title("Person")]的原因。 - 它是"覆盖"语义。
OutputSchema在每次请求时写入ChatCompletionOptions.ResponseFormat,会覆盖构造 Agent 时通过responseFormat参数设置的格式(例如 JSON mode)。这与发布说明中"允许在生成回复时覆盖结构化输出 schema"的描述一致。
如果你熟悉 JSON mode,可以进一步参考仓库中的 OpenAIChatAgent-use-json-mode.md 了解 JSON mode 与结构化输出的关系;结构化输出(JSON Schema)是 JSON mode 的超集,能约束字段级结构。
新特性二与改进:AutoGen.OpenAI 切换到 OpenAI v2.0,原包保留为 AutoGen.OpenAI.V1
包结构变化
v0.2.0 之后,仓库中并存的两个 OpenAI 集成包分别是:
- AutoGen.OpenAI:基于 OpenAI .NET SDK v2(
OpenAIClient/ChatClient/ChatMessage等新类型),是新的默认包; - AutoGen.OpenAI.V1:保留基于 Azure.AI.OpenAI v1(
OpenAIClient/ChatCompletionsOptions/ChatRequestMessage等旧类型)的实现,供尚未迁移的项目继续使用。
这一设计意味着升级是渐进的:新项目直接使用新 AutoGen.OpenAI,存量项目可先引用 AutoGen.OpenAI.V1 保持编译通过,再逐步迁移。
创建 OpenAIChatAgent 的前后对比
发布说明给出的迁移方式如下。
迁移前(v1 风格,OpenAIClient + 模型名字符串):
var openAIClient = new OpenAIClient(apiKey);
var openAIClientAgent = new OpenAIChatAgent(
openAIClient: openAIClient,
model: "gpt-4o-mini",
// Other parameters...
);
迁移后(v2 风格,直接传 ChatClient):
var openAIClient = new OpenAIClient(apiKey);
var openAIClientAgent = new OpenAIChatAgent(
chatClient: openAIClient.GetChatClient("gpt-4o-mini"),
// Other parameters...
);
核心差异是:模型名从 Agent 构造参数下沉到了 SDK 的 ChatClient 层(openAIClient.GetChatClient("gpt-4o-mini")),Agent 只持有 ChatClient 实例。对照两个包中的 OpenAIChatAgent 构造函数可以印证这一点:
- 新版 OpenAIChatAgent.cs(
AutoGen.OpenAI):构造参数为ChatClient chatClient,并额外支持seed、responseFormat(ChatResponseFormat,设为 JSON 格式即启用 JSON mode)等可选参数; - 旧版 OpenAIChatAgent.cs(
AutoGen.OpenAI.V1):构造参数为OpenAIClient openAIClient+string modelName,选项类型为 v1 的ChatCompletionsOptions。
此外,新版 Agent 内部的消息转换、系统消息注入等逻辑(如 CreateChatMessages 在消息列表缺少 system 消息时自动补上构造时指定的 systemMessage)与 v1 包保持一致,迁移时对话行为不会改变。
改进:GPTAgent 弃用与迁移
弃用声明
发布说明宣布 GPTAgent 被弃用,推荐改用 OpenAIChatAgent + OpenAIMessageConnector(即 RegisterMessageConnector() 扩展)。源码中这一弃用是显式标注的,GPTAgent.cs 第 30 行带有:
[Obsolete("Use OpenAIChatAgent instead")]
public class GPTAgent : IStreamingAgent
使用它的工程在编译时会收到弃用警告。
迁移方式
Before:
var agent = new GPTAgent(...);
After:
var agent = new OpenAIChatAgent(...)
.RegisterMessageConnector();
RegisterMessageConnector() 的作用是把 OpenAIChatAgent 收发的 SDK 消息类型(如 ChatCompletion)转换为 AutoGen 核心消息类型(TextMessage、ToolCallMessage 等),使其能与其他 Agent 在 AutoGen.Core 的消息体系中互通。
源码佐证:GPTAgent 本就是一层薄包装
从 GPTAgent.cs 的构造逻辑看,GPTAgent 内部正是按迁移后的形态实现的:
_innerAgent = new OpenAIChatAgent(openAIClient, name, modelName, systemMessage, temperature, maxTokens, seed, responseFormat, functions)
.RegisterMessageConnector();
if (functionMap is not null)
{
var functionMapMiddleware = new FunctionCallMiddleware(functionMap: functionMap);
_innerAgent = _innerAgent.RegisterStreamingMiddleware(functionMapMiddleware);
}
也就是说,GPTAgent 除了从 AzureOpenAIConfig / OpenAIConfig 中解析出 OpenAIClient 和模型名(见 GPTAgent.cs 的 config 分支)以及可选地挂载 FunctionCallMiddleware 外,行为完全等价于 OpenAIChatAgent(...).RegisterMessageConnector()。因此迁移是"去掉配置对象解析这一层间接",语义不变;functionMap 参数对应的行为则需要在迁移后通过中间件自行挂载。
Bug 修复:多工具调用导致的 500 错误
v0.2.0 修复了消息历史中包含多个不同 name 字段的 tool call 时抛错的问题(#3437)。该问题属于消息连接器在将历史 ToolCallMessage 还原为 OpenAI 请求消息时的兼容性缺陷。如果你此前在多轮函数调用场景(如 ReAct 循环、工具编排)中遇到过请求失败,升级到 v0.2.0 即可消除;仓库中的 OpenAIChatAgent-use-function-call.md 与 Function-call-with-ollama-and-litellm.md 分别覆盖了 OpenAI 与 ollama/LiteLLM 场景下的 tool call 用法,与本次新增的文档条目(#3248)对应。
迁移检查清单
结合发布说明与源码,从 v0.1.x 升级到 v0.2.0 建议按以下顺序操作:
- 确认目标包:新代码引用
AutoGen.OpenAI(v2 SDK);若必须暂留 v1,改为引用AutoGen.OpenAI.V1,避免包名与 SDK 版本错配。 - 替换
GPTAgent:全局搜索new GPTAgent(,按上文 Before/After 模式替换为OpenAIChatAgent(...).RegisterMessageConnector();若原先传了functionMap,迁移后以RegisterStreamingMiddleware(new FunctionCallMiddleware(functionMap: ...))等价挂载。 - 调整
OpenAIChatAgent构造:把"客户端 + 模型名"改为"客户端.GetChatClient(模型名)",并核对responseFormat类型变化(v1 的ChatCompletionsResponseFormat→ v2 的ChatResponseFormat)。 - (可选)启用结构化输出:为需要强类型返回的 Agent 添加
JsonSchema约束,调用时通过GenerateReplyOptions.OutputSchema传入;务必确保 schema 带 Title(如[Title("Person")]),否则会抛出ArgumentException。 - 验证工具调用回归:在多 tool call 的对话历史场景中跑一遍回归用例,确认 #3437 修复生效。
小结
v0.2.0 的主线是"向 OpenAI .NET SDK v2 全面对齐":结构化输出让 GenerateReplyOptions.OutputSchema 成为每次调用级、schema 驱动的回复约束;包拆分(AutoGen.OpenAI / AutoGen.OpenAI.V1)为 v1 用户保留了平滑过渡通道;GPTAgent 的弃用则让消息连接器(RegisterMessageConnector)成为标准用法。三者的代码级证据均可在 AutoGen.OpenAI 源码、AutoGen.OpenAI.V1 源码 与 结构化输出示例 中直接对照验证。
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 StartedRust0627
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