news 2026/7/26 9:39:12

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET+AI | MEAI | 结构化输出(9)

目录

一句话简介

🎯 核心要点

📝 核心概念(超精炼)

💻 实现方式(最佳实践)

1) 强类型结构化输出(最常用)

2) 嵌套对象与数组(企业常见)

3) 流式结构化输出(可边收边用)

4) 国内模型(DeepSeek/Qwen)兼容策略

🏢 生产最佳实践

❓常见问题与解决

🎯 总结


上一篇

一句话简介

将大模型的自由文本输出,稳定地转为强类型 JSON 对象,用于可靠的业务集成与自动化处理。


🎯 核心要点

  • ✅ 通过 JSON Schema 约束输出结构,减少解析异常

  • ✅ 一行配置启用结构化输出:ChatOptions.ResponseFormat

  • ✅ 自动从 C# 类型生成 Schema:AIJsonUtilities.CreateJsonSchema

  • ✅ 支持嵌套对象、枚举、数组与流式输出

  • ✅ 国内模型(如 DeepSeek)采用“提示词 + 纯 JSON”策略


📝 核心概念(超精炼)

  • ChatResponseFormat:定义模型返回格式(Text/Json/ForJsonSchema)

  • JSON Schema:描述 JSON 字段与类型的标准

  • AIJsonUtilities:从 C# 类型自动生成 JSON Schema

  • ChatOptions.ResponseFormat:向模型声明“必须按指定结构返回”

flowchart LR A[提示词] --> B[ResponseFormat<br/>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.Deserialize<PersonInfo>(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 List<string>? 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.Deserialize<ProductReviewAnalysis>(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.Deserialize<PersonInfo>(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.Deserialize<PersonInfo>(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

下一篇

引入地址

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/26 9:37:03

Unity手游热更新实战:基于HybridCLR的C#热修复架构与性能优化

1. 项目概述&#xff1a;为什么是HybridCLR与CrazyCar&#xff1f; 在移动游戏开发&#xff0c;尤其是Unity手游的迭代长跑中&#xff0c;有一个场景是所有项目组都绕不开的噩梦&#xff1a;线上出了个紧急Bug&#xff0c;或者有个活动配置需要立刻调整&#xff0c;但玩家必须重…

作者头像 李华
网站建设 2026/7/26 9:32:37

h2oGPT:开源大模型本地化部署与隐私保护实践

1. h2oGPT&#xff1a;开源大模型领域的隐私守护者去年我在为一家金融机构做AI咨询时&#xff0c;遇到一个典型困境——他们既想用大语言模型处理客户财务数据&#xff0c;又担心数据泄露风险。当时市面上要么是闭源商业API&#xff08;数据必须上传第三方&#xff09;&#xf…

作者头像 李华
网站建设 2026/7/26 9:32:03

Dify自主学习系统架构与实现解析

1. 自主学习系统的基本原理Dify作为一个具备自主学习能力的系统&#xff0c;其核心在于构建了一个动态的知识获取与处理框架。这种框架不同于传统的规则驱动型系统&#xff0c;它能够通过持续的数据输入和反馈机制不断优化自身的行为模式。自主学习系统的三大支柱包括&#xff…

作者头像 李华
网站建设 2026/7/26 9:31:37

终极指南:如何快速掌握Wallpaper Engine资源提取神器RePKG

终极指南&#xff1a;如何快速掌握Wallpaper Engine资源提取神器RePKG 【免费下载链接】repkg Wallpaper engine PKG extractor/TEX to image converter 项目地址: https://gitcode.com/gh_mirrors/re/repkg 你是否曾经想要获取Wallpaper Engine中的精美壁纸资源&#x…

作者头像 李华
网站建设 2026/7/26 9:30:42

UE4载具性能调优实战:从参数解析到瓶颈定位的完整指南

1. 项目概述&#xff1a;为什么UE4载具性能调优是门“手艺活”&#xff1f; 做UE4项目&#xff0c;尤其是涉及开放世界或大规模场景的&#xff0c;载具系统往往是性能的“重灾区”。你可能遇到过这种情况&#xff1a;场景美轮美奂&#xff0c;角色丝滑流畅&#xff0c;但只要一…

作者头像 李华