转写说明
本文基于已校验的公开原文进行结构化转写与事实梳理,非原文转载。 转写保留可核验的技术事实,并将工程建议与来源观点明确分开。
- 原作者: 默_笙
- 原始来源: https://juejin.cn/post/7684195084155076617
- 原文发布时间: Sat, 12 Sep 2026 08:59:15 GMT
核心结论
LLM 默认输出自由文本,而非结构化 JSON。直接调用 JSON.parse() 会因 markdown 包裹或格式偏差而失败。将 LLM 驯服为结构化输出是一个渐进过程:从手搓正则剥除外衣,到 LangChain OutputParser 体系,再到 Zod Schema 类型约束,最后到 Tool Call 原生能力,约束强度逐级提升。核心目的是为下游业务提供字段名固定、类型精确、结构可靠的数据。
能力机制
第一级手搓正则通过 /```json\s*([\s\S]*?)\s*```/ 捕获 markdown 代码块内的 JSON 字符串,需手动处理 ```json ``` 包裹、try/catch 异常及多种格式变体。
第二级 JsonOutputParser 是 LangChain 基础解析器,parser.getFormatInstructions() 在 prompt 中追加格式约束文本,parser.parse() 内部完成 markdown 剥离与 JSON.parse 转换,但仅保证返回合法 JSON,不约束字段名和类型。
第三级 StructuredOutputParser.fromNamesAndDescriptions 通过字段名加描述的方式固定输出结构,强制 LLM 使用指定字段名,避免用同义中文替代。类型仍依赖描述约束。
第四级 StructuredOutputParser.fromZodSchema 以 Zod Schema 定义精确类型系统,支持 z.string()、z.number()、z.array()、z.object() 及嵌套结构,配合 .describe() 向 LLM 传递字段语义。parse() 内部执行 Zod 运行时验证,类型不符会抛错。
第五级 Tool Call 利用 LLM 原生工具调用能力,model.bindTools([{name, description, schema}]) 绑定工具后,LLM 直接在 response.tool_calls[0].args 中返回结构化参数,无需 getFormatInstructions() 和 parse() 步骤,可靠性高于 prompt 约束。
快速开始
| |
环境变量名称按需配置,不在示例中展示。
适用边界
JsonOutputParser 适用于仅需合法 JSON、不关心字段名的场景。fromNamesAndDescriptions 适用于需要固定字段名但类型要求宽松的场景。fromZodSchema 适用于类型严格、结构复杂、需运行时验证的生产环境。Tool Call 适用于模型已支持 tool calling 能力的场景,可靠性最高但依赖模型特性。
手搓正则适合临时调试或无 LangChain 依赖的简单场景,不建议在生产代码中维护。OutputParser 体系的优势在于通用性,任何返回文本的 LLM 均可使用;Tool Call 的优势在于可靠性和简洁性,但受限于模型能力。
核验清单
开发阶段需确认:prompt 中的格式约束指令已通过 getFormatInstructions() 自动添加;parser.parse() 能够正确处理 markdown 包裹的响应;使用 Zod Schema 时验证 birth_year 等数值字段返回的是数字而非字符串;数组字段如 awards 返回的是对象数组而非字符串拼接。
生产阶段需确认:模型是否支持 tool calling,是则优先采用 bindTools 方案;异常处理已覆盖 LLM 返回非 JSON 格式的兜底逻辑;复杂嵌套结构的字段名和类型与下游消费端定义一致;测试用例覆盖字段名错误、类型错误、结构缺失等失败场景。
来源与核验
- 原始文章
- 页面事实以原始来源及其引用的官方资料为准;版本、星标和模型能力会随时间变化。
- AI Stack 不公开抓取到的全文快照,只发布独立转写与来源入口。