给 LLM Agent 搭自动化验收:分层用例、双裁判与 Golden 答案
我们给 ERP 系统接了一个 LLM Agent:用户在系统侧边栏用自然语言问”今天 3 号炉的生产计划怎么样”,Agent 调后端工具查数据,再组织成一段业务回答。
现在每发一个版本,两段都要人工扛。发布是六步手工命令:本地 build 镜像、打包、传到服务器、导入、起容器、验证健康检查。验收更麻烦:发布后在侧边栏手敲指令,人肉看 Agent 调没调对工具、数据对不对、有没有泄露内部字段。
人肉验收的缺口很明显:Agent 答非所问但格式正确,也能通过;边界情况靠记忆,覆盖不住。所以这次把发布和验收都自动化:一键触发,先本地联调、再发布、再线上验收,最后出报告。
先分层:确定性的事和语义的事分开
Agent 的输出里混着两类性质不同的东西。
确定性的事:有没有走到终态、调没调对工具、有没有把内部字段(计划 ID、状态码)直接吐出来、澄清话术有没有脱敏。这些跟模型无关,程序断言就能判。
语义的事:回答的数字对不对、状态判没判反、有没有编一个不存在的炉次。这些正则查不出来。
两类放在一起测会互相拖累,所以拆成四层:
| 层 | 测什么 | 什么时候跑 |
|---|---|---|
| L0 单元/契约 | 接口、鉴权、消息结构 | 每次提交 |
| L1 工具契约 | 后端工具入参出参 + 只读 DB 校验 | 发布前后 |
| L2 端到端 scenario | 完整对话链路行为 | 发布前后 |
| L3 冒烟 | 健康检查 + 两三条关键 case | 发布后立刻 |
确定性断言覆盖 L0/L1 和 L2 的一部分,语义判定只放在 L2。
正则查不了”业务对不对”
举一个真实问题。
用户问”今天 3 号炉生产计划怎么样”,Agent 回答”有 5 个炉次,状态都是进行中”。
正则断言能确认三件事:调了生产计划查询工具、没泄露 planId、走到了 final。但判断不了 5 对不对、状态是不是真的”进行中”、有没有编炉次。
这层缺口用 LLM 补:再拿一个模型当裁判,把”问题 + 工具返回的真实数据 + Agent 的回答”一起喂进去,让它按标准判。
LLM 当裁判,先想清楚三个坑
方案听起来直接,落地前有三个坑要先踩明白。
第一,裁判自己也会错。裁判也是 LLM,会被 Agent 流畅但错误的回答糊弄。解法是让裁判对答案,后面讲 Golden。
第二,同源盲区。裁判和 Agent 用同一个模型,可能犯同样的错。所以用两个不同模型交叉评。
第三,判分不稳。同一个回答,裁判多次判可能不同。解法是档位制 + 低温 + 结构化输出。低温是调低模型的随机性参数,让它输出更确定;结构化输出是让它吐固定 JSON,机器能直接读、能前后对比,也逼它每个维度都给结论。
档位制评分 + 硬门禁
判分不打裸分,设四个维度,每个维度分”好/中/差”三档,再加权合计成 10 分制:
| 维度 | 权重 | 硬门禁 | 判什么 |
|---|---|---|---|
| 忠实性 | 40% | 是 | 回答是否严格基于工具数据,有没有编造数字/炉次/状态 |
| 正确性 | 40% | 是 | 数据对不对、有没有答用户问的核心问题 |
| 业务恰当性 | 10% | 否(WARN) | 是否用业务化表达而非内部字段,该澄清时澄清 |
| 边界合规 | 10% | 否(WARN) | 有没有声称超出能力、泄露内部实现 |
档位映射:好=10、中=5、差=0,加权总分满分 10。
硬门禁的规则:忠实性、正确性任一判”差”,直接 FAIL,不看总分。剩下两个维度只做 WARN,不硬卡发布。总分默认阈值 8.0,低于阈值也进 WARN,交人工复核。
裁判输出固定成 JSON:
1 | |
Golden 答案:让裁判对答案
Golden 是预先算好的标准答案。链路这样走:
- 用例”今天 3 号炉生产计划怎么样”。
- 只读 SQL 查库,得到真实答案:5 个炉次,状态”进行中”。
- 让 Agent 回答同一问题,它说”6 个炉次”。
- 把”问题 + Golden + Agent 回答”一起给裁判。
- 裁判看到 6 对 5,忠实性判”差”。
裁判自己不懂业务、也不能查库,所以必须给 Golden。有了 Golden,裁判是对答案,数字编错、状态判反、编炉次都会在忠实性/正确性上落马。
Golden 来源优先只读 DB 实时查,生产计划每天变,预置假数据会过期。
双裁判 + 分歧处理
单裁判可能误判,所以用两个不同模型(这次是 Qwen 和 Codex)各自独立判:
- 两个都 PASS → PASS
- 两个都 FAIL → FAIL
- 一个 PASS 一个 FAIL → 自动重判一次,还分歧就升级 WARN,交人工复核
不同模型家族互相纠偏,压住单个模型的盲区。
Prompt 变更单独记账
这套系统有个历史坑:语义约束加得太多,模型最后变”傻”了。所以 Prompt / 语义约束的变更必须单独记账:
- 报告里声明:这次改的是 Prompt/语义约束,不是代码。
- 记录改了哪条约束、为什么改、影响什么。
- 同一 scenario 变更前后各跑一遍,对比裁判各维度档位变化。
裁判分数正好能量化”变聪明还是变傻”。去掉一条多余约束后,”业务恰当性”从低档升到高档,这就是证据。
一键流程和分支红线
最终是 agent 一键触发,串成五步:
1 | |
分支上有一条红线:只允许 dev 往 Canary 合,禁止 Canary 反向往 dev 合。反向合并只能人工做,自动化流程不得执行,也不得绕道。
代价和边界
代价集中在三处:
- LLM 非确定性还在,靠分层 + 档位 + 重判隔离,没有彻底消除。
- 裁判误差只能降低不能归零,需要定期抽样本人工复核校准。
- Golden 要维护:每个 scenario 都要有对应的只读查询,数据模型变了 Golden 也要跟着改。
它解决的是”发布 + 验收靠人扛”这件事,不解决 Agent 本身写得好不好。语义约束有没有过量,靠前后对比的裁判分数给信号,不靠感觉。