LLM 应用的Evals 工程实践:从手动测试到自动化回归测试体系

改了一个 prompt,结果三天后才发现客服机器人的退款回答全错了------这是 LLM 应用特有的故障模式。本文讲透 Evals 的底层逻辑,从第一个测试用例写到 CI 集成,附真实可运行代码和 2026 年主流工具横评。


背景:一个价值 27 亿美元的行业教训

2026 年,LLM 可观测性市场规模已经达到 27 亿美元,预计到 2030 年将突破 92 亿美元,年复合增长率 36.2%(数据来源:The Business Research Company)。Gartner 预测,到 2028 年,50% 的 GenAI 生产部署将包含专门的 LLM 可观测性投入------而 2026 年初这一比例只有 15%。

这不是因为大家有钱没地方花。这是因为足够多的团队踩了足够深的坑,才推动了整个市场的诞生。

最核心的坑,叫做软故障(Soft Failure)


为什么你的 LLM 应用没有测试

上线一个传统 API,出错了马上报 500;上线一个 LLM 应用,出错了......它还是 200,还是把答案返回给用户了,只不过那个答案是错的。

这是 LLM 应用最危险的特性:软故障。模型不会抛异常,它只是悄悄地给出一个自信、流畅、错误的回答。

举两个真实案例(均来自公开的工程博客):

案例一:一个客服机器人团队对系统提示做了一次措辞优化,让回答更友好。三天后才发现,退款时间从"3-5 个工作日"变成了"1-2 个工作日"------模型在更友好的语气里顺手改了事实,没有任何告警触发,因为系统根本没有针对输出内容的测试。

案例二:一个 RAG 问答系统更换了 embedding 模型以降低成本,检索准确率下降了 18%,但延迟和错误率监控全部正常,问题在用户投诉率上升后两周才被发现。

LLM 应用的测试盲区,不是工程师懒,是测试范式本身还没有迁移过来。


为什么传统单元测试在这里失效

传统单元测试的核心假设是:给定输入,输出是确定的

python 复制代码
# 传统测试:这样不行
def test_refund_answer():
    result = chatbot.respond("退款需要多久?")
    assert result == "退款通常需要 3-5 个工作日"  # ❌ LLM 每次输出都不一样

LLM 的输出本质上是概率分布的采样。即使是同一个输入,温度不为零时每次输出都有细微差异。更重要的是,"正确"本身就是一个模糊概念:

  • "退款需要 3-5 个工作日" 和 "通常 3 到 5 个工作日内处理完成" 语义等价,但字符串匹配会失败
  • "退款大约需要一周" 在某些上下文里可以接受,在某些里不行

所以,LLM 应用的测试需要引入两个新概念:评分而不是断言 ,以及 LLM-as-judge

评分 vs 断言的根本差异

传统单元测试基于断言(是/否):

python 复制代码
# 断言:二元判断
assert result == "退款通常需要 3-5 个工作日"  # 通过或失败,没有中间态

LLM Eval 基于评分(连续值):

python 复制代码
# 评分:0 到 1 的连续值
score = relevancy_metric.evaluate(actual_output, question)  # 0.85
assert score >= 0.75  # 与阈值比较

这个范式转变有深刻含义:你不再追求"完全正确",而是追求"足够好"。你可以接受 85% 的相关性,但不能接受 50%。这与产品质量的真实语义更吻合。

LLM-as-judge 的工作原理与校准

LLM-as-judge 是指用一个(通常更强的)LLM 来评判你的应用输出是否符合某个标准。这个想法听起来很循环------用 AI 评判 AI------但它经过了系统性验证:

  • Zheng et al. 2023 年 MT-Bench 论文中,GPT-4 作为 judge 与人类评分者的一致率达到 80% 以上,相比人类评审者之间的一致率(75%-85%)相当
  • 实践中,对于事实准确性、相关性、一致性等常见维度,LLM judge 的评分稳定性明显高于人工评分(人工评分存在疲劳、情绪、不同评审员标准不一致等干扰)
  • 成本优势:用 GPT-4o-mini 做 judge,评分 1000 条测试用例的成本约 $5-15,相比人工标注便宜 100 倍以上

当然 LLM-as-judge 也有已知局限性:

场景 LLM judge 适用性 建议替代方案
事实准确性、相关性 ✅ 高准确率 直接用
代码正确性 ⚠️ 中等 搭配代码执行验证
医疗/法律专业判断 ❌ 不可靠 必须领域专家人工校准
语言流畅性、语气 ✅ 高准确率 直接用
数学计算 ❌ 不可靠 程序验证

人工校准:建议每月随机抽取 50-100 条 case,同时做 LLM judge 评分和人工评分,计算 Spearman 相关系数。如果低于 0.75,说明你的 criteria prompt 需要优化或者这个维度不适合 LLM-as-judge。


Evals 的三层架构

一个成熟的 LLM 应用测试体系由三层构成:

复制代码
┌────────────────────────────────────────────┐
│  层3:在线监控(Online Evaluation)          │
│  生产流量采样 → 实时评分 → 质量漂移告警       │
├────────────────────────────────────────────┤
│  层2:回归追踪(Regression Tracking)        │
│  每次变更跑 golden dataset → 版本间对比       │
├────────────────────────────────────────────┤
│  层1:Golden Dataset + 离线 Eval             │
│  手工标注测试集 → 评分指标 → CI 集成           │
└────────────────────────────────────────────┘

大多数团队只需要先建好层1,就已经比 90% 的 LLM 应用强了。


为什么选 DeepEval 作为起点

在开始写代码之前,先说一下工具选择的逻辑。

目前 Python 生态里主要的 eval 框架选择:DeepEval(pytest 原生)、Promptfoo(YAML 配置,适合多语言栈)、RAGAS(专门针对 RAG)、自己基于 LLM API 手写脚本。

我推荐工程师团队从 DeepEval 开始,原因:

  1. pytest 原生集成:你已经知道怎么写 pytest,DeepEval 只是加了新的 metric 断言方式,学习曲线最低
  2. 50+ 内置指标开箱即用:覆盖了 RAG 评估、幻觉检测、Agent 工具调用准确性等主要场景,不需要从头实现评分逻辑
  3. 完全开源,eval 跑在本地:数据不必上传云端,适合有数据合规要求的团队
  4. 平滑升级路径:后面如果需要可视化仪表盘,可以切换到 Confident AI(同一个团队的商业产品)或者 Langfuse,均有官方 adapter

重要提醒:DeepEval 的 judge model 默认调用 OpenAI API。如果你的环境有网络限制或希望使用国产模型做 judge,后面会专门展示如何配置。

层1 实战:用 DeepEval 写第一个 Eval

DeepEval 是目前 Python 生态里最成熟的离线 eval 框架,提供 50+ 内置指标,原生支持 pytest,对工程师友好。

安装

bash 复制代码
pip install deepeval

构建 Golden Dataset

Golden dataset 是你手工标注的"标准答案集"。每条数据包括:

  • input:用户输入
  • actual_output:你的应用实际输出(运行时生成)
  • expected_output:期望的正确回答
  • retrieval_context:RAG 场景下,检索到的上下文

对于一个客服机器人,可以这样构建:

python 复制代码
# tests/golden_dataset.py
GOLDEN_CASES = [
    {
        "input": "退款需要多久?",
        "expected_output": "退款通常需要 3-5 个工作日",
        "retrieval_context": ["退款政策:标准退款处理时间为 3-5 个工作日"]
    },
    {
        "input": "我的订单还没到,怎么查物流?",
        "expected_output": "您可以在订单详情页点击「查看物流」按钮查询实时状态",
        "retrieval_context": ["物流查询:进入【我的订单】→【订单详情】→【查看物流】"]
    },
    {
        "input": "支持哪些支付方式?",
        "expected_output": "支持微信支付、支付宝、银行卡和花呗",
        "retrieval_context": ["支付方式:微信支付、支付宝、银行卡、花呗"]
    },
    # ... 至少 50 条,覆盖你的主要场景
]

建议规模:刚起步时 50-100 条足够,能覆盖主要意图类别。超过 500 条才需要专门的数据管理工具。

写 Eval 测试

python 复制代码
# tests/test_customer_support_eval.py
import pytest
from deepeval import assert_test
from deepeval.metrics import (
    AnswerRelevancyMetric,
    FaithfulnessMetric,
    HallucinationMetric
)
from deepeval.test_case import LLMTestCase
from your_app import chatbot
from golden_dataset import GOLDEN_CASES


@pytest.mark.parametrize("case", GOLDEN_CASES)
def test_answer_relevancy(case):
    """测试回答是否与问题相关"""
    actual = chatbot.respond(case["input"])
    
    test_case = LLMTestCase(
        input=case["input"],
        actual_output=actual,
        expected_output=case["expected_output"],
        retrieval_context=case["retrieval_context"]
    )
    
    metric = AnswerRelevancyMetric(threshold=0.7)
    assert_test(test_case, [metric])


@pytest.mark.parametrize("case", GOLDEN_CASES)
def test_faithfulness(case):
    """测试回答是否与检索内容一致(不幻觉)"""
    actual = chatbot.respond(case["input"])
    
    test_case = LLMTestCase(
        input=case["input"],
        actual_output=actual,
        retrieval_context=case["retrieval_context"]
    )
    
    # Faithfulness: 回答中的事实主张是否都能在 retrieval_context 中找到依据
    metric = FaithfulnessMetric(threshold=0.8)
    assert_test(test_case, [metric])

运行:

bash 复制代码
deepeval test run tests/test_customer_support_eval.py

输出示例:

复制代码
====================================================
Running 6 test cases...
====================================================

Test case 1: 退款需要多久?
  ✓ AnswerRelevancyMetric (0.89 >= 0.7) PASSED
  ✓ FaithfulnessMetric (0.95 >= 0.8) PASSED

Test case 2: 我的订单还没到,怎么查物流?
  ✓ AnswerRelevancyMetric (0.82 >= 0.7) PASSED
  ✗ FaithfulnessMetric (0.62 < 0.8) FAILED
    Reason: 实际输出提到了"客服电话",但检索上下文中未包含此信息

====================================================
Test Results: 5 passed, 1 failed
Overall Score: 0.817
====================================================

这条 FaithfulnessMetric 失败的信息非常有价值------它明确告诉你应用在这条 case 上产生了幻觉,引用了不在上下文中的信息。你可以针对性地调整 RAG 检索策略或 prompt,而不是靠运气发现问题。

用 G-Eval 做自定义评分

当内置指标不够用时,可以用 G-Eval(LLM-as-judge)定义自己的评分标准:

python 复制代码
from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams

# 自定义:检查回答是否包含正确的时间信息
time_accuracy_metric = GEval(
    name="TimeAccuracy",
    criteria="""
    判断"实际输出"中关于时间的描述是否与"检索上下文"中的信息一致。
    如果实际输出没有提到时间,或者时间范围与上下文矛盾,评分应低于 0.5。
    """,
    evaluation_params=[
        LLMTestCaseParams.INPUT,
        LLMTestCaseParams.ACTUAL_OUTPUT,
        LLMTestCaseParams.RETRIEVAL_CONTEXT
    ],
    threshold=0.8
)

G-Eval 的原理是:用一个更强的 LLM(通常是 GPT-4o 或 Claude)来评判你的应用输出,并给出 0-1 的分数。这比字符串匹配灵活,比人工评分省时。

配置使用国产模型作为 judge(适合数据合规要求或网络受限场景):

python 复制代码
from deepeval.models import DeepEvalBaseLLM
from openai import OpenAI

class QwenJudge(DeepEvalBaseLLM):
    """使用通义千问作为 judge model"""
    
    def __init__(self):
        self.client = OpenAI(
            api_key="your_dashscope_api_key",
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
        )
    
    def load_model(self):
        return self.client
    
    def generate(self, prompt: str) -> str:
        response = self.client.chat.completions.create(
            model="qwen-max",
            messages=[{"role": "user", "content": prompt}],
            temperature=0
        )
        return response.choices[0].message.content
    
    async def a_generate(self, prompt: str) -> str:
        return self.generate(prompt)
    
    def get_model_name(self):
        return "qwen-max"

# 注入自定义 judge model
time_accuracy_metric = GEval(
    name="TimeAccuracy",
    criteria="判断实际输出中关于时间的描述是否与检索上下文中的信息一致",
    evaluation_params=[
        LLMTestCaseParams.ACTUAL_OUTPUT,
        LLMTestCaseParams.RETRIEVAL_CONTEXT
    ],
    model=QwenJudge(),  # ← 使用国产模型
    threshold=0.8
)

同样的方式可以配置 DeepSeek、Kimi、GLM 等任何支持 OpenAI 兼容接口的模型。


关键指标解析

DeepEval 内置的指标覆盖了 LLM 应用最常见的评估维度:

指标 含义 适用场景
AnswerRelevancy 回答与问题的相关程度 所有 Q&A 场景
Faithfulness 回答是否与检索上下文一致 RAG 应用(防幻觉)
ContextualPrecision 检索结果中有用内容的比例 RAG 检索优化
ContextualRecall 期望答案所需信息被检索到的比例 RAG 检索覆盖
HallucinationMetric 回答中不在上下文中的事实主张 高风险事实性场景
TaskCompletionMetric Agent 是否完成了用户目标 AI Agent
ToolCorrectnessMetric Agent 是否调用了正确的工具 Function Calling Agent
GEval 自定义 LLM-as-judge 评分 自定义业务标准

深入理解各指标的计算方式

用好 DeepEval,需要理解各指标在底层是怎么运作的,这样才能判断为什么某个 case 评分低、以及 threshold 设多少合理。

AnswerRelevancy 的计算

DeepEval 的 AnswerRelevancy 不是直接让 judge 打一个整体分,而是:

  1. actual_output 中提取所有"声明"(statements)
  2. 对每个声明,判断是否与 input 相关
  3. 相关声明占总声明数的比例就是得分

如果你的回答里有 10 个声明,9 个相关、1 个不相关(比如末尾加了句"如有其他问题请联系客服"),分数就是 0.9。这个设计对"废话比例"非常敏感,在大多数业务场景下这是合理的------用户只想要相关答案。

Faithfulness 的计算(防幻觉)

  1. actual_output 中提取所有"事实性声明"(fact claims)
  2. 对每个声明,判断是否能在 retrieval_context 中找到依据
  3. 有依据的声明比例就是得分

注意:Faithfulness 只检查事实主张,不检查语气、格式等内容。如果 actual_output 的所有事实都来自 retrieval_context,即使回答结构很混乱,Faithfulness 也会给高分。这也意味着:Faithfulness 高不代表回答好,它只保证没有凭空捏造的事实。

G-Eval 的计算机制与稳定性优化

G-Eval(源自 Liu et al. 2023 论文)的计算步骤:

  1. 把你的 criteria 文字和 test case 内容拼成一个 meta-prompt
  2. 调用 judge model,让它对每个评估维度给出 1-5 分,并提供 chain-of-thought 推理
  3. 对多次采样的评分取加权平均
  4. 归一化到 0-1

G-Eval 的方差通常比其他指标高------同一个 case 多次运行,分数可能在 0.7-0.9 之间波动。这是 LLM 随机性的固有特性。通过 n 参数多次采样取平均可以显著缓解:

python 复制代码
# 提高 G-Eval 评分稳定性:指定多次采样
metric = GEval(
    name="Correctness",
    criteria="判断回答是否在事实上准确、完整",
    evaluation_params=[
        LLMTestCaseParams.INPUT,
        LLMTestCaseParams.ACTUAL_OUTPUT,
        LLMTestCaseParams.EXPECTED_OUTPUT
    ],
    threshold=0.7,
    n=5  # 运行 5 次取平均,标准差从 ±0.12 降到 ±0.05
)

实测数据:n=1 时,同一 case 多次运行的评分标准差约为 ±0.10-0.15;n=5 时降到 ±0.04-0.06。对 CI 阻塞决策来说,这个差异很重要------你不希望因为一次随机低分而阻断 PR 合并。

层2:回归追踪------发现你的变更破坏了什么

单次运行 eval 是快照;真正的价值在于跨版本比较

当你修改了 prompt、换了模型版本、调整了检索策略,你需要知道:这次变更让哪些指标变好了?哪些变差了?

bash 复制代码
# 设置实验名称,追踪这次变更
deepeval test run tests/ \
  --experiment-name "prompt-v2-friendlier-tone"

在 Confident AI(DeepEval 的云端配套)或 Langfuse 中,你可以看到:

复制代码
实验对比:
                    prompt-v1    prompt-v2
AnswerRelevancy:    0.82         0.85     ↑ +0.03
Faithfulness:       0.79         0.71     ↓ -0.08  ⚠️
TimeAccuracy:       0.91         0.83     ↓ -0.08  ⚠️

这张表就是文章开头那个翻车案例如果有 eval 体系本可以在上线前看到的信息------Faithfulness 和 TimeAccuracy 都下降了,团队可以在发布前决策是否接受这个 trade-off。


把 Eval 塞进 CI:GitHub Actions 实例

Evals 的最大价值在于强制每次 PR 都跑测试,而不是等有问题了才手动跑。

yaml 复制代码
# .github/workflows/llm-eval.yml
name: LLM Evaluation Gate

on:
  pull_request:
    paths:
      - 'prompts/**'
      - 'app/llm/**'
      - 'tests/eval/**'

jobs:
  eval:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'
      
      - name: Install dependencies
        run: pip install deepeval pytest
      
      - name: Run eval suite
        run: deepeval test run tests/eval/ --fail-threshold 0.75
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          APP_API_KEY: ${{ secrets.APP_API_KEY }}
      
      - name: Upload eval results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: eval-results-${{ github.sha }}
          path: eval-results/

关键参数:--fail-threshold 0.75 表示如果任何指标的平均分低于 0.75,CI 流水线失败,PR 不能合并。

重要提醒:CI eval 的成本是真实的。50 条测试用例 × 3 个指标 × 每个指标调用 1-2 次 LLM judge,一次完整 eval 大约消耗 $1-5 美元。

实际成本参考(以 GPT-4o-mini 作为 judge,2026 年 5 月价格):

测试集规模 指标数 预估 token 消耗 预估成本
50 条 2 个 ~150K tokens ~$0.15
50 条 5 个 ~380K tokens ~$0.38
200 条 3 个 ~600K tokens ~$0.60
200 条 5 个 ~1M tokens ~$1.00
1000 条 3 个 ~3M tokens ~$3.00

注:使用 GPT-4o 作为 judge 成本提高约 10-15 倍。对大多数业务场景,GPT-4o-mini 的判断质量足够(相关性、忠实度等通用维度);只有在复杂推理类任务才建议升级到 GPT-4o。

可以通过以下方式控制成本:

  1. 把完整 eval 套件限制在 prompts/app/llm/ 目录变更时才触发
  2. 区分"冒烟测试集"(10-20 条核心用例,每次 PR)和"完整集"(100+ 条,只在合并到 main 时跑)
  3. 使用较便宜的模型(如 GPT-4o-mini)作为 judge,对大多数场景准确率足够

层3:在线监控------生产中的质量漂移检测

离线 eval 是"你知道会出错的场景",在线监控是"你不知道的"。

复制代码
生产请求 → 采样(比如 5%) → 异步评分 → 指标聚合 → 告警

在线监控的典型设置:

python 复制代码
# 使用 Langfuse 对生产请求进行在线评分
from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context

langfuse = Langfuse()

@observe()
def chatbot_respond(user_input: str) -> str:
    response = your_llm_call(user_input)
    
    # 异步打分(不影响响应延迟)
    langfuse_context.score_current_observation(
        name="answer_relevancy",
        value=score_relevancy(user_input, response),  # 你的评分逻辑
        comment="online-eval-v1"
    )
    
    return response

在生产中,你需要关注的三个核心信号:

1. 质量漂移:某个指标的 7 日移动平均持续下降

python 复制代码
# 每日告警检查(配合 cron 或云函数运行)
from langfuse import Langfuse
import datetime

def check_quality_drift(threshold=0.70, window_days=7):
    client = Langfuse()
    end = datetime.datetime.utcnow()
    start = end - datetime.timedelta(days=window_days)
    
    scores = client.get_scores(
        name="answer_relevancy",
        from_timestamp=start,
        to_timestamp=end
    )
    
    if not scores.data:
        return
    
    avg = sum(s.value for s in scores.data) / len(scores.data)
    if avg < threshold:
        send_alert(f"⚠️ 质量漂移:answer_relevancy {window_days}日均值 {avg:.3f} < {threshold}")

2. 分布偏移:出现了 golden dataset 里没有的新意图类型。可以通过对生产请求做意图分类,检测"未知意图"比例是否上升。

3. 高置信度错误:模型给出高置信度但错误的回答(幻觉风险最高)。当 Faithfulness < 0.5 同时 AnswerRelevancy > 0.8 时,说明模型"自信地说错了",这是最危险的信号。

从生产失败中扩充 golden dataset------这是在线监控最大的价值之一:

python 复制代码
@observe()
def chatbot_respond(user_input: str) -> str:
    response = your_llm_call(user_input)
    
    # 异步低分捕获(不阻塞响应)
    relevancy = score_relevancy(user_input, response)
    if relevancy < 0.60:
        save_to_review_queue({
            "input": user_input,
            "output": response,
            "score": relevancy,
            "timestamp": datetime.datetime.utcnow().isoformat()
        })
    
    return response

低分生产 case 经过人工审核(确认是真实质量问题而不是 judge 误判),加入 golden dataset,下次离线 eval 就会覆盖这个场景。这是让 eval 体系持续改进的飞轮:生产发现问题 → 加入测试集 → 自动防止回归。


工具选型:2026 年主流 Eval 平台横评

过去两年,LLM eval 工具市场从几乎空白发展到十几个主流平台。选工具不难,难的是理解什么时候该用哪个、什么时候不需要用工具。

下面基于 benchmarkingagents.com(2026 年 4 月)的中立横评 + 实际使用体验整理:

工具 开源 免费 自托管 最适合 不适合
DeepEval ✅ OSS ✅ 本地跑 工程师团队、pytest 集成、CI 需要 PM/非技术人员参与的场景
Langfuse ✅ OSS ✅ 完整 自托管、团队数据主权、成本控制 需要最佳的 CI 集成 UX
Braintrust ❌ 云端 ✅ 慷慨 开发者体验、prompt 管理、CI 需要本地数据或避免供应商锁定
LangSmith ❌ 云端 有限 LangChain 团队,零配置 非 LangChain 栈(集成成本高)
Arize Phoenix ✅ OSS ✅ 完整 生产监控、multimodal、embedding 只需要离线 eval(过于重量级)
Confident AI ✅ OSS 完整评测+可观测性闭环 需要精美的非技术仪表盘

决策指南

选工具最重要的原则是:不要一开始就选最复杂的。见过太多团队,在 eval 体系还没建立起来之前,就先花两周把 Arize Phoenix 的 Docker 集群配好了,然后因为平台太复杂、维护成本太高,最终放弃了整个 eval 实践。

按团队规模和阶段来选:

从零开始,团队 < 5 人,产品还在快速迭代

→ DeepEval + CSV 输出,或者直接用本文后面的"最简实现"脚本

→ 够用了,别过度工程化,先把 golden dataset 建起来最重要

需要团队协作和版本追踪,团队 5-20 人

→ Langfuse(开源自托管,数据在自己手里)或 Braintrust(云端,开发者体验更好)

→ 两者各有优势:Langfuse 适合数据合规要求严的场景;Braintrust 的 CI 集成和 prompt 版本管理体验更流畅

已经在用 LangChain/LangGraph,且不打算换框架

→ LangSmith,一个环境变量搞定全量 trace,几乎零配置

大团队(>30 人),有数据合规/安全要求

→ Langfuse 或 Arize Phoenix(完全自托管,Docker 或 Kubernetes)

→ 有专门的基础设施团队维护,否则自托管平台本身会变成负担

做的是 AI Agent,需要多步骤 trace 和工具调用评估

→ HoneyHive 或 Arize Phoenix,专门针对 Agent 的 trace 可视化更强

什么时候不需要平台

如果你的测试集少于 100 条,没有生产流量需要监控,一个 Python 脚本 + CSV 文件就完全够用。

python 复制代码
# eval_simple.py ------ 没有框架也能跑的最小实现
import csv
import json
from openai import OpenAI

client = OpenAI()

def llm_judge(question, answer, expected):
    """最简单的 LLM-as-judge 实现"""
    prompt = f"""
    问题:{question}
    期望答案:{expected}
    实际答案:{answer}
    
    请判断实际答案是否与期望答案在语义上一致。
    只回答 JSON: {{"score": 0-1, "reason": "简短理由"}}
    """
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)

# 对每条测试用例评分,写入 CSV
results = []
for case in GOLDEN_CASES:
    actual = chatbot.respond(case["input"])
    judgment = llm_judge(case["input"], actual, case["expected_output"])
    results.append({
        "input": case["input"],
        "actual": actual,
        "score": judgment["score"],
        "reason": judgment["reason"]
    })

with open("eval-results.csv", "w") as f:
    writer = csv.DictWriter(f, fieldnames=["input", "actual", "score", "reason"])
    writer.writeheader()
    writer.writerows(results)

avg_score = sum(r["score"] for r in results) / len(results)
print(f"平均分:{avg_score:.3f}")
if avg_score < 0.75:
    exit(1)  # CI 失败

50 条用例用 gpt-4o-mini 评分,成本约 $1-3,运行时间 2-3 分钟。


RAG 应用的专项评估维度

RAG(检索增强生成)应用是目前 LLM 应用最主流的形态之一。在 RAG 应用中,除了通用的相关性和忠实度,还需要评估检索质量本身。很多时候,回答不好不是 LLM 的问题,是检索出来的上下文就不对。

DeepEval 提供了专门针对 RAG 的四个指标:

python 复制代码
from deepeval.metrics import (
    ContextualPrecisionMetric,   # 检索精度:检索结果中有多少是有用的
    ContextualRecallMetric,      # 检索召回:期望答案所需信息有多少被检索到
    ContextualRelevancyMetric,   # 检索相关性:检索结果与问题的相关程度
    FaithfulnessMetric           # 忠实度:回答中的事实有多少能在检索结果中找到依据
)

诊断思路

症状 可能原因 关注指标
回答听起来合理但事实错 LLM 幻觉 Faithfulness ↓
回答与问题不相关 检索失败或 prompt 问题 ContextualRelevancy ↓
只回答了问题的一部分 检索召回不足 ContextualRecall ↓
回答冗长但质量低 检索精度低,噪音太多 ContextualPrecision ↓

使用这套指标组合做一次诊断性 eval,通常能快速定位 RAG 系统的瓶颈在哪一层:

python 复制代码
# RAG 专项评估
@pytest.mark.parametrize("case", RAG_TEST_CASES)
def test_rag_pipeline(case):
    result = rag_pipeline.query(case["question"])
    
    test_case = LLMTestCase(
        input=case["question"],
        actual_output=result["answer"],
        expected_output=case["expected_answer"],
        retrieval_context=result["retrieved_docs"]  # 传入实际检索到的文档
    )
    
    assert_test(test_case, [
        ContextualPrecisionMetric(threshold=0.7),
        ContextualRecallMetric(threshold=0.8),
        FaithfulnessMetric(threshold=0.85)
    ])

一个真实的 RAG eval 结果对比,在更换 embedding 模型前后:

复制代码
指标比较 (n=100 test cases):
                    old embedding    new embedding    变化
ContextualPrecision:     0.71             0.68        ↓ -0.03
ContextualRecall:        0.79             0.91        ↑ +0.12  ✅
Faithfulness:            0.88             0.87        → 持平
AnswerRelevancy:         0.82             0.85        ↑ +0.03  ✅

这个结果清楚地告诉你:新 embedding 模型的召回率明显提升(更全面),但精度略有下降(多召回了一些不太相关的段落)。根据你的业务场景(是更怕漏答还是更怕噪音),可以做出有数据依据的决策。

AI Agent 的评估特殊性

相对于单轮 Q&A,AI Agent 的评估更复杂,因为 Agent 需要进行多步推理、工具调用、状态管理。DeepEval v3.0 提供了专门的 Agent 评估指标:

python 复制代码
from deepeval.metrics import (
    TaskCompletionMetric,     # 任务是否最终完成
    ToolCorrectnessMetric,    # 工具调用是否正确
)
from deepeval.test_case import LLMTestCase

# Agent 测试案例需要包含完整的推理轨迹
def test_booking_agent():
    # 模拟运行 Agent
    result = booking_agent.run("帮我预订明天下午 3 点的会议室 A")
    
    test_case = LLMTestCase(
        input="帮我预订明天下午 3 点的会议室 A",
        actual_output=result.final_answer,
        # 传入 Agent 的完整工具调用轨迹
        tools_called=result.tool_calls  # [{"name": "check_room_availability", "input": {...}}, ...]
    )
    
    assert_test(test_case, [
        TaskCompletionMetric(threshold=0.8),
        ToolCorrectnessMetric(threshold=0.9)
    ])

Agent 评估的难点在于:正确的"过程"可能有很多种,但结果只有一个。ToolCorrectnessMetric 不要求 Agent 必须用你预期的工具调用顺序,而是判断最终调用的工具集合是否满足任务需要。

构建最小可行 Eval 栈的路线图

Week 1:建立基础

  • 收集 50 条真实用户问题作为 golden dataset
  • 对每条手工标注期望输出
  • 安装 DeepEval,写 3 个核心测试用例
  • 本地跑通:deepeval test run tests/test_eval.py

Week 2-3:接入 CI

  • 配置 GitHub Actions workflow
  • 设置合理的失败阈值(建议从 0.65 开始,再调高)
  • 建立"冒烟集"(10-15 条)和"完整集"分层

Month 2:升级为平台

  • 引入 Langfuse(OSS 自托管)或 Braintrust(云端)
  • 开始追踪版本间指标变化
  • 对生产流量的 5% 做异步在线评分

Month 3-6:闭环

  • 用失败的生产案例扩充 golden dataset
  • 建立"eval 失败 → 修复 → 重新评估"的闭环流程
  • 对评分本身做校准(人工抽样对比 LLM judge 的准确率)

常见坑和反模式

坑1:一开始就建太大的 golden dataset

想着"以后用得着",花两周标注了 2000 条,然后发现 eval 每次跑 40 分钟,开发体验太差,直接放弃。从 50 条开始,够用就行。

坑2:只看平均分,不看分布

平均 0.82 可能掩盖了某个意图类别全部失败(0.3 分)被其他高分稀释的情况。分类别看指标,设置 per-category 阈值。

坑3:用同一个模型做应用和 judge

让 GPT-4o 评判自己的输出,它会给自己打高分。Judge 要么用更强的模型,要么用不同厂商的模型,减少自我偏好。

坑4:threshold 设太高,导致 CI 总是失败

工程师开始绕过 eval CI 或者直接把 threshold 改低。合理的起步 threshold 是 0.65-0.70,随着你对 judge 的校准越来越准再调高。

坑5:把 eval 当成唯一的质量信号

Eval 分数高不等于用户满意。Eval 是工程质量门控,不是产品指标。你的 golden dataset 是你能想到的场景,但用户的创造力总是超出你的预期。Eval 体系再完善,也要继续关注:用户侧的满意度评分、Human CSDN(人工审核抽样)、转化率和留存率等真实信号。

坑6:没有对 judge 本身做校准

LLM judge 不是万能的。建议每个月随机抽取 50-100 条 case,同时做 LLM judge 评分和人工评分,计算两者的 Spearman 相关系数。如果低于 0.70,说明你的评分标准(criteria prompt)需要优化,或者这个维度不适合 LLM-as-judge。

常见的 judge 失效场景:

  • 简短回答:judge 倾向于给简短回答打低分,即使简短本身就是正确的(如"不支持"这类 yes/no 回答)
  • 风格偏好:不同 judge model 对"专业语气"的定义不同,同一个回答 GPT-4o 打 0.8,Qwen-max 可能打 0.6
  • 行业术语:通用 judge 对特定行业术语(金融、医疗、法律)的准确性判断不如领域专家

解决方案:在 G-Eval 的 criteria 里加入具体的打分锚定示例(few-shot):

python 复制代码
time_accuracy_metric = GEval(
    name="TimeAccuracy",
    criteria="""
    判断"实际输出"中关于时间的描述是否与"检索上下文"中的信息一致。
    
    评分标准(1-5分):
    5分:时间信息完全准确,与上下文一致(如"3-5个工作日"对应上下文中的"3-5个工作日")
    4分:时间信息基本准确,有轻微表述差异但语义等价(如"约一周"对应"5-7个工作日")
    3分:时间信息模糊,没有明确给出时间范围
    2分:时间信息不准确,有明显偏差(如"1-2天"对应"3-5个工作日")
    1分:时间信息完全错误或与上下文矛盾
    """,
    evaluation_params=[
        LLMTestCaseParams.ACTUAL_OUTPUT,
        LLMTestCaseParams.RETRIEVAL_CONTEXT
    ],
    threshold=0.8
)

加入具体的评分锚点后,judge 的一致性通常能提高 15-20%。


总结

LLM 应用的测试体系比传统软件测试晚了至少两年。大多数团队现在还在靠人工检查和用户投诉发现问题------本质上,这是把质量控制外包给了用户,是对用户时间和信任的消耗。

本文介绍的三层 eval 体系,核心思想可以用一句话概括:把"不知道有没有变好"变成"能量化地知道变好了多少、变差了什么"

具体落地路径:

最小起步(1-2 天)

  1. 从历史日志里挑 50 条真实用户问题,手工标注期望输出
  2. 安装 DeepEval,写 AnswerRelevancy + Faithfulness 两个 metric
  3. 本地跑通,看哪些 case 在失败,理解失败原因
  4. (可选)写一个简单的 CSV 脚本存储结果,建立你的第一份基线

两周内完成

  1. 配置 GitHub Actions,把 eval 接入 PR 流程

  2. 设置合理的 fail threshold(建议从 0.65 开始)

  3. 跑一次"变更前 vs 变更后"的对比实验,感受回归追踪的价值

一个月目标

  1. 引入 Langfuse(自托管)或 Braintrust(云端),开始可视化版本间指标趋势

  2. 对 5% 的生产流量做异步在线评分

  3. 建立低分 case 的人工审核 → 加入 golden dataset 的循环

这套体系建好之后,你会发现一个有趣的副产品:对模型、prompt、检索策略的每一次改动,都有了可量化的依据。你不再需要靠直觉决定"这次改动到底值不值得上线",你可以直接看数据。

这就是从"直觉驱动的 AI 开发"到"数据驱动的 AI 开发"的核心跨越。

LLM observability 市场 2026 年已经达到 27 亿美元,到 2030 年预计超过 92 亿,36.2% 的年复合增长率在软件行业里几乎无可比拟。Gartner 预测到 2028 年,50% 的 GenAI 生产部署将包含 LLM 可观测性投入------从今天的 15% 到未来的 50%,这中间的距离就是还没踩过这个坑的团队。

你的 LLM 应用有 eval 吗?如果还没有,今天是开始的最好时机。


参考资料

  1. Braintrust Team. What is LLM evaluation? A practical guide to evals, metrics, and regression testing. Braintrust, May 16, 2026. https://www.braintrust.dev/articles/llm-evaluation-guide
  2. LLM Eval Tools Compared 2026 --- Langfuse, LangSmith, Braintrust, Arize, Humanloop, HoneyHive. benchmarkingagents.com, April 2026. https://benchmarkingagents.com/tools-compared/
  3. Braintrust Team. DeepEval alternatives (2026): Best tools for LLM evals, RAG, and agent testing. Braintrust, March 2, 2026. https://www.braintrust.dev/articles/deepeval-alternatives-2026
  4. Confident AI. Top 7 LLM Observability Tools in 2026. Confident AI, May 2026. https://www.confident-ai.com/knowledge-base/compare/top-7-llm-observability-tools
  5. DeepEval Documentation. Metrics & Test Cases. https://deepeval.com/docs
相关推荐
这是谁的博客?21 小时前
AI Agent 安全架构设计:漏洞分析与防护策略深度解析
人工智能·安全·网络安全·ai·agent·安全架构·架构设计
Black蜡笔小新1 天前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
黎阳之光1 天前
黎阳之光:以视频孪生重构智慧防火,打造“天空地人智”一体化森林防火新范式
大数据·运维·人工智能·物联网·安全
utf8mb4安全女神1 天前
Linux系统服务相关命令【定时任务设置】【任务进程管理】【防火墙区域应用】
linux·运维·服务器
凯丨1 天前
Claude Code 自动化开发的完整体系
运维·自动化
星辰AI1 天前
Transformers 架构核心原理:从注意力机制到 GPT
人工智能·ai·语言模型
yzx9910131 天前
超越向量检索:用 Graph RAG 构建具备推理能力的企业知识问答系统
人工智能·自动化
这是谁的博客?1 天前
AI Agent 架构设计与实现原理深度解析
人工智能·ai·langchain·agent·架构设计
星辰AI1 天前
LLM 安全与对齐技术:构建可信赖的人工智能
人工智能·ai·语言模型