Eval-Driven Development:AI时代的"测试驱动开发"

vibe-coding2026年9月3日14

Eval-Driven Development:AI时代的"测试驱动开发"

1. 引言:AI开发的"布朗运动"困境

你改了一版Prompt,跑了一个Case,输出看起来不错,于是上线了。三天后用户投诉,你又改了一版,跑了同一个Case,"嗯这次好多了",又上线了。一周后另一批用户投诉。你在做工程吗?不,你在扔骰子。

这是当前大量LLM应用开发团队的真实写照。没有评测集就优化Prompt,跟没有地基就盖楼一样——迟早会塌。

问题的根源在于:传统软件开发的质量保障体系,在AI时代失效了。

传统测试的核心假设是确定性——同样的输入,必须产生同样的输出。一个单元测试可以是assert(add(1, 2) === 3),结果非对即错。

LLM的输出是概率性的——同样的Prompt,十次可能给你八种不同的回答。它没有"标准答案",只有"好"与"坏"的连续谱。

这种根本差异意味着:"跑通一次"在传统软件里能说明问题,在LLM应用里毫无意义。

于是,我们需要一套新的方法论——评估驱动开发(Eval-Driven Development,简称EDD)。


2. 什么是评估驱动开发(EDD)?

一句话定义:先建评测集,再迭代Prompt/模型/检索,每次改动都拿评测集回归验证。

EDD是LLM系统的"测试驱动开发"(TDD)。两者的核心思想完全一致——先定义"什么是对的",再去做。区别只在于度量方式从"通过/失败"变成了"评分/阈值"。

环节 TDD(传统软件) EDD(AI应用)
第一步 先写测试用例 先建评测数据集
第二步 写代码让测试通过 写Prompt/调模型让评测分数上升
第三步 重构,确保测试仍通过 优化,确保评测不回归
核心纪律 不写测试不写代码 不建评测集不优化Prompt
度量方式 通过率100% 评测分数≥阈值

EDD解决的核心问题是:AI应用没有确定性输出,无法用传统断言验证,必须用一套可重复、可量化的评估体系来驱动开发。


3. EDD的核心要素

3.1 黄金数据集(Golden Dataset)

EDD依赖的测试数据不是越多越好,而是越精越好。

建议从100条左右的高质量样本开始,最多扩展到500条。原因是EDD的每次运行可能涉及LLM API调用,有成本和速度的约束。

更重要的是,研究表明1000条精心策划的示例足以让650亿参数模型的表现对齐到GPT-4的水平。质量远比数量重要。

黄金数据集应该包含:

  • 理想案例:模型应该完美通过的典型场景
  • 边缘案例:带噪音、格式混乱、边界条件的真实输入

3.2 评估指标(Metrics)

EDD的指标分为两类:

确定性指标:可以用代码硬编码检查。例如:

  • 输出是否为合法JSON
  • 是否包含某些关键词
  • 字符数是否在限制范围内

主观质量指标:需要模型或人工评判。例如:

  • 语气是否合适
  • 内容是否有用
  • 是否出现幻觉

关键在于:找到"什么对你用户来说算好" ,这件事没有人能替你回答,因为"这正是护城河的来源——那些别人不容易复制的、对你产品独有的洞察"。

3.3 评判者(Judge)

评估主观指标需要"评判者":

  • 代码检查:快、免费、适合确定性规则
  • 人工反馈:精度高、不可扩展,适合早期探索
  • LLM-as-Judge:用另一个模型来评分,可扩展但有偏差风险

实践中通常组合使用:用代码检查做快速过滤,用LLM-as-Judge评估主观维度。

3.4 评估类型

EDD中的评估像传统测试一样分层:

  • 单元评估:测试特定组件(如检索精度、工具调用准确率)
  • 回归评估:端到端测试,每次改动后运行,确保整体性能不退化

4. 一个最小的可工作例子

假设我们在构建一个客服支持Agent,它需要根据公司政策回答用户问题。初始版本没有产品知识,只会根据LLM的通用知识"胡诌"。

步骤1:构建评测数据集

eval_data = [
    {
        "question": "How do I reset my password?",
        "expected_response": "Go to the login page, click 'Forgot Password', enter your email, and follow the link in the email. The link expires after 24 hours."
    },
    {
        "question": "What's your refund policy?",
        "expected_response": "Full refunds are available within 30 days of purchase. After 30 days, we offer store credit. Refunds are processed in 5-7 business days."
    },
    {
        "question": "Can I change my shipping address?",
        "expected_response": "Go to Order History, select the order, and click 'Edit Shipping Address'. Changes can only be made before the order ships."
    }
]

只有3条样本也可以启动,5条足以开始,但建议逐步扩展到覆盖更多边缘案例。

步骤2:定义评估器

使用MLflow的评分器,从三个维度评估:

from mlflow.genai.scorers import Correctness, RelevanceToQuery, Guidelines

# 正确性:回答是否匹配预期事实
correctness = Correctness()

# 相关性:回答是否针对问题
relevance = RelevanceToQuery()

# 政策遵守:是否给出具体步骤、时间线,不编造政策
support_policies = Guidelines(
    name="support_policies",
    guidelines=[
        "Always include specific steps or actions the user can take",
        "Include relevant timeframes, deadlines, or SLAs when applicable",
        "Never make up policies -- only state facts from the company knowledge base"
    ]
)

步骤3:编写Agent(初版)

import openai
import mlflow

SYSTEM_PROMPT_V1 = "You are a customer support agent."

@mlflow.trace
def support_agent(question: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT_V1},
            {"role": "user", "content": question}
        ]
    )
    return response.choices[0].message.content

步骤4:运行评估

baseline_results = mlflow.genai.evaluate(
    data=eval_data,
    predict_fn=support_agent,
    scorers=[correctness, relevance, support_policies]
)

print(baseline_results.metrics)
# 输出示例:
# {'correctness/mean': 0.2, 'relevance_to_query/mean': 1.0, 'support_policies/mean': 0.4}

初版Agent相关性不错,但正确性仅0.2——因为它不知道公司实际政策,胡编乱造。

步骤5:迭代改进

现在我们知道了问题所在,可以针对性地优化:给System Prompt加入公司政策知识库。

SYSTEM_PROMPT_V2 = """
You are a customer support agent for our company.
Follow these policies exactly:
- Password reset: Users must go to login page, click 'Forgot Password', enter email, link expires in 24 hours
- Refunds: Full refund within 30 days, store credit after 30 days, processed in 5-7 business days
- Shipping changes: Can edit in Order History before shipment
Never invent policies. Always give concrete steps and timeframes.
"""

重新运行同样的评估:

improved_results = mlflow.genai.evaluate(
    data=eval_data,  # 同一个数据集!
    predict_fn=support_agent_improved,
    scorers=[correctness, relevance, support_policies]
)

print(improved_results.metrics)
# 输出示例:
# {'correctness/mean': 0.9, 'relevance_to_query/mean': 1.0, 'support_policies/mean': 0.95}

正确性从0.2提升到0.9。同一个评测集告诉我们:这个改动确实有效,而且没有引起其他维度的退化。

步骤6:持续集成

将这个评估流程纳入CI/CD,每次PR自动运行:

# CI配置
mlflow.genai.evaluate(data=eval_data, predict_fn=support_agent)
if aggregate_score < 0.85:
    exit(1)  # 阻止合并

"绿色的评测套件就是发布的门禁" 。


5. EDD vs TDD vs SDD:对比与辨析

5.1 EDD vs TDD

TDD(测试驱动开发)的流程是"红灯→绿灯→重构":先写一个失败的测试,再写代码让它通过,最后重构保持通过。

EDD的流程是"低分→高分→优化":先运行评估看到低分,再改进Prompt/架构让分数提升,最后优化确保不退化。

维度 TDD EDD
输出性质 确定性 概率性
验证方式 断言(对/错) 评分(好/坏程度)
测试数量 尽可能多 约100-500条精样本
执行成本 几乎免费 可能昂贵(LLM API调用)
回归发现 自动发现崩溃 不跑评测不知道退化
改动影响 局部可控 改一个词可能全局雪崩

TDD是"确定性工程的纪律",EDD是"概率性工程的纪律" 。

5.2 EDD vs SDD

SDD在不同语境下有不同含义:

在传统软件工程中,SDD有时指规格说明驱动开发(Specification-Driven Development)——先写详细的需求规格说明书,再编码实现。这是一种"文档先行"的模式,强调"写清楚再动手"。

而EDD是"评估先行"——不是写文档,而是建立可自动运行的评估系统来定义"什么算做完了"。

两者的核心区别:

维度 SDD(规格说明驱动) EDD(评估驱动)
先写什么 需求文档 评估数据集
"完成"的定义 文档通过评审 评估分数达标
反馈周期 文档→实现→验证(长) 评估→改进→评估(短)
适用场景 需求相对稳定的系统 需求随AI能力演进的系统

另有说法称SDD为支持驱动开发(Support-Driven Development) ,强调开发与客户支持协作,但这不是主流定义。

5.3 与BDD/ATDD的关系

BDD(行为驱动开发)和ATDD(验收测试驱动开发)强调用业务语言写测试,促进业务方、开发、测试三方协作。

EDD可以视为BDD思想在AI领域的延续——只不过"行为示例"变成了"输入输出样本","验收测试"变成了"评估器"。EDD同样建议与领域专家一起定义"什么是好的输出",特别是识别那些只有专家才能发现的细微故障模式。

5.4 总结对比

方法论 核心驱动力 验证方式 适用场景
TDD 单元测试 断言通过/失败 确定性代码
BDD/ATDD 验收场景 业务用例验证 需求明确的业务系统
SDD 规格文档 文档评审 需求稳定的系统
EDD 评估数据集 评分≥阈值 LLM/概率性系统

6. EDD的落地要点

6.1 什么时候使用EDD?

EDD并非万能,以下情况应该使用:

  • 构建的AI应用已有足够的问题轮廓,能定义"做完了"长什么样
  • 需要频繁迭代Prompt、切换模型或调整架构
  • 有明确的失败模式和期望行为

以下情况可以跳过或延后:

  • 还在探索阶段,团队都不知道"好的输出"是什么样,快速手动迭代比写评测更有价值

6.2 常见陷阱

1. 过拟合评测集

如果在构建功能时同时编写评测用例,可能不自觉写出"匹配当前Agent行为"而非"匹配理想行为"的用例。应该基于期望行为而非观察到的行为来写评测。

2. 评测标准过于严格或模糊

精确匹配会拒绝合理的同义表达。应使用基于结果的评判(检查状态、测试套件)或语义等价评判,而非字符串匹配。

3. 评测集太小

5条样本足以开始,但不足以可靠检测回归。应随着发现边缘案例不断扩充数据集。

6.3 成熟度阶梯

将EDD实践分为几个阶段,可以对照评估团队当前状态:

阶段 特征 评测覆盖率
凭感觉调Prompt 没有评测在CI中运行 0%
冒烟测试 对几个固定用例做简单断言 <20%
系统化EDD 黄金数据集+多维度评估+CI门禁 核心路径覆盖
生产反馈闭环 生产样本自动采样、人工标注后加入数据集 持续增长

7. 结语:从"感觉工程"到"度量工程"

AI开发很容易陷入一种幻觉:模型能说会道,所以它在做"正确的事情"。但"看起来合理"和"实际正确"之间,横亘着一条叫做"可度量性"的鸿沟。

TDD让软件开发从"写完再测"变成了"测完再写",EDD让AI应用开发从"凭感觉调Prompt"变成了"用数据驱动决策" 。

EDD的核心不是"评测"本身,而是用评测驱动决策——每次改动Prompt、换模型、改架构,评测数据集都能告诉你:这件事是让产品变好了,还是变坏了?

没有评测集就优化AI应用,不是在做工程,是在扔骰子。

而扔骰子的人,没法赢得长期信任。