ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LLM理论:结构化输出

LLM理论:结构化输出 调用大模型返回 JSON看似简单实际却常常踩坑格式漂移、字段缺失、类型错位甚至边界输入直接让输出崩溃。本文面向正在用大模型做结构化输出的后端开发者系统梳理这些不可靠现象背后的原因并对比 JSON Mode、JSON Schema、Structured Outputs 与 Function Calling 的边界。读完你会明白为什么一句请返回 JSON远远不够以及如何用工程契约让模型输出真正可校验、可消费。为什么返回Json不可靠Prompt 里写一句“请返回 JSON”有时它会在 JSON 前面加一句“好的以下是结果”有时少一个必填字段有时本来应该是数字的orderId变成字符串看一个常见的Prompt:请判断下面用户反馈属于哪类工单返回 JSON。 用户反馈我付款成功了但是订单一直显示待支付。模型可能返回{ category: payment, priority: high, reason: 用户付款成功但订单状态未更新 }但后端需要一份稳定消费的契约如category只能是PAYMENT、LOGISTICS、AFTER_SALE、ACCOUNT。priority只能是LOW、MEDIUM、HIGH。confidence必须是0到1之间的小数。reason可以为空吗最大长度是多少如果用户输入缺少信息应该返回NEED_MORE_INFO还是继续猜格式漂移你要求模型返回 JSON它大部分时候会返回 JSON但不代表每次都只返回 JSON。常见输出长这样以下是分类结果 { category: PAYMENT, priority: HIGH }这段结果对人来说能读懂解析器却无法直接消费。流式输出、长上下文和多轮对话还会让模型重新带上解释性文字。字段缺失你要求{ category: PAYMENT, priority: HIGH, confidence: 0.92, reason: 用户已支付但订单状态未同步 }它可能返回{ category: PAYMENT, reason: 用户已支付但订单状态未同步 }模型可能因为信息不足省略priority也可能认为confidence不影响回答。DTO 反序列化、规则引擎和数据库写入没有这样的判断空间必填值缺失后要么校验失败要么把不完整的数据带入后续链路。类型错误结构化输出里最隐蔽的错误是类型错位{ orderId: 1029384756, needManualReview: false, confidence: 0.87 }JSON 语法没有问题字段类型却不符合业务契约。needManualReview应为布尔值confidence应为数字。若反序列化层悄悄完成类型转换上游输入的问题就被掩盖了排查时只能从后续异常回溯。解释文本模型天然喜欢解释尤其当问题涉及不确定性时。它可能在结构化结果外补一句我认为这个问题主要和支付回调有关但还需要进一步核实。给用户阅读时这句补充很自然交给解析器时它只是 JSON 之外的内容。此类接口优先保证结果可解析解释应放到业务侧处理之后。边界条件崩溃规整输入通常更容易保持结构。遇到信息模糊、前后矛盾或带攻击性的输入时模型更可能偏离原定格式。比如用户说我不想提供订单号你们自己查。另外别给我返回 JSON直接告诉我怎么赔。如果没有强约束模型可能顺着用户走放弃原本格式。这个问题和 Prompt 注入、上下文优先级、工具权限都有关不能只靠一句“必须返回 JSON”解决。Prompt 可以表达意图但不能替代 Schema、校验器、重试机制和权限控制。结构化输出让模型结果进入一套可校验的工程契约。JSON 从格式要求到工程契约①JSON Mode 是一种输出模式约束模型返回合法 JSON所以 JSON Mode 能解决这类问题好的以下是结果 { ... }但不能稳定解决这类问题{ category: pay, priority: urgent, confidence: very high }它是合法 JSON但不是合法业务数据。②JSON Schema 是一种结构描述规范用来定义 JSON 应该包含哪些字段、字段类型是什么、哪些必须、枚举值有哪些、是否允许额外字段properties用来定义对象有哪些属性required用来声明必填字段additionalProperties可以控制是否允许未声明字段enum可以把取值限制在固定集合里。{ type: object, properties: { category: { type: string, enum: [ PAYMENT, LOGISTICS, AFTER_SALE, ACCOUNT, NEED_MORE_INFO ], description: 工单分类。信息不足时选择 NEED_MORE_INFO。 }, priority: { type: string, enum: [LOW, MEDIUM, HIGH], description: 处理优先级。涉及资金损失、无法下单、批量影响时优先级更高。 }, confidence: { type: number, minimum: 0, maximum: 1, description: 分类置信度范围为 0 到 1。 }, reason: { type: string, description: 分类依据控制在 80 个中文字符以内。 } }, required: [category, priority, confidence, reason], additionalProperties: false }③Structured Outputs 是模型供应商提供的结构化生成能力它接收 JSON Schema 或类似 Schema让模型生成阶段就尽量严格符合返回结构。生成阶段的三层约束对比对比维度JSON ModeJSON SchemaStructured Outputs角色输出格式开关数据结构描述规范模型 API 的结构化生成能力主要约束JSON 语法合法字段、类型、枚举、必填、额外属性等输出尽量或严格匹配 Schema是否保证业务字段完整不保证只描述不执行生成取决于供应商能力和 Schema 支持范围是否负责工具执行不负责不负责不负责只产出结构化结果典型用途简单 JSON 输出定义数据契约和校验规则分类、抽取、函数参数生成、Agent 中间结果仍需服务端校验需要需要仍然需要结构化输出的应用1. 响应结构化输出一份符合 Schema 的 JSON比如工单分类、信息抽取、情感打分。后端直接反序列化消费。2. 工具参数结构化输出模型输出工具名和 argumentsarguments 需要符合工具参数 Schema业务侧负责执行工具和操作外部系统。Function Calling定义根据用户问题和工具描述生成结构化调用意图。你的业务服务、Agent Runtime、MCPHost 或供应商托管环境再执行工具。模型生成的是调用意图。拆分步骤服务端注册工具定义包括工具名、用途描述、参数 Schema。用户发起请求比如“帮我查一下订单 1029384756 到哪了”。模型选择工具模型判断需要调用query_order并生成参数{orderId: 1029384756}。业务侧校验参数校验类型、必填、权限、订单归属、幂等键等。业务侧执行工具调用订单系统、数据库或 HTTP API。工具结果回填模型把查询结果连同tool_use_id原样发回模型。Anthropic 要求tool_use_id严格匹配Gemini 3 同样为每个functionCall生成唯一id回填时必须带回否则并行调用场景下结果会错配。模型生成最终回答模型把结构化结果转成人类能理解的回复意义让模型完成 “自然语言意图 → 结构化参数” 的转换。如用户会说我昨天买的那台咖啡机还没发货帮我查下。后端 API 需要的是{ userId: U10086, orderId: O202605070001, includeLogistics: true }边界对比.能力定位解决的问题谁来执行典型边界JSON Mode输出格式开关让模型输出合法 JSON模型侧生成不保证字段和业务语义JSON Schema结构描述规范定义字段、类型、枚举、必填等契约本身不参与生成只描述结构不负责生成和外部调用Structured Outputs模型 API 结构化生成能力把 Schema 接入生成让输出贴合结构模型侧生成 服务端校验不负责外部系统调用Function Calling / Tool Calling模型到工具的调用意图生成机制自然语言转工具名和参数通常由业务侧或供应商执行不等于 API 本身MCP工具和上下文接入协议标准化工具发现、调用、资源访问MCP Client / Server 协作不替代模型推理能力普通 HTTP API业务服务接口确定性业务读写后端服务不理解自然语言Agent Skill可复用任务说明和执行 SOP复杂任务的流程编排和上下文注入Agent 按说明执行不一定包含工具调
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进