让结构化 LLM 输出进入可回放测试
llm-contract 采用固定 JSON Schema 约束输出,校验失败后向模型反馈具体错误并允许一次重试,再用录制案例在 pytest 中离线回放。作者还强调,时间序列或会话数据应按完整会话划分,避免随机切分造成评估泄漏。
AI 深度解读
LLM 返回的 JSON 能解析,不代表字段符合约定;几条样例看着不错,也不代表改了 prompt 就能放心上线。作者为自己的流水线做了 llm-contract,把固定 schema、校验反馈重试和录制用例回放串起来,让变更接受测试约束。
这套方案最值得借鉴的是把输出契约和评估流程一起管理。但有两个问题必须分清:数据有没有泄漏,以及不调用 API 的回放测试,究竟能证明什么。
先约束输出,再给模型一次纠错机会
llm-contract 的第一层是 schema-first extraction:每次 LLM 调用都必须返回符合固定 schema 的 JSON。schema 就是字段、类型等要求组成的结构契约。模型偏离约定时,流水线立即报错,避免错误数据继续流向后续环节。
第二层是 validation feedback retries。校验失败后,系统把具体违反了哪条规则反馈给模型,允许它重试 1 次;仍然失败的结果转交人工检查。
这比笼统地告诉模型「格式错了,再生成一次」更有针对性。模型拿到的是明确的修正目标,而重试上限也为自动纠错划出了边界。
作者说,多数情况下模型能自行修好,但没有提供成功率、样本量或失败类型。这只能算作者的实践观察。结构校验也有能力边界:字段类型正确,不代表字段里的事实正确,业务含义仍需要另外检查。
不调用 API 的 CI,能拦住哪些问题
第三层是可在持续集成(CI)中运行的评估测试框架。作者把输入、预期输出和元数据保存为录制用例,通过 pytest 运行。测试期间不发起 API 调用,全部使用录制内容回放。
这种做法让测试不依赖当次远端请求,适合检查解析、校验及后续处理逻辑是否发生回归。作者还要求,prompt 或模型的修改必须作为 commit 提交,完整测试集通过后才能合并。
但原文留下了一个关键空白:旧录制的回放通过,不能单独证明新 prompt 或新模型生成得更好。
如果回放内容没有更新,测试看到的仍然是过去的模型响应。要评价新变更,就需要说明新输出如何产生、录制如何更新,以及预期输出按什么标准判定。原文没有交代这些步骤,因此不能仅凭「全套测试通过」,就认定模型质量已经得到验证。
作者最后提出的交付习惯也很明确:发布权重但不附原始数据,发布指标而不靠文字描述,代码则附带测试。这是他准备标准化的模式,原文没有展开其具体实现。
为什么随机 80/20 可能让评估虚高
作者认为,数据怎么切分,比选择什么模型更关键。他过去使用随机 80/20 划分,后来发现,这对带时间戳或按会话组织的数据可能产生误导。
原因是相邻帧、同一会话里的记录往往高度相关。随机拆分后,相似内容可能同时进入训练集和评估集。评估成绩看起来很好,实际衡量的却可能是模型对相近内容的适应能力,而非面对新会话时的表现。
作者改为留出完整会话,并强调时间验证的价值。按他的描述,这通常会让测得的准确率明显下降,但他没有给出下降幅度或对照结果。
这里真正可迁移的原则是:评估集应当模拟上线后遇到的新数据,而不是只满足一个切分比例。
完整会话留出和时间验证也不是同一个条件。前者防止同一会话跨集合,后者关注过去与未来的边界;具体采用哪一种,需要看实际使用方式。
我的判断
我认同这套方案的工程方向:明确输出契约、限制纠错次数、把失败变成可追踪的测试结果,比人工抽看几条回答更容易持续执行。
它的局限在于,原文把结构正确、程序回归和模型质量放得很近,但三者需要不同证据。回放测试擅长验证已有响应的处理行为;重新调用模型才能观察新生成结果;后者还需要可靠的预期答案或评分规则。
「数据切分比模型重要」也应结合数据类型理解。对于会话相关、时间相关的数据,这个提醒很有价值;作者没有给出对照实验,不能把它当作所有任务都成立的排序结论。
能拿来做什么
- 给日常 AI 编程中的结构化提取任务定义固定 schema,先校验字段和类型,再让结果进入后续处理,并单独检查业务语义。
- 把具体校验错误反馈给模型,先采用原文的 1 次重试上限,将仍然失败的样本留下供人工检查。
- 在 Node 项目中借鉴录制回放的思路,把输入、预期输出和元数据纳入版本管理,同时明确哪些测试验证程序行为、哪些评估需要重新调用模型。
- 对带时间戳或会话标识的数据,检查随机 80/20 是否混入相关记录,再根据上线场景选择完整会话留出或时间验证。