20 min · 五级可靠性阶梯逐级走读,最后给一段可直接抄的校验重试代码
🎒 预备知识:完成上一课「A6 记忆」(零基础入口:第 0 课)
级 1:prompt 恳求。"请以 JSON 格式输出"。典型失败——模型贴心地包了一层:
好的!以下是 JSON:```json {...} ```。寒暄、代码围栏、尾逗号、单引号,全都会来。
级 2:few-shot。给一两个示例。格式漂移收敛大半,但换个模型/换个任务就得重调, 且字段多余/缺失仍不可控。
级 3:JSON mode / 受限解码。API 层保证输出能 parse。重要边界: 语法合法 ≠ 字段齐全——缺 required 字段、枚举拼错,它不管。
级 4:工具 schema 约束。用 function calling 的 parameters schema 承载输出 ("调用 submit_result 工具"),结构由 provider 约束解码保证。这是多数场景的最优解—— 你已经有工具基础设施了,复用它。
级 5:校验 + 重试。不管前面几级,永远生成后校验、失败回喂。 这是从"应该对"到"必然对"的最后一道闸。
from typing import Literal
from pydantic import BaseModel, ValidationError # pydantic:Python 最常用的数据校验库,用类型声明自动校验 JSON
class Verdict(BaseModel):
overall: Literal["pass", "warn", "fail"] # 枚举用 Literal:pydantic 会真的拦截越界值
issues: list[str]
top_fix: str
def ask_structured(messages, tries=3):
for i in range(tries):
raw = call_llm(messages) # 任意级别的前四级手段
try:
return Verdict.model_validate_json(raw)
except ValidationError as e:
messages += [ # 失败回喂,不是崩给用户
{"role": "assistant", "content": raw},
{"role": "user", "content":
f"输出不符合 schema:{e}。请严格按 schema 重输,"
f"overall 只能取 pass/warn/fail。"}]
raise RuntimeError("结构化输出连续失败") # 三次都坏才上抛——此时是真异常
注意这段代码和 A3 铁律①的同构性:校验失败是消息,不是异常—— 错误信息回喂让模型自我修复,重试上限才是失控保险丝。
模型输出的每个自由文本字段都是下游的定时炸弹。两个 Easel 实例:
① skill-quality-gate 的输出契约把结论定为三级枚举(overall_verdict)
加 issues 列表加 top_fixes——下游按 schema 解析,永不猜"模型到底什么意思";
② platform_readback 的四档结论(verified/unverified/login_required/readback_error)
本质是用枚举类型约束判断表达。设计原则:
能枚举的不要字符串,能数字的不要描述,字段能少一个就少一个。
坑 1:要求 JSON 但不校验。级 1-4 都上了,就是不 validate—— "大多数时候能 parse"在生产里等于"凌晨三点炸一次"。
坑 2:错误信息回喂得太抽象。"格式错误请重试"不如 "缺 issues 字段、overall 取了'通过'(只允许 pass/warn/fail)"——纠错信息越具体,重试越快成功。
坑 3:重试不设上限。和 loop 一样,重试也要保险丝(示例里的 tries=3)。
为"竞品分析技能"设计输出 schema(≥4 个字段、至少 1 个枚举、说明每个字段为什么值得结构化), 并写出第五级的校验重试伪代码(3 行即可)。发到对话里我批改。