我们在几乎每一个运行超过六个月的智能体系统中都看到同一种模式:一个叫 evals/ 的文件夹,里面是第二周热情写下的 40 个场景,加上一份比最近一次 prompt 改动还要早的 last_run.json。
这不是 evals 套件。这是三月某次会议的截图。
两份工作的难题
当 evals 套件游离于 CI 之外时,它最终会同时承担两份方向相反的工作:
- 说服自己系统能跑(跑一次、演示、归档)
- 在用户之前抓住回归(每次改动都跑、卡发布门禁)
第一份工作鼓励周到——写 200 条覆盖各种边界的用例。第二份工作鼓励速度——五分钟内跑完,否则没人会等。
脱离 CI 之后,套件往往倾向第一份工作,因为第二份没有强制力。结果是一份演示起来很惊艳、实战中却毫无用处的套件。
“在 CI 里”到底意味着什么
三件具体的事,按成本由低到高:
- 一个子集在每个 PR 上运行。 挑出 20–40 条快速、覆盖度高的用例。它们应在 90 秒内跑完,失败则阻断合并。
- 完整套件每晚对 main 分支运行一次。 失败时呼叫具体的人——不是 on-call 轮值,而是该 prompt 的 owner。
- 分数随时间追踪。 不只是通过/失败。某项引用准确率回归 4%,即便没踩硬门禁,也仍然是回归。
中间那条——失败时呼叫 owner——是团队往往跳过、然后再纳闷为什么漂移会复利累积的部分。
我们随每个系统交付的内容
一个 pnpm eval(或等价)目标,在本地两分钟内跑完快速子集。一个在 PR 上运行同样内容的 GitHub Action。一个每晚对生产 prompts 跑完整集合的任务。再加一个仪表板,只有两张图:按 tag 的通过率,以及通过率随时间的曲线。
就这些。这份清单里没有任何新颖之处。新颖之处在于它在第一天就接好了线,并且在我们离开后仍然接着。
为什么这套管用
工程师不会为不强制要求的系统写 evals。evals 套件不是道德象征,它是测试金字塔里承重的一环。把它放在其他测试该在的地方。