工程实战

把模型评测接进 CI 流水线

大多数团队对 LLM 应用的测试还停留在”改完 prompt,手动跑几个例子看看像不像样”。这套流程在 demo 阶段够用,一旦进入迭代频繁的生产阶段就会失控:模型换了版本、prompt 改了一个字、RAG 的检索策略调整了,没人能确定这次改动会不会让某类 case 的回答质量下滑。真正的解法不是招更多人来手测,而是把评测当成单元测试一样接进 CI,让每次 PR 自动跑一遍评测集,用数字说话。

这篇文章聚焦”怎么把评测流水线搭起来”这件工程活儿本身:数据集怎么管、评测在 CI 里什么时候跑、跑多少、门禁怎么设、结果怎么呈现。评测方法论(怎么打分、怎么做 LLM-as-judge)本站已有专门文章覆盖,这里不重复展开。

一、为什么手动回归测试会失效

手动测试在团队规模小、迭代慢的阶段确实够用。但当以下任一条件成立时,它会系统性失效:

  • 迭代频率超过每周一次:人工跑 20 个 case 需要 15-30 分钟,一天改 5 次 prompt 就是 2 小时纯人力成本,团队会自然而然地开始”跳过测试直接上线”。
  • 评测维度超过 3 个:准确性、格式合规、语气、拒答边界……人脑很难同时盯住多个维度还保持客观,容易出现”看起来还行”的错觉判断。
  • 多人协作改同一个 prompt:没有基准数字,A 说”这次改动效果更好了”,B 说”我觉得变差了”,最后谁声音大谁赢,这不是工程决策。

CI 化评测解决的核心问题是把”感觉”变成”数字”,把”事后发现线上问题”变成”合并前拦截”。

二、评测数据集:从零散 case 到可维护资产

搭 CI 流水线之前,先要有一份能被程序读取、能版本化管理的评测集。常见的失败模式是评测数据散落在几个人的笔记本或聊天记录里,没人维护、没人知道哪些 case 还有效。

数据集的最小结构

一份可用于 CI 的评测数据集,建议至少包含这几个字段:

字段说明示例
id唯一标识,便于追踪历史趋势refund-policy-001
input完整的用户输入 / 上下文用户问题 + 必要的系统状态
expected期望输出或判断标准具体答案,或一组必须满足的规则
category分类标签,便于按维度统计边界拒答 / 多轮上下文 / 格式合规
severity该 case 失败的严重程度blocker / warning

severity 这个字段是很多团队漏掉的关键设计:不是所有失败的 case 都该阻塞合并。把 case 分成”必须通过”和”允许波动观察”两档,CI 门禁只对前者硬拦截,后者只做趋势记录,能避免评测集变成合并的绊脚石。

数据集来源与更新机制

  • 线上 bad case 回流:用户反馈、人工审核标记的问题案例,定期(建议每周)筛选补充进评测集,这是覆盖真实分布最有效的方式。
  • 对抗性构造:针对已知薄弱环节(如长上下文遗忘、多语言切换)人工构造边界 case。
  • 版本化管理:评测集本身应该进 git,改动走 PR review,避免有人为了让测试通过悄悄删掉难 case。

三、CI 里的触发时机与分层策略

不是每次评测都要跑全量数据集——那样 CI 会慢到没人愿意等。合理的做法是分层触发:

分层触发策略

  1. PR 提交时(快速层):只跑一个几十条的核心子集,覆盖最常见和最容易出问题的场景,目标是 3-5 分钟内出结果,反馈要快到不打断开发心流。
  2. 合并到主分支后(完整层):跑全量评测集(可能几百到几千条),允许跑 20-30 分钟,结果写入历史趋势表。
  3. 定时(每日/每周):针对模型服务商侧的漂移做监控——即便代码和 prompt 都没变,模型服务端更新也可能改变行为,定时跑同一批 case 能第一时间发现这类”背后动了手脚”的情况。

门禁设计

CI 门禁不是简单的”分数低于阈值就 fail”,实践中更实用的是相对比较:

  • 拿当前分支的评测结果和 main 分支最近一次的基准结果做对比
  • blocker 类 case 通过率下降 → 直接 fail,阻止合并
  • warning 类 case 或综合分数波动超过某个百分比(如 5%)→ 标黄警告,允许人工确认后合并,但会在 PR 评论里留痕
  • 分数提升也要记录,形成可追溯的改进历史,这对复盘”哪次改动真正带来了提升”很有价值

关于用 LLM 打分还是规则打分、多个判官投票如何聚合,属于评测方法论范畴,可以参考 LLM 评测 Golden Set 构建方法 和 Agent 轨迹级评测方法。

四、成本与延迟的现实约束

评测流水线本身也要调用模型 API,这部分成本容易被低估。几百条 case、每条可能还要额外调一次 judge 模型打分,一次全量评测的 token 消耗可能超过日常线上流量的一小部分。几个实用的控制手段:

  • PR 层用小模型评测子集,只有合并到主干才用更强的 judge 模型做完整评测,平衡成本和信号可靠性
  • 利用 prompt caching 把评测集里重复的系统提示词、few-shot 示例缓存起来,能显著降低重复评测的成本,具体可参考 Prompt Caching 成本优化实践
  • 并发调用 + 限流:评测集通常可以高并发跑,但要注意别把 CI 环境的 API key 打到限流,建议给评测流水线单独配置一个中转 key 和独立的速率限制

如果团队用的是 API 中转服务,独立的评测环境建议单独开一个 key、单独监控用量,避免评测跑爆导致生产环境的额度或速率被挤占。

五、结果呈现:让评测数字变成团队共识

评测跑完只是第一步,能不能变成团队共识才是关键。几个建议:

  • PR 评论自动贴摘要:机器人在 PR 下自动评论”本次改动:blocker 类 100% 通过,综合分数 92.3(基准 91.8,+0.5)“,让评审者不用跳出 GitHub 就能看到结果
  • 趋势看板:把每次合并后的完整评测结果存进时序数据库或者简单的 CSV,画一条趋势线,比单次数字更有说服力
  • 失败详情可下钻:门禁 fail 时,要能一键看到具体是哪几条 case 失败了、期望输出和实际输出的 diff,而不是只给一个红叉

评测流水线搭起来之后,和 Claude Code 之类的 AI 编程工具接入 CI 是自然的下一步——可以参考 Claude Code 接入 CI/CD:自动 PR 评审与 bug 修复,把评测门禁和代码评审结合起来,形成更完整的自动化闭环。但要注意区分职责边界:哪些环节适合完全自动化,哪些还需要人工把关,AI 编程 Agent 接入 CI 的边界 这篇有更细的讨论。

六、常见误区

  • 把评测集当成一次性任务:评测集需要像代码一样持续维护,过时的 case 会给出虚假的安全感。
  • 只看聚合分数不看分类分布:综合分数 90 分可能掩盖了某个关键分类(比如拒答边界)全军覆没的问题,按 category 拆解看才靠谱。
  • 门禁一步到位设得太严:刚搭好流水线就把所有 case 都设为 blocker,容易导致团队绕过 CI 或者干脆关掉检查,建议先跑一段时间收集基准数据,再逐步收紧。
  • 忽略评测本身的不确定性:LLM judge 打分存在方差,同一批 case 跑两次分数可能有小幅波动,门禁阈值要留出合理的容错空间,不要对着噪声做决策。

七、相关阅读