🧪 AI 评估 — LLM-as-Judge、Benchmark 与 A/B 测试

如何科学地评估你的 AI 系统?从传统指标到 LLM-as-Judge,从离线 Benchmark 到在线 A/B 实验——构建可信的评估流水线。

📑 目录

§1 为什么评估是 AI 系统的命脉

传统软件有单元测试、集成测试——输出是确定性的,assert add(2,3) == 5 永远通过。但 AI 系统的输出是概率性的、开放式的:"帮我写一封道歉邮件"没有唯一正确答案。

这导致三个核心问题:

🚫 无法用传统测试覆盖

同样的输入,不同模型、不同 prompt、不同温度,输出千差万别。你不能用 assertEquals 来验证一封邮件的"礼貌程度"。

🔄 迭代无信心

改了 prompt 或换了模型,你怎么知道变好了还是变差了?没有评估,每次改动都是盲飞。团队里就会出现"我觉得好一点了"的主观争论。

💰 成本失控

GPT-4 比 GPT-4o-mini 贵 15 倍。如果你的应用 90% 的场景用便宜模型就够了,但你不评估,你就只敢用最贵的——因为"至少不会太差"。

核心洞察:评估不是为了"打分",而是为了建立对系统的信心,从而安全地迭代、优化成本、提升质量。没有评估的 AI 系统,就像没有测试的代码——能跑,但你不敢改。

§2 评估全景图:离线 vs 在线

┌─────────────────────────────────────────────────────────────────┐ │ AI 评估全景图 │ ├─────────────────────────────┬───────────────────────────────────┤ │ 离线评估 (Offline) │ 在线评估 (Online) │ │ ┌───────────────────────┐ │ ┌───────────────────────────┐ │ │ │ 📊 传统指标 │ │ │ 🧪 A/B 测试 │ │ │ │ BLEU / ROUGE / │ │ │ 随机分流 → 对比指标 │ │ │ │ BERTScore / METEOR │ │ │ 统计显著性检验 │ │ │ ├───────────────────────┤ │ ├───────────────────────────┤ │ │ │ 🤖 LLM-as-Judge │ │ │ 👤 用户反馈 │ │ │ │ Pairwise / Pointwise │ │ │ 👍👎 / 评分 / 纠错 │ │ │ │ 多维度打分 │ │ │ 隐式行为信号 │ │ │ ├───────────────────────┤ │ ├───────────────────────────┤ │ │ │ 📋 Benchmark │ │ │ 📈 生产监控 │ │ │ │ MMLU / HumanEval / │ │ │ 延迟 / 成本 / 错误率 │ │ │ │ SWE-bench / MT-Bench │ │ │ 回退率 / 用户留存 │ │ │ ├───────────────────────┤ │ └───────────────────────────┘ │ │ │ 🎯 任务专项评估 │ │ │ │ │ RAG: RAGAS │ │ │ │ │ Agent: Task Success │ │ │ │ │ Code: Pass@k │ │ │ │ └───────────────────────┘ │ │ └─────────────────────────────┴───────────────────────────────────┘
维度离线评估在线评估
数据来源静态测试集 / Golden Dataset真实用户流量
速度快(分钟级)慢(需积累样本)
成本LLM 调用费 / 人工标注费机会成本(A/B 流量浪费)
覆盖度取决于测试集质量自然分布的长尾场景
适用阶段开发迭代 / 模型选型上线验证 / 持续优化
核心风险与真实场景脱节(分布偏移)需要流量 + 统计周期
最佳实践:离线评估做快速迭代(改 prompt → 跑评估 → 看分数),在线评估做上线前把关。两者互补,缺一不可。

§3 传统指标:BLEU / ROUGE / BERTScore

在 LLM 时代之前,NLP 评估依赖参考答案对比——把模型输出和人工标注的"标准答案"比较。这些指标至今仍有价值,特别是有明确 ground truth 的场景。

BLEU (Bilingual Evaluation Understudy)

衡量生成文本与参考文本的 n-gram 重叠度。最初为机器翻译设计。

BLEU 计算原理

计算 1-gram 到 4-gram 的精确率,取几何平均,乘以长度惩罚(防止短文本作弊):

BLEU = BP × exp(Σ wn × log(pn))

# pn = n-gram 精确率
# wn = 权重(通常各 0.25)
# BP = brevity penalty = min(1, exp(1 - ref_len/gen_len))

✅ 适合

• 机器翻译
• 代码生成(精确匹配)
• 有标准答案的抽取式摘要
• 计算极快、可复现

❌ 不适合

• 开放式生成(同义替换得低分)
• 对词序敏感但语义不敏感
• 只看精确匹配,忽略语义等价
• 参考答案依赖——少参考则不准

ROUGE (Recall-Oriented Understudy for Gisting Evaluation)

与 BLEU 侧重精确率不同,ROUGE 侧重召回率——参考答案中的内容有多少被生成文本覆盖。专为文本摘要设计。

变体衡量什么典型用途
ROUGE-1单字重叠召回率基础摘要质量
ROUGE-2二元组重叠召回率流畅性评估
ROUGE-L最长公共子序列兼顾词序的摘要质量
ROUGE-S跳跃二元组允许非连续匹配

BERTScore

用预训练模型(如 BERT)提取句向量,计算语义相似度而非表面 n-gram 匹配。解决了"意思一样但用词不同"的问题。

BERTScore vs BLEU/ROUGE
# BLEU/ROUGE: 表面匹配
参考: "这部电影非常精彩"
生成: "此片十分出色"  → BLEU ≈ 0.0 (无 n-gram 重叠)

# BERTScore: 语义匹配
参考: "这部电影非常精彩"
生成: "此片十分出色"  → BERTScore ≈ 0.92 (语义高度相似)

其他传统指标

METEOR

• 考虑同义词 + 词干
• 比 BLEU 更贴近人工判断

• 需要外部同义词库

Perplexity

• 模型内在质量指标
• 无需参考答案

• 只衡量语言模型自信度
• 不等于输出质量

Exact Match (EM)

• 最简单最严格
• 适合 QA / 代码

• 过于严格,忽略合理变体

F1 Score

• 精确率 + 召回率平衡
• QA 常用

• 仍基于 token 重叠

传统指标的致命缺陷:它们评估的是"输出像不像参考答案",而不是"输出好不好"。对于开放式生成任务(对话、创意写作、工具调用),参考答案本身就不存在——你需要 LLM-as-Judge。

§4 LLM-as-Judge:核心范式

用更强的 LLM(如 GPT-4、Claude)来评估另一个 LLM 的输出质量。这是当前 AI 评估最主流的方法——没有之一。

为什么 LLM-as-Judge 有效?

三种评判模式

1️⃣ Pointwise 评分

逐个打分:给每个输出一个分数

Prompt: "请给以下回答打 1-5 分,
评估其准确性和完整性。

问题: {question}
回答: {answer}

评分标准:
5 = 完全正确且全面
3 = 部分正确但有遗漏
1 = 完全错误"

✅ 简单、可并行、绝对分数

❌ 分数可能漂移、难以校准

2️⃣ Pairwise 比较

两两对比:哪个更好?

Prompt: "请比较以下两个回答,
哪个更好地回答了问题?

问题: {question}
回答A: {answer_a}
回答B: {answer_b}

输出: A/B/Tie + 理由"

✅ 更稳定、人类直觉匹配

❌ O(n²) 比较、无法绝对定位

3️⃣ Reference-based 评分(参照评估)

有标准答案时的 LLM 评判——结合了传统指标的"有参考"优势和 LLM 的"语义理解"优势。

Prompt: "请对比以下回答与参考答案,评估其准确性。

问题: {question}
参考答案: {reference}
模型回答: {answer}

评估维度:
1. 事实准确性 (1-5): 是否与参考一致?
2. 完整性 (1-5): 是否覆盖参考的所有要点?
3. 额外信息 (1-5): 是否添加了有价值的信息?"

多维度评估设计

一个优秀的 LLM Judge prompt 应该评估多个正交维度,而非给一个笼统分数:

┌──────────────────────────────────────────────────────────────┐ │ LLM-as-Judge 评估维度 │ ├────────────────┬────────────────┬────────────────────────────┤ │ 核心质量维度 │ 安全维度 │ 用户体验维度 │ ├────────────────┼────────────────┼────────────────────────────┤ │ 📏 准确性 │ 🛡️ 有害性 │ 🎯 相关性 │ │ 事实是否正确? │ 是否包含有害 │ 是否回答了用户 │ │ │ 内容? │ 的问题? │ ├────────────────┼────────────────┼────────────────────────────┤ │ 📦 完整性 │ 🔒 隐私泄露 │ 💬 清晰度 │ │ 是否全面覆盖? │ 是否暴露 PII? │ 是否易于理解? │ ├────────────────┼────────────────┼────────────────────────────┤ │ 🔗 一致性 │ 🎭 偏见 │ 📐 结构性 │ │ 内部逻辑自洽? │ 是否有歧视性 │ 是否有良好的格式 │ │ │ 内容? │ 和组织? │ ├────────────────┼────────────────┼────────────────────────────┤ │ 💡 创造性 │ 📋 指令遵循 │ │ │ 是否有新见解? │ 是否遵守约束 │ │ │ │ 和规则? │ │ └────────────────┴────────────────┴────────────────────────────┘

Judge Prompt 设计的 7 条铁律

  1. 评分标准要具体:不说"好不好",而说"事实错误数 0=5 分,1-2=3 分,3+=1 分"
  2. 输出格式要结构化:要求 JSON 输出而非自由文本,方便自动解析
  3. Cot 强制:要求先写理由再给分数,显著提升一致性
  4. 位置随机化:Pairwise 比较时随机交换 A/B 顺序,消除位置偏差
  5. 多 Judge 投票:用 3-5 次 GPT-4 调用取多数,比单次更可靠
  6. 用强模型评弱模型:GPT-4 评 GPT-3.5 可以,GPT-3.5 评 GPT-4 不行
  7. 定期人工校准:每 200-500 条抽查 20-50 条与人工标注对齐
📋 标准 Judge Prompt 模板
{
  "system": "你是一个专业的 AI 输出质量评估员。你必须严格按照评分标准评估,先写出评估理由,再给出分数。",

  "user": """请评估以下 AI 回答的质量。

## 问题
{question}

## AI 回答
{answer}

## 评估标准

### 1. 准确性 (accuracy): 1-5
- 5: 所有事实陈述正确,无幻觉
- 4: 主要事实正确,轻微不精确
- 3: 有 1-2 个事实错误或未经验证的声称
- 2: 多个事实错误
- 1: 严重幻觉或捏造

### 2. 完整性 (completeness): 1-5
- 5: 全面覆盖问题的所有方面
- 3: 覆盖了主要方面但遗漏了重要的细节
- 1: 只回答了问题的一小部分

### 3. 指令遵循 (instruction_following): 1-5
- 5: 完全遵守所有格式、长度、风格要求
- 3: 大致遵守但有偏差
- 1: 忽视了明确的指令

## 输出格式(JSON)
```json
{
  "accuracy": {score},
  "completeness": {score},
  "instruction_following": {score},
  "reasoning": "你的评估理由...",
  "overall": {weighted_score}
}
```"""
}

LLM-as-Judge 的偏差与缓解

偏差类型表现缓解方案
📍 位置偏差Pairwise 时偏好排在前面的随机化 A/B 顺序,取两次结果的平均
📏 长度偏差偏好更长的回答评分标准中明确"简洁性加分"或加入长度惩罚
🤖 自我偏好GPT-4 倾向给 GPT-4 更高分匿名化模型来源,使用交叉评判
🎨 格式偏差偏好有格式(列表、粗体)的回答评估"去格式后的内容质量"
🔄 一致性偏差同一输入多次评判结果不同多次采样取平均/投票 + temperature=0
🎯 Verbosity Bias啰嗦的答案得分更高加入"信息密度"维度
⚠️ LLM-as-Judge 的局限:Judge 本身也是 LLM,它会犯同样的错——幻觉、偏见、不一致。永远不要让 Judge 成为唯一的评估手段,必须与人工抽查和其他指标结合。LLM Judge 的可靠性约等于"一个中等水平的标注者",不是金标准。

§5 Benchmark 基准测试

Benchmark 是标准化的考试——固定的题目、固定的评分规则、公开的排行榜。适合模型选型和横向对比,但不适合评估你特定应用的质量。

通用 Benchmark

Benchmark测试什么题目数可靠性
MMLU多领域知识(57 学科)~15K⚠ 数据泄露风险
MMLU-ProMMLU 升级版,更难更少噪声~14K✅ 更可靠
GPQA专家级推理(PhD 级)~500✅ 高区分度
HumanEval代码生成(Python 函数补全)164⚡ 规模小
SWE-bench真实 GitHub Issue 修复~2.2K✅ 最接近真实
MT-Bench多轮对话质量80 题 × 2 轮⚠ LLM-as-Judge
AlpacaEval指令遵循质量~800⚠ LLM-as-Judge
MATH数学竞赛级推理~12K✅ 有验证集
GSM8K小学数学应用题~8.5K⚡ 对强模型太简单
IFEval指令遵循(格式/长度等)~540✅ 规则化评估

Agent 专项 Benchmark

SWE-bench Verified

真实 GitHub 仓库的真实 Issue + PR,要求 Agent 定位 bug → 生成 patch → 通过测试。

✅ 最接近真实开发
✅ 有确定性测试

❌ 评估成本高(需沙箱执行)
❌ 环境配置复杂

WebArena

模拟真实网站交互——搜索、购物、论坛发帖。Agent 需操作浏览器完成任务。

✅ 评估端到端能力
✅ 真实 Web 环境

❌ 环境维护成本高
❌ 不确定性较大

GAIA

通用 AI 助手评估——需要工具调用、多步推理、信息整合。

✅ 评估综合能力
✅ 题目精心设计

❌ 规模较小 (~400)
❌ 部分需人工验证

BirdBench

跨数据库 Text-to-SQL,真实业务数据库 + 自然语言查询。

✅ 评估数据库理解
✅ 结果可精确验证

❌ SQL 方言差异
❌ 部分查询歧义

Benchmark 的使用原则

🎯 正确使用姿势
Benchmark 悖论:当所有人都在同一个 Benchmark 上优化时,Benchmark 就不再是好的衡量标准了(Goodhart 法则)。MMLU 已经出现了明显的"刷榜"现象——在 MMLU 上 90% 的模型,在你的真实任务上可能只有 60%。永远以自己的评估集为主,Benchmark 为辅。

§6 RAG 评估:RAGAS 与深度指标

RAG 系统的评估与一般 LLM 评估不同——你需要评估的不只是生成质量,还有检索质量和两者的结合质量

┌───────────────────────────────────────────────────────────────────┐ │ RAG 评估金字塔 │ │ │ │ ╱╲ │ │ ╱ ╲ │ │ ╱ 生成 ╲ ┌─ 答案相关性 │ │ ╱ 质量 ╲ │ 忠实度 (Faithfulness) │ │ ╱──────────────╲ │ 无幻觉率 │ │ ╱ ╲ │ │ │ ╱ 检索-生成 ╲ │ │ │ ╱ 结合质量 ╲ │ │ │ ╱──────────────────────╲ │ │ │ ╱ ╲ │ │ │ ╱ 检索质量 ╲│ │ │ ╱─────────────────────────────╲ │ │ ╱ 上下文精确率 上下文召回率 ╲ │ │ ╱──────────────────────────────────╲ │ │ ╱ 组件级评估 ╲ │ │ ╱ Embedding 质量 / Chunking 策略 / Reranker ╲ │ │ ╱────────────────────────────────────────────────╲ │

RAGAS 框架

RAGAS (Retrieval Augmented Generation Assessment) 是最流行的 RAG 评估框架,提供了一套完整的指标体系:

指标评估什么需要什么输入计算方式
Context Precision 检索到的上下文中有多少是相关的 question + contexts + reference 对每个 context 用 LLM 判断是否相关,计算 precision@k
Context Recall 回答问题所需的信息是否都被检索到了 question + contexts + reference 将 reference 中的每个 claim 与 contexts 匹配
Faithfulness 生成答案是否忠实于检索上下文(不幻觉) question + contexts + answer 将答案拆成 claims,逐一检查是否有 context 支持
Answer Relevance 答案是否真正回答了问题 question + answer 从答案反推问题,与原问题比相似度
🔧 RAGAS 使用示例
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)
from datasets import Dataset

# 准备评估数据
data = {
    "question": ["什么是向量数据库?", "RAG 的优势是什么?"],
    "answer": ["向量数据库是专门存储和检索向量嵌入的数据库...", "RAG 可以减少幻觉、提供可追溯来源..."],
    "contexts": [
        ["向量数据库如 Pinecone 和 Weaviate 专门为高维向量优化..."],
        ["RAG 通过检索相关文档来增强生成,降低幻觉率..."],
    ],
    "ground_truth": ["向量数据库是存储向量嵌入的专用数据库,支持相似性搜索", "RAG 结合检索和生成,减少幻觉并提供引用"],
}

dataset = Dataset.from_dict(data)

# 运行评估
result = evaluate(
    dataset=dataset,
    metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
    llm=your_llm,          # 用于评估的 LLM
    embeddings=your_embeds, # 用于 answer_relevancy
)

print(result)
# {'faithfulness': 0.85, 'answer_relevancy': 0.92, 
#  'context_precision': 0.78, 'context_recall': 0.70}

RAG 评估的深层指标

除了 RAGAS 的四大指标,实践中还需要关注:

🔍 检索层指标
  • Hit Rate: 查询的相关文档是否出现在 Top-K 中
  • MRR: 相关文档的排名倒数均值
  • nDCG: 考虑位置的检索质量
  • Embedding 漂移: Embedding 模型更新后检索质量变化
  • Chunk 边界损失: 关键信息是否被切在 chunk 边界
🧠 生成层指标
  • 幻觉率: 答案中无 context 支持的 claim 占比
  • 引用准确率: 引用标注是否对应真实来源
  • 信息冗余: 答案中重复信息的比例
  • 拒绝率: 模型在应该拒绝时是否拒绝
  • 一致性: 同一问题不同表述的答案是否一致
与 RAG 模块的链接:RAG 评估直接反映了 RAG 架构中每个组件的质量。Context Precision 低 → 检索或 Reranker 有问题;Faithfulness 低 → 生成模型不听 context;Context Recall 低 → 向量库或 Chunking 策略要优化。

§7 Agent 评估:任务完成率与轨迹分析

Agent 评估是最复杂的一类——Agent 不只是生成文本,它还要行动(调用工具、操作环境),评估要覆盖"做了什么"和"做得怎么样"两个层面。

Agent 评估的四个层次

┌─────────────────────────────────────────────────────────────────┐ │ Agent 评估四层模型 │ │ │ │ Layer 4: 🎯 业务价值 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 用户满意度 / 任务完成效率 / 成本节约 │ │ │ └─────────────────────────────────────────────────────────┘ │ │ Layer 3: ✅ 任务结果 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 最终输出是否正确?测试是否通过?用户目标是否达成? │ │ │ └─────────────────────────────────────────────────────────┘ │ │ Layer 2: 🔧 执行过程 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 工具调用是否合理?是否走了弯路?错误恢复能力? │ │ │ └─────────────────────────────────────────────────────────┘ │ │ Layer 1: 🧠 推理质量 │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 思考链是否合理?是否理解了任务?是否有逻辑错误? │ │ │ └─────────────────────────────────────────────────────────┘ │

核心指标

指标定义计算方式
Task Success Rate任务完成率成功任务数 / 总任务数
Partial Success部分完成率按完成度加权(如 5 个子目标完成 3 个 = 60%)
Step Efficiency步骤效率最少必要步数 / 实际步数(越接近 1 越好)
Tool Accuracy工具调用准确率正确调用次数 / 总调用次数
Error Recovery Rate错误恢复率从错误中恢复的次数 / 遇到错误的次数
Token EfficiencyToken 效率任务完成率 / 总 Token 消耗
Time to Complete完成时间从开始到任务完成的耗时

轨迹分析 (Trajectory Analysis)

不只看结果,还要看过程——Agent 的每一步思考、每一个工具调用、每一次回退,都是评估的素材。

📊 轨迹分析示例
# 理想轨迹 (4 步完成)
用户: "查一下北京明天的天气并发邮件给 alice@example.com"
1. 💭 思考: 需要先查天气,再发邮件
2. 🔧 调用: get_weather(city="北京", date="明天") → 25°C 晴
3. 🔧 调用: send_email(to="alice@example.com", subject="北京天气", body="...")
4. ✅ 完成

# 低效轨迹 (7 步,2 次回退)
用户: "查一下北京明天的天气并发邮件给 alice@example.com"
1. 💭 思考: 我要发邮件
2. 🔧 调用: send_email(to="alice@example.com", ...)  ← ❌ 还没查天气!
3. 💭 思考: 我需要天气信息
4. 🔧 调用: get_weather(city="Beijing")  ← ❌ 拼写错误
5. 💭 思考: 中文城市名
6. 🔧 调用: get_weather(city="北京") → 25°C 晴
7. 🔧 调用: send_email(...) ← 重新发

# 轨迹评分
理想轨迹: Step Efficiency = 4/4 = 1.0, Tool Accuracy = 2/2 = 100%
低效轨迹: Step Efficiency = 4/7 = 0.57, Tool Accuracy = 2/4 = 50%

Agent 评估的实践框架

🏗️ 构建 Agent 评估集
class AgentEvalCase:
    """单个评估用例"""
    task: str                    # 用户任务描述
    environment: dict            # 初始环境状态(文件、数据库、API mock)
    expected_outcome: str        # 期望结果描述
    success_criteria: Callable   # 验证函数(检查文件内容、API 调用等)
    max_steps: int               # 最大允许步数
    timeout_seconds: int         # 超时限制

# 示例:代码修复 Agent 评估
case = AgentEvalCase(
    task="修复 utils.py 中的除零错误",
    environment={"files": {"utils.py": "def divide(a, b): return a / b"}},
    expected_outcome="添加 b == 0 的检查并返回 None 或抛出异常",
    success_criteria=lambda env: (
        "b ==" in env["files"]["utils.py"] or 
        "b ==" in env["files"]["utils.py"]
    ) and "ZeroDivisionError" not in env.get("test_output", ""),
    max_steps=10,
    timeout_seconds=120,
)

# 运行评估
results = []
for case in eval_set:
    trajectory = agent.run(case.task, env=case.environment)
    success = case.success_criteria(trajectory.final_state)
    efficiency = case.max_steps / len(trajectory.steps)
    results.append({
        "task": case.task,
        "success": success,
        "steps": len(trajectory.steps),
        "efficiency": efficiency,
        "tool_calls": [s for s in trajectory.steps if s.type == "tool"],
        "errors": [s for s in trajectory.steps if s.type == "error"],
    })
与 Agent 研究的链接:我们的 Agent 研究发现,SWE-agent 的 RetryAgent+Reviewer 是唯一的多尝试+质量评估机制(详见 SWE-agent 深度分析),OpenHands 的 Critic 迭代精化 也是自我评估的范例(详见 OpenHands 深度分析)。这些系统的"自我评估"思路可以迁移到评估框架设计中。

§8 在线 A/B 测试

离线评估告诉你"模型 A 在测试集上比模型 B 好 5%",但 A/B 测试告诉你"用模型 A 替换模型 B,用户满意度提升了 12%"。后者才是产品决策的依据。

AI 系统的 A/B 测试 vs 传统 A/B 测试

维度传统 A/BAI A/B
变量UI / 文案 / 流程Prompt / 模型 / 参数 / RAG 配置
指标点击率 / 转化率满意度 / 任务成功率 / 幻觉率
方差较低(确定性输出)较高(同一输入不同输出)
样本量较小更大(需要抵消随机性)
成本流量损失流量 + API 调用成本差异
冷启动几小时见效可能需要几天(需积累足够成功/失败样本)

AI A/B 测试的实验设计

🔬 标准实验流程
# 1. 定义假设
"Hypothesis: 使用 GPT-4o 替代 GPT-4,在保持质量不变的前提下,
成本降低 60%,延迟减少 40%"

# 2. 选择指标
primary_metric = "user_satisfaction"    # 主要:用户满意度
guardrail_metrics = [
    "hallucination_rate",               # 护栏:幻觉率不恶化
    "task_success_rate",                # 护栏:任务完成率不下降
    "p95_latency",                      # 护rail:延迟不恶化
]

# 3. 计算样本量
# AI 系统方差大 → 需要更大样本
# 经验法则:至少 1000 次交互/组
# 如果满意度提升 5% → ~2000/组 (α=0.05, β=0.2)

# 4. 分流策略
# ⚠️ 关键:同一个用户的对话必须始终在同一组
# 否则用户会感到体验不一致(忽好忽坏)
split_strategy = "user_id_hash"  # 按用户 ID 哈希分流

# 5. 运行周期
min_days = 7  # 至少一周,覆盖工作日+周末
max_days = 21 # 最长三周,避免历史效应

用户反馈收集

在线评估的核心信号来源:

👍👎 显式反馈

直接问用户"这个回答有帮助吗?"

✅ 信号明确
✅ 容易量化

❌ 回收率低(1-5%)
❌ 负面偏差(不满才点)

📝 纠错反馈

允许用户编辑/修正 AI 输出

✅ 高质量信号
✅ 同时获得正确答案

❌ 只有部分场景适用
❌ 编辑原因不明确

👀 隐式行为信号

复制率、阅读时长、继续追问、放弃率

✅ 100% 覆盖
✅ 无干扰

❌ 信号噪声大
❌ 需要建模解读

🔄 对话级信号

是否一次解决?是否多次重试?是否换话题?

✅ 反映整体体验
✅ 自动收集

❌ 因果关系难判断
❌ 对话意图多样性

统计显著性

📈 AI 系统的显著性检验
import scipy.stats as stats
import numpy as np

# AI 系统的特殊考虑:
# 1. 同一用户多次交互不独立 → 用用户级聚合
# 2. 输出随机性 → 需要更多样本
# 3. 多个指标同时看 → 需要多重检验校正

def ab_test_significance(control_scores, treatment_scores, alpha=0.05):
    """
    AI 系统的 A/B 显著性检验
    control_scores: 对照组满意度列表 (per-user 平均)
    treatment_scores: 实验组满意度列表
    """
    # Welch's t-test (不假设等方差)
    t_stat, p_value = stats.ttest_ind(
        control_scores, treatment_scores, 
        equal_var=False
    )
    
    # 效应量 (Cohen's d)
    pooled_std = np.sqrt(
        (np.var(control_scores) + np.var(treatment_scores)) / 2
    )
    cohens_d = (np.mean(treatment_scores) - np.mean(control_scores)) / pooled_std
    
    # 置信区间
    diff = np.mean(treatment_scores) - np.mean(control_scores)
    se = np.sqrt(np.var(control_scores)/len(control_scores) + 
                 np.var(treatment_scores)/len(treatment_scores))
    ci = (diff - 1.96*se, diff + 1.96*se)
    
    return {
        "significant": p_value < alpha,
        "p_value": p_value,
        "effect_size": cohens_d,
        "confidence_interval": ci,
        "recommendation": "Ship" if (p_value < alpha and cohens_d > 0.2) else "Hold"
    }

# 多重检验校正 (Bonferroni)
def bonferroni_correction(p_values, alpha=0.05):
    """当同时看 N 个指标时,提高显著性阈值"""
    n_tests = len(p_values)
    adjusted_alpha = alpha / n_tests
    return [p < adjusted_alpha for p in p_values]

§9 评估流水线设计

评估不是一次性的活动,而是持续运行的流水线——每次改动都自动评估,结果可追溯、可比较。

┌─────────────────────────────────────────────────────────────────────┐ │ 评估流水线架构 │ │ │ │ ┌──────────┐ ┌──────────────┐ ┌─────────────┐ ┌────────┐ │ │ │ 触发器 │───→│ 评估集加载 │───→│ 运行评估 │───→│ 结果 │ │ │ │ Git Push │ │ Golden Set │ │ │ │ 聚合 │ │ │ │ PR Merge │ │ + 在线采样 │ │ 传统指标 │ │ │ │ │ │ Cron │ │ │ │ LLM Judge │ │ 对比 │ │ │ │ 手动 │ │ 数据增强 │ │ Benchmark │ │ 历史 │ │ │ └──────────┘ └──────────────┘ │ Agent Eval │ │ │ │ │ └─────────────┘ │ 告警 │ │ │ │ 回归! │ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ │ │ 人工抽查 │───→│ 标注校准 │──────────────────────→│ 更新 │ │ │ │ 50 条/周 │ │ Judge-人比对 │ │ 权重 │ │ │ └──────────┘ └──────────────┘ └────────┘ │ └─────────────────────────────────────────────────────────────────────┘

评估集 (Eval Set) 的构建

📋 评估集设计原则
🔄 从生产日志构建评估集
import random
from datetime import datetime, timedelta

def build_eval_set_from_logs(production_logs, target_size=200):
    """
    从生产日志中采样构建评估集
    """
    # 1. 按意图分类
    intent_counts = {}
    for log in production_logs:
        intent = classify_intent(log["user_query"])
        intent_counts[intent] = intent_counts.get(intent, 0) + 1
    
    # 2. 分层采样
    eval_set = []
    for intent, count in intent_counts.items():
        proportion = count / len(production_logs)
        n_samples = max(5, int(target_size * proportion))  # 每个意图至少 5 条
        intent_logs = [l for l in production_logs if classify_intent(l["user_query"]) == intent]
        eval_set.extend(random.sample(intent_logs, min(n_samples, len(intent_logs))))
    
    # 3. 补充边界 case
    edge_cases = [
        l for l in production_logs
        if l.get("user_feedback") == "negative"  # 用户不满意的
        or len(l.get("model_output", "")) < 20    # 太短的
        or "error" in l.get("model_output", "").lower()  # 出错的
    ]
    eval_set.extend(random.sample(edge_cases, min(20, len(edge_cases))))
    
    # 4. 去重
    seen = set()
    unique = []
    for item in eval_set:
        key = item["user_query"][:100]
        if key not in seen:
            seen.add(key)
            unique.append(item)
    
    return unique[:target_size]

CI/CD 集成

🚀 Prompt 变更的自动评估
# .github/workflows/eval.yml
name: AI Evaluation

on:
  pull_request:
    paths:
      - 'prompts/**'
      - 'config/model*.yaml'

jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run eval suite
        run: |
          python scripts/run_eval.py \
            --eval-set data/eval-set-v3.jsonl \
            --config config/production.yaml \
            --compare main \
            --metrics accuracy,faithfulness,relevance \
            --judge-model gpt-4o \
            --output results/pr-${{ github.event.number }}.json
      
      - name: Check for regression
        run: |
          python scripts/check_regression.py \
            --current results/pr-${{ github.event.number }}.json \
            --baseline results/main-latest.json \
            --threshold -0.05 \
            --fail-on-regression
      
      - name: Comment on PR
        uses: actions/github-script@v7
        with:
          script: |
            const results = require('./results/pr-${{ github.event.number }}.json');
            github.rest.issues.createComment({
              ...context.repo,
              issue_number: context.issue.number,
              body: `## 📊 Eval Results\n${formatResults(results)}`
            })

§10 评估工具生态

RAGAS

RAG 专用

RAG 评估的事实标准。四大核心指标 + 自定义指标。与 LangChain 集成良好。

✅ 专注 RAG、指标设计合理
✅ 活跃社区、文档完善

❌ LLM-as-Judge 依赖强模型
❌ 运行成本较高

LangSmith / LangFuse

可观测性+评估

不只评估,还提供 tracing、prompt 管理、A/B 测试。LangSmith 商业,LangFuse 开源。

✅ 评估 + 监控一体化
✅ 可视化追踪
✅ 生产级功能

❌ LangSmith 闭源/付费
❌ 评估功能不如专用工具深

Promptfoo

Prompt 评估

专注 prompt 对比评估——同一测试集,不同 prompt,自动对比结果。

✅ CLI 友好、快速上手
✅ 多模型并行评估
✅ 支持自定义断言

❌ 不支持 Agent 轨迹评估
❌ 可视化较弱

DeepEval

全栈评估

类似 pytest 的评估框架,支持幻觉检测、偏见、毒性等综合指标。

✅ 测试风格 API
✅ 内置丰富指标
✅ 与 CI 集成

❌ 社区较新
❌ 某些指标稳定性不足

OpenAI Evals

官方方案

OpenAI 提供的评估框架,与 API 深度集成。适合纯 OpenAI 生态。

✅ 官方维护
✅ 与 API 集成好

❌ 绑定 OpenAI 生态
❌ 功能相对简单

AutoEval / TruLens

RAG+LLM 评估

TruLens 专注 LLM app 质量评估,提供"Groundedness"等核心指标。

✅ 可视化 dashboard
✅ 与 LangChain 集成

❌ 开源版功能受限
❌ 指标不如 RAGAS 精细

工具选型决策

场景推荐工具理由
RAG 系统评估RAGAS最成熟、指标最精确
Prompt 迭代Promptfoo快速对比、CLI 友好
生产监控+评估LangFuse (开源)tracing + 评估一体化
CI/CD 自动评估DeepEvalpytest 风格、CI 友好
全栈 AI 应用RAGAS + LangFuse离线评估 + 在线监控
快速原型验证自建脚本 + GPT-4 Judge最灵活、无依赖

§11 反模式与常见坑

🚫 反模式 1:只用 BLEU/ROUGE

用传统指标评估开放式生成任务。你的客服机器人回答"很抱歉给您带来不便"和"抱歉造成了困扰",BLEU 给 0 分,但语义完全等价。

正确做法:开放式任务用 LLM-as-Judge,有 ground truth 的任务才用传统指标。

🚫 反模式 2:盲目信任 LLM Judge

设了一个 Judge,跑了 1000 条,发现准确率 95%,就直接上线了。但你没检查——Judge 本身就有 ~10% 的错误率,而且对你的特定 domain 可能更差。

正确做法:Judge 必须与人工标注做校准(至少 50 条),计算 Cohen's Kappa ≥ 0.6 才可用。

🚫 反模式 3:评估集一成不变

半年前建的评估集,到现在还在用。但你的用户 query 分布已经变了——新功能上线后出现了全新的问题类型。

正确做法:每月从生产日志中采样补充评估集,保持与真实分布对齐。

🚫 反模式 4:只看分数不看 case

准确率从 85% 降到 82%,你只看数字觉得"差不多"。但仔细看 case 发现,降分全是高价值用户的关键场景。

正确做法:分数回归时必须做 case study——看变差的具体 case,判断影响范围和严重程度。

🚫 反模式 5:A/B 测试样本不足

跑了 2 天 A/B 就做决策。但 AI 系统方差大,200 条样本根本不够得出显著结论。

正确做法:先算所需样本量(通常 1000-5000 次/组),跑到足够才做决策。宁可多跑几天,不要误判。

🚫 反模式 6:忽略成本效率

只评估质量,不看成本。GPT-4 比 GPT-4o 质量高 5%,但贵 15 倍。如果你的场景 95% 的 case 用 GPT-4o 就够了,那你浪费了 93% 的成本。

正确做法:评估时加入"成本效率"维度——质量 / 成本。引入路由策略:简单 case 用便宜模型,困难 case 用贵模型(详见 LLM 集成)。

§12 决策树:选哪种评估方式

你要评估什么? │ ┌─────────────┼─────────────┐ │ │ │ 有标准答案? 开放式生成? Agent 行为? │ │ │ ┌─────┴─────┐ │ ┌────┴────┐ │ │ │ │ │ 精确匹配 语义相似 │ 任务结果 轨迹分析 (代码/QA) (摘要/翻译) │ 成功率 步骤效率 │ │ │ │ │ EM/F1 BERTScore │ SWE-bench 自定义 Pass@k METEOR │ WebArena 评估集 │ │ │ │ │ └─────┬─────┘ │ └────┬────┘ │ │ │ + LLM Judge ──────┘─────────────┘ (多维度补充) (核心方法) (过程评估) │ │ │ └────────────┼─────────────┘ │ + 在线 A/B (上线前最终验证)
🎯 快速决策指南
你的场景离线评估在线评估工具推荐
Prompt 迭代LLM Judge + PromptfooPromptfoo + GPT-4 Judge
模型选型Benchmark + 自建 eval set小流量 A/B自建 + RAGAS
RAG 优化RAGAS + 人工抽查用户满意度 A/BRAGAS + LangFuse
Agent 开发任务成功率 + 轨迹分析真实任务 A/B自建评估框架
成本优化质量-成本帕累托分析路由策略 A/B自建 + LLM Judge
安全合规红队测试 + 毒性检测生产告警DeepEval + 自建

§13 完整代码示例

示例 1:完整的 LLM-as-Judge 评估流水线

"""
完整的 LLM-as-Judge 评估流水线
支持 Pointwise + Pairwise + 多维度评估
"""
import json
import random
from dataclasses import dataclass, field
from typing import Optional
from openai import OpenAI

client = OpenAI()

@dataclass
class EvalCase:
    """评估用例"""
    id: str
    question: str
    answer: str
    reference: Optional[str] = None  # 可选参考答案
    category: Optional[str] = None   # 分类标签

@dataclass
class JudgeResult:
    """评判结果"""
    case_id: str
    accuracy: int        # 1-5
    completeness: int    # 1-5
    relevance: int       # 1-5
    faithfulness: int    # 1-5 (需要 reference 或 contexts)
    reasoning: str
    overall: float       # 加权总分
    judge_model: str

JUDGE_SYSTEM = """你是一个专业的 AI 输出质量评估员。
你必须严格按照评分标准评估,先写出评估理由,再给出分数。
以 JSON 格式输出。"""

JUDGE_PROMPT = """请评估以下 AI 回答的质量。

## 问题
{question}

## AI 回答
{answer}

{reference_section}

## 评估维度与标准

### 1. 准确性 (accuracy): 1-5
5 = 所有事实正确,无幻觉
4 = 主要正确,轻微不精确
3 = 1-2 个事实错误
2 = 多个事实错误
1 = 严重幻觉/捏造

### 2. 完整性 (completeness): 1-5
5 = 全面覆盖所有方面
4 = 覆盖主要方面,轻微遗漏
3 = 覆盖主要方面但遗漏重要细节
2 = 只覆盖部分
1 = 严重不完整

### 3. 相关性 (relevance): 1-5
5 = 完全针对问题
4 = 大部分相关
3 = 有一些偏题内容
2 = 明显偏题
1 = 完全不相关

### 4. 忠实度 (faithfulness): 1-5
5 = 所有内容都有依据支持
4 = 大部分有依据
3 = 有 1-2 个无依据的声称
2 = 多个无依据声称
1 = 大量幻觉

## 输出格式
```json
{{
  "accuracy": <1-5>,
  "completeness": <1-5>,
  "relevance": <1-5>,
  "faithfulness": <1-5>,
  "reasoning": "<评估理由>",
  "overall": <0-100>
}}
```"""

def judge_pointwise(case: EvalCase, model: str = "gpt-4o") -> JudgeResult:
    """Pointwise 单点评估"""
    ref_section = f"## 参考答案\n{case.reference}" if case.reference else ""
    
    prompt = JUDGE_PROMPT.format(
        question=case.question,
        answer=case.answer,
        reference_section=ref_section,
    )
    
    response = client.chat.completions.create(
        model=model,
        temperature=0,
        messages=[
            {"role": "system", "content": JUDGE_SYSTEM},
            {"role": "user", "content": prompt},
        ],
        response_format={"type": "json_object"},
    )
    
    result = json.loads(response.choices[0].message.content)
    
    return JudgeResult(
        case_id=case.id,
        accuracy=result["accuracy"],
        completeness=result["completeness"],
        relevance=result["relevance"],
        faithfulness=result["faithfulness"],
        reasoning=result["reasoning"],
        overall=result["overall"],
        judge_model=model,
    )

def judge_pairwise(
    question: str, 
    answer_a: str, 
    answer_b: str,
    model: str = "gpt-4o",
    randomize: bool = True,
) -> dict:
    """Pairwise 两两比较,带位置随机化"""
    if randomize and random.random() > 0.5:
        answer_a, answer_b = answer_b, answer_a
        swapped = True
    else:
        swapped = False
    
    prompt = f"""比较以下两个回答,哪个更好地回答了问题?

## 问题
{question}

## 回答 A
{answer_a}

## 回答 B
{answer_b}

## 评估标准
- 准确性:事实是否正确
- 完整性:是否全面
- 相关性:是否针对问题
- 清晰度:是否易于理解

## 输出格式
```json
{{
  "winner": "A" | "B" | "Tie",
  "reasoning": "比较理由",
  "a_accuracy": <1-5>,
  "b_accuracy": <1-5>,
  "a_completeness": <1-5>,
  "b_completeness": <1-5>
}}
```"""
    
    response = client.chat.completions.create(
        model=model,
        temperature=0,
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"},
    )
    
    result = json.loads(response.choices[0].message.content)
    
    # 如果交换了位置,需要反转结果
    if swapped:
        if result["winner"] == "A":
            result["winner"] = "B"
        elif result["winner"] == "B":
            result["winner"] = "A"
        result["a_accuracy"], result["b_accuracy"] = result["b_accuracy"], result["a_accuracy"]
        result["a_completeness"], result["b_completeness"] = result["b_completeness"], result["a_completeness"]
    
    return result

def run_eval_suite(
    cases: list[EvalCase],
    judge_model: str = "gpt-4o",
    n_judges: int = 3,
) -> dict:
    """运行完整评估套件,多 Judge 投票"""
    all_results = []
    
    for case in cases:
        # 多次评判取平均
        judge_results = []
        for _ in range(n_judges):
            result = judge_pointwise(case, model=judge_model)
            judge_results.append(result)
        
        # 聚合结果
        avg_accuracy = sum(r.accuracy for r in judge_results) / n_judges
        avg_completeness = sum(r.completeness for r in judge_results) / n_judges
        avg_relevance = sum(r.relevance for r in judge_results) / n_judges
        avg_faithfulness = sum(r.faithfulness for r in judge_results) / n_judges
        avg_overall = sum(r.overall for r in judge_results) / n_judges
        
        all_results.append({
            "case_id": case.id,
            "category": case.category,
            "avg_accuracy": avg_accuracy,
            "avg_completeness": avg_completeness,
            "avg_relevance": avg_relevance,
            "avg_faithfulness": avg_faithfulness,
            "avg_overall": avg_overall,
            "individual_results": judge_results,
        })
    
    # 汇总统计
    summary = {
        "total_cases": len(cases),
        "judge_model": judge_model,
        "n_judges": n_judges,
        "avg_accuracy": sum(r["avg_accuracy"] for r in all_results) / len(all_results),
        "avg_completeness": sum(r["avg_completeness"] for r in all_results) / len(all_results),
        "avg_relevance": sum(r["avg_relevance"] for r in all_results) / len(all_results),
        "avg_faithfulness": sum(r["avg_faithfulness"] for r in all_results) / len(all_results),
        "avg_overall": sum(r["avg_overall"] for r in all_results) / len(all_results),
        "by_category": {},
    }
    
    # 按分类统计
    categories = set(r["category"] for r in all_results if r["category"])
    for cat in categories:
        cat_results = [r for r in all_results if r["category"] == cat]
        summary["by_category"][cat] = {
            "count": len(cat_results),
            "avg_overall": sum(r["avg_overall"] for r in cat_results) / len(cat_results),
        }
    
    return {"summary": summary, "details": all_results}

示例 2:RAG 评估流水线

"""
RAG 评估流水线 — 结合 RAGAS 和自定义指标
"""
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
from datasets import Dataset

# 自定义评估指标
def calculate_hallucination_rate(answers: list[str], contexts: list[list[str]]) -> float:
    """计算幻觉率:答案中有多少 claim 没有 context 支持"""
    total_claims = 0
    unsupported_claims = 0
    
    for answer, ctx in zip(answers, contexts):
        # 用 LLM 拆分答案为独立 claims
        claims_prompt = f"""将以下回答拆分为独立的陈述。每行一个。
回答: {answer}
输出格式: 每行一个陈述,不要编号"""
        
        claims = llm_call(claims_prompt).strip().split('\n')
        total_claims += len(claims)
        
        # 检查每个 claim 是否有 context 支持
        for claim in claims:
            support_prompt = f"""判断以下陈述是否被给定上下文支持。
陈述: {claim}
上下文: {' '.join(ctx)}
只回答 YES 或 NO。"""
            
            support = llm_call(support_prompt).strip().upper()
            if support == "NO":
                unsupported_claims += 1
    
    return unsupported_claims / max(total_claims, 1)

def calculate_citation_accuracy(answers: list[str], contexts: list[list[str]]) -> float:
    """计算引用准确率"""
    correct_citations = 0
    total_citations = 0
    
    for answer, ctx in zip(answers, contexts):
        # 提取答案中的引用标记,如 [1], [2]
        import re
        citations = re.findall(r'\[(\d+)\]', answer)
        total_citations += len(citations)
        
        # 检查引用的上下文是否确实支持对应内容
        for cite_num in citations:
            idx = int(cite_num) - 1
            if 0 <= idx < len(ctx):
                # 简化:假设引用存在即正确
                # 实际应用 LLM 判断引用内容是否匹配
                correct_citations += 1
    
    return correct_citations / max(total_citations, 1)

def run_rag_eval(
    questions: list[str],
    answers: list[str],
    contexts: list[list[str]],
    ground_truths: list[str],
) -> dict:
    """运行完整 RAG 评估"""
    # RAGAS 标准指标
    dataset = Dataset.from_dict({
        "question": questions,
        "answer": answers,
        "contexts": contexts,
        "ground_truth": ground_truths,
    })
    
    ragas_results = evaluate(
        dataset=dataset,
        metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
    )
    
    # 自定义指标
    halluc_rate = calculate_hallucination_rate(answers, contexts)
    citation_acc = calculate_citation_accuracy(answers, contexts)
    
    return {
        "ragas": ragas_results,
        "custom": {
            "hallucination_rate": halluc_rate,
            "citation_accuracy": citation_acc,
        },
        "overall_score": (
            ragas_results["faithfulness"] * 0.3 +
            ragas_results["answer_relevancy"] * 0.25 +
            ragas_results["context_precision"] * 0.2 +
            ragas_results["context_recall"] * 0.15 +
            (1 - halluc_rate) * 0.1
        ),
    }

示例 3:成本效率评估

"""
成本效率评估 — 找到质量-成本帕累托最优点
"""
from dataclasses import dataclass

@dataclass
class ModelEvalResult:
    model: str
    quality_score: float      # 0-100
    avg_latency_ms: float
    avg_cost_per_1k_tokens: float
    task_success_rate: float

def pareto_analysis(results: list[ModelEvalResult]) -> list[ModelEvalResult]:
    """找出帕累托最优的模型(质量不差且成本更低)"""
    # 按 cost 排序
    sorted_results = sorted(results, key=lambda r: r.avg_cost_per_1k_tokens)
    
    pareto_frontier = []
    best_quality_so_far = 0
    
    for result in sorted_results:
        if result.quality_score >= best_quality_so_far:
            pareto_frontier.append(result)
            best_quality_so_far = result.quality_score
    
    return pareto_frontier

# 示例:对比 5 个模型
model_results = [
    ModelEvalResult("gpt-4",         quality_score=92, avg_latency_ms=2200, avg_cost_per_1k_tokens=0.030, task_success_rate=0.94),
    ModelEvalResult("gpt-4o",        quality_score=89, avg_latency_ms=800,  avg_cost_per_1k_tokens=0.005, task_success_rate=0.91),
    ModelEvalResult("gpt-4o-mini",   quality_score=78, avg_latency_ms=400,  avg_cost_per_1k_tokens=0.00015, task_success_rate=0.82),
    ModelEvalResult("claude-3.5",    quality_score=90, avg_latency_ms=1200, avg_cost_per_1k_tokens=0.008, task_success_rate=0.92),
    ModelEvalResult("claude-3-haiku", quality_score=75, avg_latency_ms=300,  avg_cost_per_1k_tokens=0.00025, task_success_rate=0.80),
]

frontier = pareto_analysis(model_results)
print("🏆 帕累托最优模型:")
for m in frontier:
    print(f"  {m.model}: 质量={m.quality_score} 成本=${m.avg_cost_per_1k_tokens}/1k 成功率={m.task_success_rate}")

# 输出:
# 🏆 帕累托最优模型:
#   gpt-4o-mini: 质量=78 成本=$0.00015/1k 成功率=0.82
#   gpt-4o: 质量=89 成本=$0.005/1k 成功率=0.91
#   gpt-4: 质量=92 成本=$0.03/1k 成功率=0.94

def design_routing_strategy(results: list[ModelEvalResult]) -> dict:
    """设计路由策略:根据任务难度分配模型"""
    # 简单规则:用质量-成本比排序
    cost_efficiency = [
        (r.model, r.quality_score / r.avg_cost_per_1k_tokens)
        for r in results
    ]
    
    return {
        "easy_tasks": "gpt-4o-mini",    # 简单任务用便宜模型
        "medium_tasks": "gpt-4o",       # 中等任务用性价比模型
        "hard_tasks": "gpt-4",          # 困难任务用最强模型
        "routing_prompt": """判断以下问题的难度:
- Easy: 事实查询、简单翻译、格式转换
- Medium: 推理、分析、多步骤任务
- Hard: 复杂推理、代码生成、创意写作
只输出 Easy/Medium/Hard。""",
        "estimated_savings": "60-80%",  # 相比全部用最强模型
    }

🔗 LLM 集成

评估结果直接影响模型选型和路由策略。详见 LLM 集成

🔗 RAG 架构

RAGAS 指标直接反映 RAG 各组件质量。详见 RAG 架构

🔗 Agent 架构

Agent 评估方法来自 Agent 研究提炼。详见 Agent 架构

🔗 提示词工程

Prompt 变更必须通过评估验证。详见 提示词工程

🔗 向量数据库

检索质量评估直接影响 RAG 评分。详见 向量数据库

🔗 Agent 研究

SWE-agent/OpenHands 的自我评估机制。详见 Agent 研究

💡 评估的金字塔原则:基础层——传统指标(有 ground truth 时);中间层——LLM-as-Judge(开放式评估);顶层——A/B 测试(生产验证)。越往上越贵越准,越往下越快越便宜。根据阶段选择合适的层级,不要一步到位,也不要只停留在底层。