评测驱动开发(01):从 TDD 到评测驱动

QuibblerAgentQuibblerAgent 2026-11-13 约 14 分钟 2 次阅读

在传统软件里,测试写在代码后面;在大语言模型(LLM)应用里,顺序正在被倒过来——先写评测,再写应用。Braintrust 在 2026 年 2 月的博客 What is eval-driven development 里给这套做法起了正式名字:评测驱动开发(Eval-Driven Development,EDD)。它的核心主张只有一句话:先把"什么是好输出"写成可执行的评测集,再动手改提示词、换模型。

本站此前的《AI Agent 开发》系列用 30 篇解决"搭骨架",《上下文工程》系列用 18 篇解决"供血液",本系列是第三根支柱:EDD 负责"验健康",也是六大新系列里的第二个。作为系列第 1 篇,本文不重复 Agent 系列第 27 篇讲过的 LangSmith 工具入门,专注方法论本身:先讲 EDD 与 TDD 的血缘与分野,再展开 eval-as-oracle 模式、八步工作流闭环与评测四象限,最后给出后续 13 篇的路线图。


1、从 TDD 到 EDD

每个工程师都熟悉 TDD(Test-Driven Development,测试驱动开发)的红绿重构:先写一个失败的测试(红),用最小实现让它通过(绿),再在不弄灭绿灯的前提下重构。EDD 直接继承了这个骨架,只是每一环都换成了概率世界的对应物。

两者的映射关系如下:

TDD EDD 含义
红:先写失败测试 先建评测集 定义"好"的标准
绿:最小实现通过 迭代提示词与模型 让指标过线
重构:保持绿灯 重构:指标不劣化 安全地改结构
测试套件防回归 回归门禁防劣化 概率版的"绿灯"

真正的分野在确定性。TDD 的前提是被测函数是确定性的:同一个输入永远得到同一个输出,绿灯一旦亮起就不再熄灭。LLM 恰恰相反——temperature 大于 0、采样随机、底层模型还在被供应商悄悄更新,同一个问句问三遍可能得到三个答案。

TDD 的绿是一种状态,EDD 的绿是一个统计量。

所以 EDD 里没有 100% 绿:判定从布尔值变成分数与通过率,assertEqual 变成"相关性得分不低于 0.8";跑一次通过不算数,还要看多次运行的稳定性。接受了这一点,后面所有流程与工具的设计逻辑都会顺理成章。

2、LLM 应用的三重失控

为什么普通 Web 应用不需要 EDD,LLM 应用却离不开?因为在三个方向上,LLM 应用同时失去了传统软件的安全网。

第一重失控:提示词改动等于全系统改动。提示词就是源代码,却运行在一个没有编译器、没有类型系统、没有 lint 的环境里。改一个词,没有任何工具能告诉你影响了哪条路径;500 行的 system prompt 是全项目最大的隐式全局变量,牵一词而动全身。

第二重失控:模型升级是隐性行为变更。模型版本是锁不住的外部依赖:供应商静默更新、旧版本弃用、同名模型行为漂移,都是家常便饭。传统软件升级依赖,看 changelog 加测试套件就够;LLM 应用唯一能依靠的,是一套可随时全量重跑的评测集。

第三重失控:"感觉更好"是反科学的。改完提示词,随手试三条,变好了,上线——样本量为一,没有对照组,还叠加确认偏误。Hamel Husain 在广被引用的评估入门长文里反复强调:没有评测的迭代等于蒙眼开枪。更麻烦的是,LLM 应用的失败多是软失败:不抛异常、不返回 500,而是输出一段"看起来对"的错误答案,错误率与延迟监控全绿,质量却在劣化。

三重失控的共同解法,是把"感觉"换成"测量"。这正是 EDD 的全部动机。

3、评测即规格

3.1、先写应用再补评测

多数团队的真实路径长这样:想法 → 提示词 → demo 一鸣惊人 → 上线 → 用户抱怨 → 想复现问题,却发现没有评测集,无法判断"到底改好没有" → 临时拼 20 条测试 → 修好 A 场景,悄悄弄坏 B 场景。

补出来的评测集只覆盖已经翻车的案例,本质是一份亡羊补牢清单:它只能防住已知的坏,定义不了什么是好。

3.2、先写评测再写应用

Braintrust 给出的模式叫 eval-as-oracle:评测集就是你的规格说明书。oracle 借自软件测试理论,test oracle 指判定"输出对不对"的机制;传统软件的 oracle 是一行断言,而 LLM 应用没有唯一正确输出,oracle 便升级为"一个评测集加一组评估器",成为应用的工作规格(working specification)。

DeepEval 在 2026 年 10 月的实践博客里把 EDD 落成三步:准备数据集、定义指标、迭代与回归。学术侧也有呼应:CSIRO Data61 团队的EDDOps 论文(arXiv 2411.13768)给出了把评测嵌入设计、开发、运维全生命周期的过程模型与参考架构。

一条最小评测长这样,基于 DeepEval:

from deepeval import assert_test
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase

def test_refund_flow():
    metric = AnswerRelevancyMetric(threshold=0.8)  # 过线分数,而非布尔断言
    case = LLMTestCase(
        input="退货流程是什么?",
        actual_output=bot.answer("退货流程是什么?"),  # 被测系统
        expected_output="给出 7 天无理由退货的操作步骤",
    )
    assert_test(case, [metric])

这段代码没有一行应用逻辑,却已经完整定义了"好":输入是什么、期望覆盖什么、几分算过线。assert_test 的角色与 pytest 的普通断言相同,只是断言对象从"相等"换成了"分数过线"。真实项目里,你会把几十条这样的用例组织成 golden set,覆盖常见、边界与对抗场景。

运行方式与普通测试无异:

deepeval test run tests/evals/ --minimum-pass-rate 0.75

输出不再是绿点,而是带分数的报告:

Test: test_order_status
  answer relevancy | score 0.92 | threshold 0.8 | PASS
Test: test_refund_flow
  answer relevancy | score 0.61 | threshold 0.8 | FAIL
Overall pass rate: 50.0% (minimum 75.0%) -> exit 1

两个细节值得注意:判定单位是分数而非布尔值;通过率低于下限时命令以非零退出码结束,这正是 CI(持续集成)回归门禁的雏形。一句话对比两种姿势:先评测后应用,评测集是设计工具,逼你在写第一行提示词前回答"好输出长什么样";先应用后评测,评测集只是道歉工具。

4、EDD 工作流全景

把 EDD 摊开,是一条八步闭环,全貌如下:

flowchart TD A["定义任务"] --> B["建评测集"] B --> C["实现应用"] C --> D["离线评测"] D --> E["分析失败"] E -->|"未过线"| F["迭代改进"] F --> A E -->|"过线"| G["回归门禁"] G -->|"CI 全量重跑"| H["上线"] H --> I["线上监控"] I --> J["新样本回流评测集"] J -.->|"闭环"| B

八个步骤各有要点:

  • 1 定义任务:一句话任务定义,加好输出的验收标准
  • 2 建评测集:golden set 起步 30~100 条,覆盖边界场景
  • 3 实现:提示词、检索、工具编排
  • 4 评测:看分数分布,不只看均值
  • 5 分析失败:聚类失败样本,找模式而非逐条 hack
  • 6 迭代:针对失败类别改提示词、加示例、换检索
  • 7 回归门禁:CI 全量重跑,设通过率下限
  • 8 线上监控:漂移检测,坏例回流评测集

第 7 步落到工程上,就是一段 CI 配置:

name: evals
on: [pull_request]
jobs:
  regression:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install deepeval
      - name: run regression evals
        run: deepeval test run tests/evals/ --minimum-pass-rate 0.9

从此,任何提示词改动、模型升级、依赖更新都必须先过这道回归门禁才能合并。再看一眼图里第 8 步的回流箭头:评测集是活文档,线上新出现的坏例不断补进去,评测集随产品一起生长——这是 EDD 与"一次性测试"最本质的区别。

5、评测体系的四象限

评测不是单一活动。按时机场(离线/在线)与判定方式(自动/人工)切两刀,得到四象限:

自动判定 人工判定
离线 组件级评测、端到端评测 人工标注、团队评审会
在线 A/B 实验、指标与漂移监控 点赞点踩、投诉、抽检

离线自动是主力,也是 CI 门禁的唯一对象。它分两层:组件级类似单元测试,单独测检索命中率、工具选择准确率;端到端类似集成测试,评判整条回答乃至完整轨迹的质量。

离线人工最贵,却是全体系的地基:人工标注的 golden set 是 judge 校准的燃料,没有它,自动评估器的分数无从取信。在线自动看真实业务指标与漂移;在线人工是最真实的信号,也是最慢的信号。

四象限不是孤岛,而是互相喂养:线上点踩回流进离线评测集,经过人工标注校准的 judge 反过来承担线上抽检。成熟的团队四个象限都有布点,起步团队优先把左上角做扎实。

6、与上下文工程的衔接

把三个系列放回一张图:《AI Agent 开发》搭骨架,让系统会规划、会调工具;《上下文工程》供血液,让每一步喂给模型的信息又准又省;《评测驱动开发》验健康,量出这套系统到底行不行。

上下文工程系列第 15 篇已经把"上下文质量"从直觉变成可评测的对象。本系列是那个思路的放大:上下文质量只是众多被测维度之一,EDD 提供"定义、测量、迭代、回归"的外循环,上下文工程优化的是循环里的被测对象。反过来,评测本身也是上下文工程——judge 的提示词怎么写、评测集怎么构造,本质仍是"喂给模型什么"的问题。两个系列互为表里。

7、系列路线图

本系列规划 14 篇,本篇之后按"数据、度量、过程、门禁、线上、安全"推进:

板块 篇数 覆盖内容
评测数据集 2 golden set 构造、真实流量采样
评估器 2 规则校验、语义相似度、指标设计
LLM-as-a-Judge 2 judge 提示词、偏差治理、与人工对齐
轨迹评测 2 多步任务、工具调用、过程质量
CI 与门禁 2 回归流水线、失败聚类分析
线上评测 2 漂移检测、A/B 实验、反馈回流
红队与安全 1 对抗样本、提示注入与越狱

工具层面会横跨 DeepEval、LangSmith 文档 与 Braintrust。LangSmith 的界面操作 Agent 系列第 27 篇已经讲过,本系列不再重复工具教程,专注方法论与选型判断。

8、总结

EDD 的全部内容可以压成四句话:评测当规格,先定义好输出再写应用;迭代当开发,分数不过线就不合并;回归当门禁,每次改动全量重跑;监控当哨兵,线上坏例回流评测集。并且永远记住:概率世界里没有 100% 绿,只有"分数不劣化"。

行动建议有三条。对于已在维护 LLM 应用的团队,建议本周就从线上日志挑 30 条真实请求,人工标注好坏,跑出第一个基线分数——它会立刻告诉你当前版本的真实水平,通常并不乐观。对于正要立项的团队,建议把"建评测集"写进里程碑,并排在"写提示词"之前。对于个人开发者,建议现在就装上 DeepEval,把本文的 test_refund_flow 抄进项目跑通——体验一次分数化的绿,你就回不去了。

相关推荐

​Jev 详解:不做生成的判断模型
精选AI

​Jev 详解:不做生成的判断模型

Jev 详解:不做生成的判断模型让 LLM 干"判断"的活,一直是件拧巴的事:它擅长生成文本给人读,你要的却是结构化决策给代码用——于是提示词约束、JSON 解析、重试兜底一层层糊上去。TypeSafe AI 的答案是干脆换一类模型:Jev,首个 System One 模型——不做文本生成,专职快速、结构化的判断:输入状态与类型化问题,输出带概率与置信度的结构化答案,类型错误在数学上不可能发生,因

718
网站被注入恶意脚本排查实录:AI 辅助安全分析实战
置顶 精选AI

网站被注入恶意脚本排查实录:AI 辅助安全分析实战

网站被注入恶意脚本排查实录:AI 辅助安全分析实战某天收到华为云监管反馈,称个人博客网站存在色情违规界面。作为技术博主,这简直是晴天霹雳——网站一直正常运行,怎么会突然出现这类问题?经过排查发现,网站被注入了恶意跳转脚本。本文记录完整的排查过程,重点分享如何借助 AI 快速定位问题并修复,希望能给遇到类似情况的开发者提供参考。1、问题发现与初步排查收到监管反馈后,第一时间打开网站检查。首页看起来完

421
博客七周年:AI 一天完成整体重构
全站置顶 精选AI

博客七周年:AI 一天完成整体重构

博客从 2019 年国庆用 Xiuno BBS 搭建,到 2026 年国庆整整七年。868 篇文章、53 条评论、6060 个代码块,这次与 AI Agent 结对,一天完成从 PHP 论坛到 Next.js 的整体重构与无损迁移。

379