.NET+AI | MEAI | 结构化输出(9)

📅 2026/7/26 9:39:19
.NET+AI | MEAI | 结构化输出(9)
目录一句话简介 核心要点 核心概念超精炼 实现方式最佳实践1) 强类型结构化输出最常用2) 嵌套对象与数组企业常见3) 流式结构化输出可边收边用4) 国内模型DeepSeek/Qwen兼容策略 生产最佳实践❓常见问题与解决 总结上一篇一句话简介将大模型的自由文本输出稳定地转为强类型 JSON 对象用于可靠的业务集成与自动化处理。 核心要点✅ 通过 JSON Schema 约束输出结构减少解析异常✅ 一行配置启用结构化输出ChatOptions.ResponseFormat✅ 自动从 C# 类型生成 SchemaAIJsonUtilities.CreateJsonSchema✅ 支持嵌套对象、枚举、数组与流式输出✅ 国内模型如 DeepSeek采用“提示词 纯 JSON”策略 核心概念超精炼ChatResponseFormat定义模型返回格式Text/Json/ForJsonSchemaJSON Schema描述 JSON 字段与类型的标准AIJsonUtilities从 C# 类型自动生成 JSON SchemaChatOptions.ResponseFormat向模型声明“必须按指定结构返回”flowchart LR A[提示词] -- B[ResponseFormatbr/JsonSchema] B -- C[LLM] C -- D[JSON] D -- E[反序列化为br/强类型对象] 实现方式最佳实践1) 强类型结构化输出最常用从 C# 类型生成 Schema并要求模型按该结构返回。using Microsoft.Extensions.AI; using System.Text.Json; using System.Text.Json.Serialization; publicclassPersonInfo { [JsonPropertyName(name)] publicstring? Name { get; set; } [JsonPropertyName(age)] publicint? Age { get; set; } [JsonPropertyName(occupation)] publicstring? Occupation { get; set; } [JsonPropertyName(location)] publicstring? Location { get; set; } } // 1) 生成 JSON Schema var schema AIJsonUtilities.CreateJsonSchema(typeof(PersonInfo)); // 2) 配置结构化输出 var options new ChatOptions { ResponseFormat ChatResponseFormatJson.ForJsonSchema( schema: schema, schemaName: PersonInfo, schemaDescription: 包含一个人的姓名、年龄、职业和地点) }; // 3) 请求并反序列化 var messages new[] { new ChatMessage(ChatRole.System, 从文本中提取个人信息严格按 JSON 返回。), new ChatMessage(ChatRole.User, 张伟35岁软件工程师在北京工作。) }; var client AIClientHelper.GetDefaultChatClient(); var result await client.CompleteAsync(messages, options); var person JsonSerializer.DeserializePersonInfo(result.Message.Text!, JsonSerializerOptions.Web);为什么推荐模型端“强约束”客户端“强类型”连线最短、容错更高。2) 嵌套对象与数组企业常见适合评论分析、工单解析、多联系人提取等复杂结构。public classSentimentAnalysis { [JsonPropertyName(sentiment)] publicstring? Sentiment { get; set; } // Positive/Neutral/Negative [JsonPropertyName(confidence)] publicdouble Confidence { get; set; } // 0.0-1.0 } publicclassProductReviewAnalysis { [JsonPropertyName(product_name)] publicstring? ProductName { get; set; } [JsonPropertyName(rating)] publicint Rating { get; set; } // 1-5 [JsonPropertyName(sentiment)] public SentimentAnalysis? Sentiment { get; set; } [JsonPropertyName(key_points)] public Liststring? KeyPoints { get; set; } [JsonPropertyName(recommendation)] publicbool Recommendation { get; set; } } var reviewSchema AIJsonUtilities.CreateJsonSchema(typeof(ProductReviewAnalysis)); var reviewOptions new ChatOptions { ResponseFormat ChatResponseFormatJson.ForJsonSchema(reviewSchema, ProductReviewAnalysis, 产品评论分析) }; var review await client.CompleteAsync(new[] { new ChatMessage(ChatRole.System, 分析评论并按 JSON 返回名称、评分、情感、要点、是否推荐。), new ChatMessage(ChatRole.User, iPhone 15 Pro 屏幕清晰、速度快、夜景强价格稍高但值得买。) }, reviewOptions); var analysis JsonSerializer.DeserializeProductReviewAnalysis(review.Message.Text!, JsonSerializerOptions.Web);要点嵌套结构、数组与约束在 Schema 中一次性声明输出更稳定。3) 流式结构化输出可边收边用当内容较长时可流式接收再整体反序列化。var sb new System.Text.StringBuilder(); await foreach (var chunk in client.CompleteStreamingAsync(messages, options)) { if (chunk.Text is not null) sb.Append(chunk.Text); } var streamed JsonSerializer.DeserializePersonInfo(sb.ToString(), JsonSerializerOptions.Web);4) 国内模型DeepSeek/Qwen兼容策略部分模型暂不支持 ForJsonSchema采用“纯 JSON 响应 严格提示”。var ds AIClientHelper.GetDeepSeekClient().GetChatClient(deepseek-chat).AsIChatClient(); var dsOptions new ChatOptions { ResponseFormat ChatResponseFormat.Json }; var system 严格按下列 JSON 返回不要输出任何其他文本 { \name\: \字符串\, \age\: 0, \occupation\: \字符串\, \location\: \字符串\ }; var resp await ds.GetResponseAsync(new[] { new ChatMessage(ChatRole.System, system), new ChatMessage(ChatRole.User, 刘洋42岁数据科学家深圳工作。) }, dsOptions); var person2 JsonSerializer.DeserializePersonInfo(resp.Text!, JsonSerializerOptions.Web);提示词关键明确“只返回 JSON、无需解释”提供完整 JSON 模板与类型约束。 生产最佳实践✅ 精简 Schema仅保留业务必须字段减少 Token 与偏差✅ 使用 JsonStringEnumConverter 显式声明枚举降低自由文本✅ 统一 JsonSerializerOptions.Web提升命名与容错一致性✅ 失败兜底捕获 JsonException 时尝试提取 JSON 片段或回退默认值✅ 批量数据分批处理降低上下文长度与失败率❓常见问题与解决问题可能原因解决方案反序列化失败返回不完全符合 Schema明确字段约束与示例增加系统提示兜底解析字段缺失/命名不一致命名风格不统一统一使用 JsonPropertyName JsonSerializerOptions.Web枚举值异常模型自由发挥提示中列出允许值并使用字符串枚举转换器国内模型格式漂移不支持 ForJsonSchema使用 ChatResponseFormat.Json 严格 JSON 模板 总结✅ 结构化输出把“不可控的文本”变成“可控的对象”便于对接业务系统✅ ForJsonSchema 强类型模型是最稳且通用的生产方案✅ 支持嵌套、数组、枚举与流式覆盖主流企业场景✅ 国内模型用“纯 JSON 严格模板”同样可达标https://github.com/mzhongl524/meai_dotnet_for_begenner下一篇引入地址