让大模型稳定吐 JSON:4 种工程化写法(含重试与校验)

为什么模型总爱加废话

大模型本质是「接着写」,你让它返回 JSON,它很可能顺手补一句「以下是结果」再给 JSON,或者直接包在 Markdown 代码块里。下游 json.loads 一碰就报错。要稳定,得用约束而不是靠 prompt 祈求。

办法一:response_format(最稳)

OpenAI 兼容接口原生支持 json_object 模式,DeepSeek / 通义 / 本地 vLLM 大多也支持。模型被强制只输出合法 JSON。

from openai import OpenAI
client = OpenAI()
r = client.chat.completions.create(
    model="gpt-4o-mini",
    response_format={"type": "json_object"},
    messages=[{"role": "user", "content": "提取订单:买了3个A和2个B"}]
)
import json
print(json.loads(r.choices[0].message.content))

办法二:函数调用(天然结构化)

把字段定义成 tool 的 schema,模型把参数填进 arguments,出来就是 JSON,连格式都帮你保证。

tools = [{"type": "function", "function": {
  "name": "save_order",
  "parameters": {
    "type": "object",
    "properties": {
      "items": {"type": "array", "items": {"type": "object",
        "properties": {"name": {"type": "string"}, "qty": {"type": "integer"}}}},
      "total": {"type": "number"}
    },
    "required": ["items"]
  }
}}]
r = client.chat.completions.create(model="gpt-4o-mini", tools=tools,
                                  tool_choice="auto", messages=[{"role": "user", "content": "订单:3个A 2个B"}])
print(r.choices[0].message.tool_calls[0].function.arguments)

办法三:schema 校验 + 重试兜底

即使有 json_object,字段也可能缺。用 pydantic 校验,失败就重试,最多 3 次。

from pydantic import BaseModel, ValidationError
class Order(BaseModel):
    items: list
    total: float

def parse(completion):
    for _ in range(3):
        try:
            return Order(**json.loads(completion))
        except (json.JSONDecodeError, ValidationError):
            continue
    raise ValueError("解析失败")
要求 JSONresponse_format/函数解析校验失败?重试
约束 → 生成 → 解析 → 校验重试

几个坑

  • json_object 模式要求 prompt 里明确「你要返回 JSON」,否则会拒答。
  • 函数调用返回的是字符串,记得 json.loads。
  • 超大结构用流式拼接再整体解析,别逐 token 解析。