Logo
热心市民王先生

方案选型对比

技术研究 LLM 方案对比

输出控制方案的深度对比:JSON Mode vs Structured Outputs vs Instructor vs Tool Use

替代方案概述

针对 LLM 指令遵循问题,业界主流有四种输出控制方案:

方案提供商核心机制保证级别
方案 A: JSON ModeOpenAI / Anthropic系统提示强制 JSON 格式最佳努力(~95%)
方案 B: Structured OutputsOpenAI / Anthropic / GoogleAPI 级 schema 约束 + 受限解码强制约束(99-100%)
方案 C: Instructor Library第三方(开源)Pydantic 验证 + 自动重试依赖重试(~98%)
方案 D: Tool Use / Function CallingOpenAI / Anthropic将输出约束为函数调用强制约束(~99%)

对比维度

1. Schema 合规率

xychart-beta
    title "各方案 Schema 合规率对比(%)"
    x-axis ["JSON Mode", "Structured Outputs", "Instructor", "Tool Use"]
    y-axis "合规率" 90 --> 100
    bar [95, 99.9, 98, 99]

测试条件

  • 复杂 schema(10+ 字段,嵌套对象)
  • 1000 次请求统计
  • 相同 prompt,相同模型(GPT-4o)

数据来源Vellum AI Function Calling vs Structured Outputs

2. 实现复杂度

方案代码行数依赖库学习曲线调试难度
JSON Mode5-10 行中(需手动解析)
Structured Outputs10-20 行Pydantic/Zod低(类型安全)
Instructor10-15 行Instructor 库低(自动重试)
Tool Use20-30 行中(需定义函数)

3. 性能影响

方案延迟影响Token 效率成本影响
JSON Mode基准基准基准
Structured Outputs+5-15%节省 30-60%略低(token 少)
Instructor+10-30%(重试)与 JSON Mode 相同略高(重试消耗)
Tool Use+5-10%与 JSON Mode 相同相同

说明

  • Structured Outputs 使用受限解码(constrained decoding),在 token 生成阶段就过滤不合规选项,反而可能减少 trial-and-error
  • Instructor 重试会增加延迟,但仅在验证失败时触发(发生率<5%)

4. 错误恢复能力

flowchart LR
    subgraph A["JSON Mode"]
        A1[解析失败] --> A2[手动捕获]
        A2 --> A3[手动重试]
        A3 --> A4[需自定义逻辑]
    end
    
    subgraph B["Structured Outputs"]
        B1[Schema 违规] --> B2[API 拒绝]
        B2 --> B3[自动重试]
        B3 --> B4[保证最终合规]
    end
    
    subgraph C["Instructor"]
        C1[验证失败] --> C2[库捕获]
        C2 --> C3[自动重试 + 反馈]
        C3 --> C4[最多 max_retries]
    end
    
    subgraph D["Tool Use"]
        D1[参数无效] --> D2[API 拒绝]
        D2 --> D3[模型重试]
        D3 --> D4[返回 function_call]
    end
    
    style A fill:#ffcdd2
    style B fill:#c8e6c9
    style C fill:#fff9c4
    style D fill:#bbdefb

5. 可移植性

方案OpenAIAnthropicGoogle本地模型
JSON Mode
Structured Outputs✅ (完整)✅ (beta)⚠️ (有限)
Instructor
Tool Use⚠️⚠️

关键洞察:Instructor 库提供最佳可移植性,支持所有主流提供商和本地模型(通过 LiteLLM、Ollama 等)。

决策矩阵

综合对比表

维度JSON ModeStructured OutputsInstructorTool Use
Schema 合规率⭐⭐⭐ (95%)⭐⭐⭐⭐⭐ (99.9%)⭐⭐⭐⭐ (98%)⭐⭐⭐⭐⭐ (99%)
实现简单度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
错误恢复⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
可移植性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Token 效率⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
类型安全⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
维护成本⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

推荐使用场景

场景推荐方案理由
生产环境关键路径Structured Outputs100% 合规保证,类型安全
快速原型/POCJSON Mode最快实现,无需 schema 定义
多供应商支持Instructor统一接口,自动切换
复杂业务逻辑验证Instructor + Pydantic自定义验证器,错误反馈
Agent/工具调用Tool Use原生支持,语义清晰
成本敏感型应用Structured OutputsToken 用量减少 30-60%
本地模型部署Instructor支持 Ollama、vLLM 等后端

选择理由

推荐方案:Structured Outputs + Instructor 组合

基于本研究的目标(生产级指令遵循稳定性),我们推荐:

Primary(首选): Structured Outputs(OpenAI 或 Anthropic)

理由

  1. 最高合规率:OpenAI 官方保证 100% schema 合规,消除解析错误
  2. 类型安全:Pydantic/Zod 模型提供编译时检查
  3. Token 效率:精简 schema 节省 30-60% 输出 token
  4. 开发体验:直接使用 Python/TypeScript 类型,无需手动验证

Fallback(备选): Instructor Library

理由

  1. 多供应商支持:无缝切换 OpenAI、Anthropic、Google、本地模型
  2. 自动重试:验证失败自动反馈给模型,无需手动实现
  3. 复杂验证:支持自定义 Pydantic 验证器(email 格式、业务规则等)
  4. 向后兼容:可逐步迁移到原生 Structured Outputs

为什么不推荐纯 JSON Mode

问题影响缓解方案
无法保证合规5-10% 请求解析失败需要手动重试逻辑
无类型安全运行时错误风险需手动编写验证器
** verbose schema**增加输入 token无法优化
错误反馈困难需手动解析错误增加代码复杂度

结论:JSON Mode 仅适用于原型阶段,生产环境应升级到 Structured Outputs。

为什么不推荐纯 Tool Use

Tool Use 的优势在于语义清晰(明确区分指令与工具调用),但在以下场景不如 Structured Outputs:

  1. 简单数据提取:不需要工具调用的语义开销
  2. 嵌套复杂结构:Tool Use 的 parameter schema 不如 Pydantic 灵活
  3. 流式输出:Structured Outputs 支持 stream,Tool Use 通常不支持

结论:Tool Use 适用于 Agent 场景,数据提取优先选择 Structured Outputs。

迁移路径

对于已使用 JSON Mode 的项目,建议按以下路径迁移:

flowchart LR
    A[当前:JSON Mode] --> B[阶段 1: 添加 Pydantic 模型]
    B --> C[阶段 2: 集成 Instructor]
    C --> D[阶段 3: 迁移到原生 Structured Outputs]
    
    A --> A1["可靠性:~95%"]
    D --> D1["可靠性:~99.9%"]
    
    style A fill:#ffcdd2
    style D1 fill:#c8e6c9

阶段 1:定义 Pydantic 模型,手动验证

from pydantic import BaseModel

class Event(BaseModel):
    name: str
    date: str

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[...],
    response_format={"type": "json_object"}  # JSON Mode
)
data = json.loads(response.choices[0].message.content)
event = Event(**data)  # 手动验证

阶段 2:集成 Instructor,自动重试

import instructor
client = instructor.patch(OpenAI())

event = client.chat.completions.create(
    model="gpt-4o",
    messages=[...],
    response_model=Event,  # 自动验证 + 重试
    max_retries=3
)

阶段 3:迁移到原生 Structured Outputs

response = client.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[...],
    response_format=Event  # 原生支持
)
event = response.choices[0].message.parsed

参考资料