Skip to content

LLM 应用评测与可观测

本文是 AI 应用系统学习系列的 L2 核心篇。前置:34. RAG 全链路:从文档到答案。 学完可以配合面试题食用:12. RAGAS & LLM-as-Judge 评测指标体系26. RAG 评估忠实度

为什么评测是"不能省"的环节

没有评测的 AI 应用改 prompt 等于蒙眼开枪。你改了一个词,输出可能变好也可能变差,但没有任何数据告诉你发生了什么。评测不是上线前的"收尾动作",而是 prompt 开发的测试驱动——你写一条 prompt 就该有一条对应的评测用例。

RAG 系统尤其复杂:检索召回差、生成不忠实、上下文被截断,三件事症状相似("回答不对"),但根因完全不同。没有分层评测,你永远在瞎猜。

评测集构建:20 条也能起步

很多人觉得评测要几千条数据才能开始,实际上 20 条精心设计的样本就能覆盖大部分回归场景。评测集分三类:

真实样本:从线上日志或人工标注里挑 10-15 条典型 query。比如 RAG 场景下用户最常问的那几个问题,附带标准答案。

边界样本:覆盖系统的能力边缘——超长 query(2000 字以上)、空输入、单关键词、多意图混合。这些是线上最容易出问题的地方。

对抗样本:故意"刁难"系统——包含否定词的 query("A 不是 B 说的那样")、需要多步推理的 query、含有不存在的实体名(测试幻觉倾向)。

三类加起来 20 条起步,50 条算及格,200 条以上可以走自动化回归。重点是每条都标注了期望答案,没有标准答案的评测集等于没有基线。

RAG 分层评测:检索与生成分开评

RAG 的"回答不对"只有两种可能:检索没回来,或者回来了但生成错了。不分层评测就是混在一起猜。

检索层指标

  • recall@k:前 k 个结果里有多少相关文档被召回。假设有 3 篇相关文档,k=5 时召回 2 篇,recall@5=2/3≈0.67。
  • MRR(Mean Reciprocal Rank):第一个相关结果的排名倒数。排在第一位得分 1,第二位 0.5,第三位 0.33。MRR 对"第一个结果是否相关"敏感,适合问答场景。
python
# 检索评测:recall@k 与 MRR 计算
def evaluate_retrieval(retrieved_docs, relevant_docs, k=5):
    recalled = sum(1 for d in retrieved_docs[:k] if d in relevant_docs)
    recall = recalled / len(relevant_docs) if relevant_docs else 0
    
    # MRR:第一个相关文档的排名倒数
    for rank, doc in enumerate(retrieved_docs, 1):
        if doc in relevant_docs:
            mrr = 1.0 / rank
            break
    else:
        mrr = 0.0
    
    return {"recall_at_" + str(k): recall, "mrr": mrr}

生成层指标

  • 忠实度(faithfulness):回答是否基于检索到的文档,有没有"编造"事实。Ragas 的 faithfulness 评测就是逐句检查:每个断言能否在上下文中找到支撑。
  • 相关性(answer_relevancy):回答是否回答了用户的问题。一个忠实但答非所问的回答(比如用户问"怎么配置",回答把文档重述了一遍)不会通过。
  • 有害性(harmlessness):输出是否包含敏感/歧视/危险内容。

两层指标不能混算。检索 recall 高但生成忠实度低,问题在 prompt 或模型;检索 recall 低,直接修检索策略。

自动化评测:规则打分 -> LLM-as-Judge -> 人工抽检

三条路,递进使用。

规则打分是最底层的保底。精确匹配、包含匹配、正则匹配。适合事实性判断("答案包含'128G'这个数字")。快,零成本,但只覆盖硬性指标。

LLM-as-Judge 是目前最通用的方案。用强模型(GPT-4/Claude)给弱模型的输出打分。评分 prompt 是关键:

python
# 忠实度评分 prompt 模板
FAITHFULNESS_PROMPT = """你是一个严格的评测助手。
给定一个<上下文>和一个<回答>,判断回答中的每个断言是否在上下文中能找到依据。

评分标准:
- 1分:所有断言都有上下文支持
- 0分:至少有一个断言无依据(编造)

回答格式:只输出一个数字,0 或 1。

<上下文>
{context}
</上下文>

<回答>
{answer}
</回答>

评分:"""

def llm_judge_faithfulness(question, context, answer, judge_model):
    """用 LLM 评测回答的忠实度"""
    prompt = FAITHFULNESS_PROMPT.format(context=context, answer=answer)
    response = judge_model.chat([{"role": "user", "content": prompt}])
    score = int(response.strip())
    return {"faithfulness": score, "reasoning": "LLM-as-Judge"}

LLM-as-Judge 最大的坑是评分偏差:强模型会给自己的输出更高分,偏好长回答,对格式敏感。解决办法是平衡评测集(混合正反例)和定期人工抽检校准。

人工抽检是最后的兜底。自动化评测跑完,抽 5-10% 的样本人工复核。发现评分偏差就调整评分 prompt 或评测集标签。

Ragas 实操:跑分与解读

Ragas 是一个开源的 RAG 评测框架,把上面说的指标封装成一行调用。安装和基础用法:

python
# pip install ragas
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_recall, context_precision
from datasets import Dataset

# 评测数据:30 条样本起步
samples = {
    "question": [  # 用户问题
        "Redis 的持久化方案有哪些?",
        "Raft 协议怎么选主?",
        "Kafka 怎么保证消息不丢失?",
        # ... 更多问题
    ],
    "answer": [  # 系统回答
        "Redis 支持 RDB 和 AOF 两种持久化方案。RDB 是定时快照...",
        "Raft 选主使用超时机制,Follower 在选举超时后转为 Candidate...",
        "Kafka 从生产者、Broker、消费者三个层面保证不丢失...",
        # ... 更多回答
    ],
    "contexts": [  # 检索到的上下文
        ["Redis 提供了 RDB 和 AOF 两种持久化方式..."],
        ["Raft 将节点分为 Leader、Follower、Candidate 三种角色..."],
        ["Kafka 的可靠性设计包含 acks 参数、副本机制和 ISR..."],
        # ... 更多上下文列表
    ]
}

dataset = Dataset.from_dict(samples)
result = evaluate(
    dataset,
    metrics=[faithfulness, answer_relevancy, context_recall, context_precision]
)

# 结果解读
print(result)
# 输出类似:
# {'faithfulness': 0.87, 'answer_relevancy': 0.92, 
#  'context_recall': 0.78, 'context_precision': 0.85}

解读的要点:

  • faithfulness < 0.7:生成层有问题,检查 prompt 约束或换模型。
  • context_recall < 0.6:检索层漏太多,调 chunk 大小、embedding 模型或加 rerank。
  • context_precision 高但 recall 低:检索到的都相关,但没找全,加多路检索或扩 top-k。
  • answer_relevancy 低但 faithfulness 高:回答忠实但答非所问,检查 prompt 的任务指令。

Ragas 对中文支持尚可,但 faithfulness 的逐句断言检查在大段中文输出上可能漏判。建议配合人工抽检。

线上可观测:全链路 trace

线下评测不能替代线上监控。线上指标和线下指标往往有差距:用户 query 分布、数据漂移、模型黑度变化都会导致效果衰减。

全链路 trace 是线上可观测的基石。每条请求记录以下信息:

请求ID -> [输入 prompt] -> [检索结果 top-5 + 得分] -> [生成回答] -> [最终输出]

                              token 用量、耗时、重试次数

每步都记录,出了问题可以通过 trace 精确归因是检索空、生成不忠实还是 prompt 写错。

灰度回归流程:改 prompt 或检索策略后,先切 5% 流量到新版本,跑 24 小时对比离线评测集分数 + 线上 trace 的关键指标(平均忠实度、首 token 时间、重试率)。两个版本差异超过阈值(比如忠实度下降 3%)就自动回滚。

常见误区与小结

  • 把评测集当 API 用例:评测集是"期望行为"的集合,不是功能测试用例。每条都要标注"为什么这么回答是对的",而不仅仅是"返回了 200"。
  • 只测检索不测生成:检索 recall 高不代表回答好——模型可能无视上下文自说自话。
  • LLM-as-Judge 用同一个模型:评测模型和生成模型用同一个,会有系统性偏好。至少用更强的模型来做 judge。
  • 线上指标对齐线下:线下 faithful 0.9 不等于线上 0.9。用户 query 分布和评测集分布不同,需要定期采集线上数据补充评测集。
  • Ragas 指标当绝对值:Ragas 分数是相对信号,不是绝对质量。同一个评测集跑两次分数稳定比分数本身更有价值。

小结:评测是可观测的基石。线下构建分层评测集(检索 vs 生成),用规则+LLM-as-Judge+人工三层递进评测;线上通过全链路 trace 监控效果衰减。下一篇(L3 实战)讲成本和延迟优化——评测告诉你"哪里不好",优化告诉你"怎么改省又稳"。

参考

参考:Ragas 官方文档 https://docs.ragas.io/ 、"Evaluating RAG Applications" by LangChain 博客、LLM-as-Judge "Judging LLM-as-a-Judge" 论文(MT-Bench 和相关工作)

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。
粤ICP备2026104257号-1