2025年底的共识是:想把 LLM 真正用到生产里,几乎绕不开“结构化输出”这一关。
目前主流的几种实现方式(由弱到强)
| 方式 | 可靠性 | 实现难度 | 代表工具/技术 | 备注 |
|---|---|---|---|---|
| 纯提示词工程 | ★☆☆☆☆ | 低 | 写 “必须用 JSON 格式输出,不要多说一句话” | 最简单,但最容易翻车 |
| 模型原生支持结构化输出 | ★★★☆☆ | 低 | OpenAI structured outputs, Claude 的 tool use, Gemini 等 | 2024-2025年大模型厂商陆续都加了这个功能,比较推荐的入门方式 |
| 代码侧后处理 + 重试 | ★★★★☆ | 中 | Instructor (Pydantic + 重试 + 修复) | 目前 Python 社区最受欢迎的生产方案之一 |
| 约束解码 / 引导生成 | ★★★★★ | 高 | Outlines, Guidance, jsonformer 等 | 最强保证,几乎不可能输出非法格式(靠有限状态机/grammar 强制) |
为什么它对生产级 LLM 应用这么重要?
- 下游系统才能可靠对接(解析不出 JSON → 整个链路崩)
- 减少幻觉(很多实验表明约束输出格式后,模型胡编乱造的概率显著下降)
- 能做复杂信息提取(合同、发票、病例、法规、简历、日志…… → 结构化字段)
- Agent / Function Calling / Tool Use 的基础(Agent 要调用工具,必须先结构化输出参数)
- RAG / 知识库构建(干净的结构化 chunk 质量远高于纯文本)、
Instructor
Instructor 比较好理解,发现结果不符合规则,则重试,重试几次即可。
Outlines
这里Outlines 就比较奇特了,从表格可以看到Outlines 比Instructor 优秀太多了,那么它是如何做到的呢 ?
| 维度 | Instructor | Outlines |
|---|---|---|
| 保证程度 | 很高(靠重试) | 100%(生成时强制) |
| 延迟 & token 消耗 | 可能翻倍(重试) | 几乎不变 |
| 兼容性 | 最好(几乎所有 API 厂商) | 很好(最好本地/vLLM/ollama) |
| 实现难度 | ★☆☆☆☆ 最简单 | ★★☆☆☆ 稍复杂 |
| 对小模型友好度 | 一般(function calling 弱) | 优秀 |
| 适用场景 | 快速原型、API 模型、复杂 Pydantic | 生产级、本地部署、高可靠性需求 |
| 社区热度(2026) | 最高(下载量第一) | 增长最快(硬核用户多) |
核心解决思路:
在 LLM 每生成一个 token 前,就用有限状态机 + logits 屏蔽的方式,强制只允许生成符合 schema 的下一个 token。 比如 JSON 要求下一个必须是 { 或 [,就直接把其他 token 的概率设为 0。
具体来说,当模型要生成下一个 token 时,Outlines 做了什么?
- 模型先正常算出所有 token 的 logits(原始分数,代表模型认为每个 token 有多大概率)。
- Outlines 拿到当前生成进度(用有限状态机 FSM 表示),计算出此时此刻,哪些 token 是合法的(能让输出继续保持在 schema 轨道上)。
- 对所有不合法的 token,直接把它们的 logit 值设为 -∞(或者等效地概率设为 0)。
- 模型只能从剩下的合法 token 集合里采样/选下一个 token。
→ 所以模型永远不可能输出一个会让 JSON 崩掉的 token(比如在应该写 “ 的地方写 ,,或者在对象里突然写数字开头)。
可以看到 Outlines是和模型深度耦合的,所以只有支持 logits processor 的模型才能使用 Outlines。而很多闭源大模型不支持 logits processor。