我梳理了本地模型导致 JSON 输出失效的每一种情况并构建了修复库,以下是我在 288 次模型调用中的发现
摘要
一位开发者梳理了 288 次本地模型运行中的 JSON 输出失败案例,发现了如 Markdown 代码块包裹和尾随逗号等常见问题,并开发了 outputguard,这是一个采用 15 种策略修复无效 JSON 的 Python 库。
过去几个月,我一直在 OpenRouter 上通过一堆模型运行结构化输出提示词 —— Llama 3、Mistral、Command R、DeepSeek、Qwen 以及 OpenRouter 上的其他所有模型 —— 同时也包括那些常见的闭源模型。总共 288 次调用。
我想知道到底什么会出问题,发生的频率如何,以及开放模型是否与仅限 API 的模型有不同的失败模式。简短的回答是:并非如此。失败模式几乎完全相同。
*频率* 有所不同 —— 有些模型几乎每次调用都用 Markdown 代码块包裹你,有些只有当你以特定方式措辞提示词时才会;但错误的类别到处都一样。
最常见的情况,大致按顺序如下:
1. Markdown 代码块包裹 JSON(模型以为它正在提供帮助)
2. 尾随逗号(训练数据中的 JS 习惯)
3. 使用 Python 的 `True`/`False`/`None` 而不是 JSON 的 `true`/`false`/`null`
4. 因响应中途 Token 耗尽而截断的对象
5. 字符串值内未转义的引号
6. JSON 内的 `//` 或 `#` 注释
7. 模型偷懒没有生成所有数据时的字面量 `...`
我特意在此发帖的原因是:我看到的大多数处理建议都是“直接使用 JSON 模式”或“使用受限语法”。
是的,如果可用,这些确实有帮助。但很多人本地运行的内容并没有可靠的 JSON 模式,基于语法的生成有其自身的权衡(速度、兼容性),而且即使你得到了语法有效的 JSON,仍然可能出现 Schema 违规和截断问题。
最终我构建了一个 Python 库 ([outputguard](https://github.com/ndcorder/outputguard)),当出现问题时,它会针对 JSON Schema 进行验证并按特定顺序运行 15 种修复策略。
排序部分比我预期的更重要:先修复编码再修复结构,并在每种策略之间重新解析,以免后续修复破坏之前的修复。
同时还支持 YAML、TOML 和 Python 字面量,一旦我开始与没有 JSON 模式且随意输出任何格式的模型合作,这种情况出现的频率比我想象的要高。
如果任何人想要详细信息,我已经将完整发现写成了博文:[向 LLM 请求 JSON 时会发生什么错误](https://thecrosswalk.news/what-breaks-when-you-ask-an-llm-for-json)
2,001 个测试用例,MIT 许可,无 LLM 提供商依赖。`pip install outputguard`
很好奇其他人的经历如何——你们是否看到了相同的失败模式,还是有某些模型/量化版本的表现与我描述的不同?
相似文章
我以为是模型问题的代理bug,结果出在框架上
作者分享了一次调试经历:代理循环是由框架截断工具输出导致的,而非模型故障,突显了代理基础设施相比模型存在的可靠性差距。
干掉 `Cow` 让我的 JSON 格式化器提速 42%
作者详细介绍了如何通过移除写时复制(Copy-on-Write, Cow)数据结构,使其 JSON 格式化器 JJPWRGEM 的性能提升了 42%,使其速度显著优于 Prettier 和 Oxfmt。
API 中的结构化输出介绍
OpenAI 在其 API 中引入了结构化输出功能,使开发者能够可靠地从语言模型获取符合 JSON Schema 的输出,改进与下游系统的集成并减少解析错误。
编码模型做得太多了
一篇博客文章探讨“过度编辑”问题:编码大语言模型在修复简单错误时改写了过多代码,提出衡量指标与训练方法以鼓励最小化、忠实于原意的编辑。
结构化输出的可移植性不如表面看起来那么高
作者分享了关于 JSON Schema 结构化输出在不同 AI 提供商(如 OpenAI、Gemini 和 Anthropic)之间缺乏可移植性的研究结果,强调了约束执行方面的一致性缺失,并为稳健的集成提供了实用建议。