跳到正文

更多文章

影响力日常操作系统:21天习惯养成计划 从技能雇佣者到价值创造者 互惠账户的运营 影响力的三层架构 组织的注意力经济学
LLM评估体系

本文来源于数据从业者全栈知识库,更多体系化内容请访问知识库。

BLEU 分数 0.45,用户投诉率 30%。你信哪个?

传统 NLP 评估指标与人类判断之间的相关性,在 LLM 时代几乎崩塌了。BLEU 高不代表答案好,ROUGE 低不代表答案差。LLM 评估需要一套完全不同的体系。

目录

  • #为什么 LLM 评估很难
  • #三层评估体系总览
  • #第一层:自动化评估(RAGAS)
  • #第二层:LLM-as-Judge
  • #第三层:人工评估
  • #评估数据集建设
  • #评估驱动的开发工作流

为什么 LLM 评估很难

三个根本性困难

1. 开放域输出,没有唯一正确答案

传统分类模型的评估很简单:预测标签和真实标签对比,算准确率。

LLM 的输出是自由文本。“Flink 的 Checkpoint 机制”这个问题,有无数个”正确”回答——详细的、简洁的、偏原理的、偏实践的。没有一个”golden answer”能覆盖所有合理表达。

2. 人工评估是黄金标准,但不可持续

请人类专家评估每一条输出,是最准确的方法,也是最贵、最慢的方法。规模上来之后,每天产生 10 万条输出,人工评估直接不可行。

3. 传统自动化指标与人类判断相关性差

指标原始设计场景LLM 场景下的问题
BLEU机器翻译评估只看 n-gram 重叠,忽略语义,同义词替换就得低分
ROUGE文本摘要评估关注词汇重叠,长答案比短答案天然高分
Perplexity语言模型评估反映流畅度,不反映正确性;流畅的幻觉也有低困惑度
Exact MatchQA 评估”2024年”和”2024”被判为不同答案

结论:需要一套新的评估框架,兼顾成本、速度和与人类判断的相关性。


三层评估体系总览

flowchart LR
    subgraph L1["第一层:自动化评估"]
        direction TB
        A1[RAGAS 框架]
        A2[TruLens]
        A3[自定义规则检查]
    end

    subgraph L2["第二层:LLM-as-Judge"]
        direction TB
        B1[GPT-4o / Claude 评判]
        B2[打分式评估]
        B3[对比式评估]
    end

    subgraph L3["第三层:人工评估"]
        direction TB
        C1[专家评审]
        C2[众包标注]
        C3[用户反馈收集]
    end

    L1 -- "快速迭代<br>成本: $<br>速度: 分钟级" --> L2
    L2 -- "质量校验<br>成本: $$<br>速度: 小时级" --> L3
    L3 -- "黄金标准<br>成本: $$$<br>速度: 天级" --> L1

    style L1 fill:#e8f5e9
    style L2 fill:#fff3e0
    style L3 fill:#fce4ec

三层体系的分工

层级用途触发时机成本
第一层:自动化评估快速迭代验证,CI/CD 门禁每次 Prompt 变更极低
第二层:LLM-as-Judge更细致的质量评估每次版本发布前,日常抽样中等
第三层:人工评估建立基准,校准自动化指标新模型上线,高风险场景

第一层:自动化评估(RAGAS)

RAGAS(Retrieval Augmented Generation Assessment)是专门为 RAG 系统设计的评估框架,也是目前最被广泛使用的开源 LLM 评估工具之一。

四个核心指标

指标评估对象说明分值范围
Context Recall检索质量理想答案需要的信息,有多少比例在检索结果中?0~1
Context Precision检索质量检索结果中,有多少是真正有用的(非噪声)?0~1
Answer Relevancy生成质量模型的回答是否切题?0~1
Faithfulness幻觉检测回答中的事实是否都来自检索结果(无幻觉)?0~1

一句话记忆

  • Context Recall = 检索有没有漏掉重要信息
  • Context Precision = 检索有没有引入无关噪声
  • Answer Relevancy = 回答有没有答非所问
  • Faithfulness = 回答有没有编造信息

RAGAS 完整评估流程

Terminal window
pip install ragas langchain-openai
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_recall,
context_precision,
)
from datasets import Dataset
# 准备评估数据集
# 每条数据需要:问题、检索到的文档、模型回答、参考答案(context_recall 需要)
eval_data = {
"question": [
"Flink 的 Checkpoint 和 Savepoint 有什么区别?",
"什么是 Kafka 的消费者组?",
"Spark 的 RDD 和 DataFrame 有什么区别?",
],
"answer": [
# 模型实际生成的回答
"Checkpoint 是 Flink 自动触发的容错机制,用于故障恢复。Savepoint 是手动触发的状态快照,专用于版本升级和迁移。",
"消费者组是 Kafka 的消费端抽象,同组内的消费者共同消费一个 Topic 的所有分区,每个分区只被组内一个消费者消费。",
"RDD 是 Flink 底层的数据结构,不支持 SQL。DataFrame 是基于 RDD 的高层抽象,支持 SQL 查询且有 Schema。",
],
"contexts": [
# 检索返回的文档列表(每道题对应一个文档列表)
[
"Apache Flink 的 Checkpoint 是一种容错机制,由 Flink 运行时自动触发...",
"Savepoint 是用户手动触发的全局一致性快照...",
],
[
"Kafka 消费者组(Consumer Group)允许多个消费者实例共同消费同一个 Topic...",
],
[
"Spark 的 RDD(弹性分布式数据集)是最基础的数据抽象...",
"DataFrame 是 Spark 1.3 引入的高层 API,提供了类似 SQL 的操作接口...",
],
],
"ground_truth": [
# 参考答案(Context Recall 需要用到)
"Checkpoint 自动触发用于故障恢复,Savepoint 手动触发用于版本升级和状态迁移。两者都是全局一致性快照。",
"消费者组使得多个消费者可以协作消费一个 Topic,实现负载均衡,每个分区在同一时刻只能被组内一个消费者消费。",
"RDD 是低层 API,类型安全但缺少优化;DataFrame 有 Schema,支持 SQL,Catalyst 优化器自动优化执行计划。",
],
}
dataset = Dataset.from_dict(eval_data)
# 执行评估(RAGAS 内部会调用 LLM 来判断语义匹配)
results = evaluate(
dataset=dataset,
metrics=[
context_precision,
context_recall,
faithfulness,
answer_relevancy,
],
# 默认使用 gpt-3.5-turbo,可以换成更便宜的模型
# llm=ChatOpenAI(model="gpt-4o-mini"),
)
print(results)
# {'context_precision': 0.88, 'context_recall': 0.75,
# 'faithfulness': 0.92, 'answer_relevancy': 0.85}
# 转成 DataFrame 详细分析
df = results.to_pandas()
print(df"question", "faithfulness", "answer_relevancy")

批量评估脚本(集成到 CI/CD)

import json
from pathlib import Path
from datetime import datetime
def run_automated_evaluation(
test_cases_path: str,
output_path: str,
pass_threshold: dict = None,
) -> bool:
"""
运行自动化评估,返回是否通过质量门禁
可集成到 GitHub Actions 等 CI/CD 流水线
"""
if pass_threshold is None:
pass_threshold = {
"faithfulness": 0.85, # 幻觉率不超过 15%
"answer_relevancy": 0.80, # 回答相关性不低于 80%
"context_precision": 0.75, # 检索精度不低于 75%
}
# 加载测试用例
with open(test_cases_path, encoding="utf-8") as f:
test_cases = json.load(f)
dataset = Dataset.from_dict(test_cases)
results = evaluate(
dataset=dataset,
metrics=[faithfulness, answer_relevancy, context_precision],
)
scores = {
"faithfulness": results["faithfulness"],
"answer_relevancy": results["answer_relevancy"],
"context_precision": results["context_precision"],
}
# 判断是否通过
passed = all(scores[k] >= pass_threshold[k] for k in pass_threshold)
# 输出评估报告
report = {
"timestamp": datetime.now().isoformat(),
"scores": scores,
"thresholds": pass_threshold,
"passed": passed,
"failed_metrics": [
k for k, v in scores.items()
if v < pass_threshold.get(k, 0)
],
}
with open(output_path, "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"评估{'通过' if passed else '未通过'}{scores}")
return passed
# CI/CD 中使用
# if not run_automated_evaluation("test_cases.json", "eval_report.json"):
# sys.exit(1) # 失败则阻断部署

第二层:LLM-as-Judge

用强模型(GPT-4o / Claude)评估弱模型(或相同模型)的输出质量。

为什么 LLM-as-Judge 有效

  1. 强模型具备语义理解能力,能判断”两种表达方式是否等价”
  2. 评估速度比人工快 100 倍,成本比人工低 10 倍
  3. 评估标准可以通过 Prompt 精确控制,比人工标注更一致

已知偏见(需要缓解):

  • 位置偏见:倾向于选择第一个选项(对比式评估中)
  • 冗长偏见:倾向于给更长的答案打高分
  • 自我偏好偏见:GPT-4o 评估时倾向于给 GPT 系列打高分

打分式评估(Scoring)

from openai import OpenAI
import json
from typing import Optional
client = OpenAI()
SCORING_PROMPT_TEMPLATE = """你是一个专业的 AI 质量评估专家。
请从以下四个维度评估【助手回答】的质量,每个维度打 1-5 分:
**评分维度**:
1. **正确性(Correctness)**:答案是否事实准确?
- 5分:完全准确,无错误
- 3分:基本准确,有小瑕疵
- 1分:存在明显错误或幻觉
2. **相关性(Relevancy)**:答案是否切题?
- 5分:完全切题,直接回答了问题
- 3分:基本相关,但有离题部分
- 1分:答非所问
3. **完整性(Completeness)**:答案是否覆盖了问题的主要方面?
- 5分:全面覆盖,无明显遗漏
- 3分:覆盖主要方面,有次要遗漏
- 1分:严重不完整
4. **清晰度(Clarity)**:答案是否易于理解?
- 5分:结构清晰,表达准确
- 3分:基本清晰,有些地方可以更好
- 1分:混乱或难以理解
**用户问题**:
{question}
**参考信息**(如果有):
{context}
**助手回答**:
{answer}
请严格按照以下 JSON 格式输出,不要有其他内容:
{{
"correctness": <1-5分>,
"relevancy": <1-5分>,
"completeness": <1-5分>,
"clarity": <1-5分>,
"overall": <四项平均值,保留一位小数>,
"reasoning": "<简要说明打分理由,100字以内>",
"issues": ["<存在的问题1>", "<存在的问题2>"]
}}"""
def llm_judge_score(
question: str,
answer: str,
context: str = "",
judge_model: str = "gpt-4o-mini",
) -> dict:
"""
使用 LLM 对单条输出打分
返回各维度分数和理由
"""
prompt = SCORING_PROMPT_TEMPLATE.format(
question=question,
context=context if context else "(无参考信息)",
answer=answer,
)
response = client.chat.completions.create(
model=judge_model,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0, # 评估需要确定性,不要随机
)
return json.loads(response.choices[0].message.content)
# 使用示例
score = llm_judge_score(
question="什么是 Kafka 的消费者组?",
answer="Kafka 消费者组是一组共同消费 Topic 的消费者,每个分区只能被组内一个消费者消费,实现负载均衡。",
context="Kafka Consumer Group 是 Kafka 消费端的核心抽象...",
)
print(score)
# {
# "correctness": 5,
# "relevancy": 5,
# "completeness": 4,
# "clarity": 5,
# "overall": 4.8,
# "reasoning": "答案准确、切题,略缺少 Rebalance 机制的说明",
# "issues": ["未提及 Rebalance 触发场景"]
# }

对比式评估(Pairwise Comparison)

在 A/B 测试中,对比两个版本的输出哪个更好:

PAIRWISE_PROMPT_TEMPLATE = """你是一个专业的 AI 质量评估专家。
请比较以下两个回答哪个更好。
**用户问题**:{question}
**回答 A**:
{answer_a}
**回答 B**:
{answer_b}
评估标准(按重要性排序):
1. 事实正确性(最重要)
2. 问题相关性
3. 表达清晰度
4. 内容完整性
注意:避免长度偏见,不要因为某个回答更长就认为它更好。
请输出 JSON:
{{
"winner": "A" 或 "B" 或 "tie",
"confidence": "high" 或 "medium" 或 "low",
"reasoning": "<比较理由,150字以内>",
"a_strengths": ["<A的优点>"],
"b_strengths": ["<B的优点>"]
}}"""
def pairwise_compare(
question: str,
answer_a: str,
answer_b: str,
judge_model: str = "gpt-4o-mini",
swap_and_average: bool = True, # 交换顺序再评估一次,缓解位置偏见
) -> dict:
"""
对比两个答案,判断哪个更好
swap_and_average=True 时:正序 + 逆序各评估一次,取综合结论
"""
def single_compare(a: str, b: str) -> dict:
prompt = PAIRWISE_PROMPT_TEMPLATE.format(
question=question, answer_a=a, answer_b=b
)
response = client.chat.completions.create(
model=judge_model,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0,
)
return json.loads(response.choices[0].message.content)
result_1 = single_compare(answer_a, answer_b)
if not swap_and_average:
return result_1
# 交换顺序再评估(注意:winner 需要取反)
result_2 = single_compare(answer_b, answer_a)
# 汇总两次结果
winner_votes = {"A": 0, "B": 0, "tie": 0}
if result_1["winner"] == "A":
winner_votes["A"] += 1
elif result_1["winner"] == "B":
winner_votes["B"] += 1
else:
winner_votes["tie"] += 1
# 第二次评估中 A/B 是反的
if result_2["winner"] == "A": # A 是原始的 B
winner_votes["B"] += 1
elif result_2["winner"] == "B": # B 是原始的 A
winner_votes["A"] += 1
else:
winner_votes["tie"] += 1
final_winner = max(winner_votes, key=winner_votes.get)
return {
"winner": final_winner,
"vote_counts": winner_votes,
"confidence": "high" if winner_votes[final_winner] == 2 else "low",
"round1": result_1,
"round2": result_2,
}

批量评估脚本

import concurrent.futures
from tqdm import tqdm
def batch_llm_judge(
eval_cases: list[dict],
judge_model: str = "gpt-4o-mini",
max_workers: int = 5, # 并发数,注意 API 限速
) -> list[dict]:
"""
批量评估,使用线程池并发加速
"""
def evaluate_single(case: dict) -> dict:
score = llm_judge_score(
question=case["question"],
answer=case["answer"],
context=case.get("context", ""),
judge_model=judge_model,
)
return {**case, "judge_score": score}
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(evaluate_single, case): case for case in eval_cases}
for future in tqdm(
concurrent.futures.as_completed(futures),
total=len(eval_cases),
desc="LLM 评估中"
):
try:
results.append(future.result())
except Exception as e:
print(f"评估失败:{e}")
# 汇总统计
all_scores = [r["judge_score"]["overall"] for r in results if "judge_score" in r]
print(f"\n评估完成:{len(results)} 条")
print(f"平均综合分:{sum(all_scores)/len(all_scores):.2f}/5.0")
print(f"高质量(>4分)比例:{sum(1 for s in all_scores if s > 4)/len(all_scores):.1%}")
return results

第三层:人工评估

人工评估是黄金标准,但成本高,不能替代自动化,只能战略性使用。

必须人工评估的场景

  1. 新模型/基础模型上线前:验证自动化指标与人类判断的相关性是否仍然成立
  2. 高风险场景:医疗、法律、金融建议类内容,自动化评估不能承担责任
  3. 建立基准测试集(Golden Dataset):第一批标注必须是人工的
  4. 校准自动化指标:检查 LLM-as-Judge 的打分是否与人类判断一致

评估工作流设计

# 评估任务分发系统(简化版)
from dataclasses import dataclass, field
from datetime import datetime
import random
import json
@dataclass
class EvalTask:
task_id: str
question: str
answer: str
context: str = ""
assigned_to: str = ""
completed: bool = False
human_score: dict = field(default_factory=dict)
created_at: str = field(default_factory=lambda: datetime.now().isoformat())
class HumanEvalWorkflow:
"""
人工评估任务管理
- 随机分配评估任务
- 同一条数据由 2 人独立评估(用于计算标注一致性)
- 分歧较大时触发第三人裁决
"""
def __init__(self, evaluators: list[str], agreement_threshold: float = 0.8):
self.evaluators = evaluators
self.agreement_threshold = agreement_threshold
self.tasks: list[EvalTask] = []
def add_tasks(self, eval_cases: list[dict]) -> None:
"""添加评估任务,重要数据分配 2 个标注者"""
for case in eval_cases:
task = EvalTask(
task_id=f"eval_{len(self.tasks):04d}",
question=case["question"],
answer=case["answer"],
context=case.get("context", ""),
)
self.tasks.append(task)
def assign_tasks(self) -> dict[str, list[str]]:
"""
为每个评估者分配任务
每条数据分配给 2 个不同的评估者
"""
assignments: dict[str, list[str]] = {e: [] for e in self.evaluators}
for task in self.tasks:
# 随机选 2 个评估者
assigned = random.sample(self.evaluators, min(2, len(self.evaluators)))
for evaluator in assigned:
assignments[evaluator].append(task.task_id)
return assignments
def compute_inter_rater_agreement(
self,
scores_a: list[float],
scores_b: list[float],
) -> float:
"""
计算两个标注者之间的一致性(Cohen's Kappa 近似)
实际生产中建议使用 sklearn.metrics.cohen_kappa_score
"""
agreements = sum(
1 for a, b in zip(scores_a, scores_b)
if abs(a - b) <= 1 # 相差不超过 1 分算一致
)
return agreements / len(scores_a) if scores_a else 0.0
def flag_disagreements(self, task_id: str, scores: list[float]) -> bool:
"""检查是否需要第三人裁决"""
if len(scores) < 2:
return False
return abs(scores[0] - scores[1]) > 2 # 分差超过 2 分,需要裁决

数据采样策略

不是每条输出都需要人工评估,聪明的采样能最大化评估价值:

def smart_sampling(
production_logs: list[dict],
sample_size: int = 200,
) -> list[dict]:
"""
策略性采样:困难案例重点评估
"""
samples = []
# 1. 随机样本(20%):代表正态分布,用于总体质量估计
random_sample = random.sample(production_logs, int(sample_size * 0.2))
samples.extend([(log, "random") for log in random_sample])
# 2. 低自信案例(30%):模型表达了不确定性的输出
uncertainty_keywords = ["我不确定", "可能", "据我所知", "不太清楚"]
uncertain_logs = [
log for log in production_logs
if any(kw in log.get("answer", "") for kw in uncertainty_keywords)
]
uncertain_sample = random.sample(
uncertain_logs, min(int(sample_size * 0.3), len(uncertain_logs))
)
samples.extend([(log, "uncertain") for log in uncertain_sample])
# 3. 用户负反馈案例(30%):被用户踩的输出,最有价值
thumbs_down_logs = [
log for log in production_logs
if log.get("user_feedback", 1) == 0 # 0 = 踩
]
thumbs_down_sample = random.sample(
thumbs_down_logs, min(int(sample_size * 0.3), len(thumbs_down_logs))
)
samples.extend([(log, "thumbs_down") for log in thumbs_down_sample])
# 4. 长上下文案例(20%):复杂输入往往更容易出幻觉
long_context_logs = [
log for log in production_logs
if len(log.get("context", "")) > 2000
]
long_sample = random.sample(
long_context_logs, min(int(sample_size * 0.2), len(long_context_logs))
)
samples.extend([(log, "long_context") for log in long_sample])
return [{"log": log, "sample_type": t} for log, t in samples[:sample_size]]

评估数据集建设

从生产日志挖掘困难案例

def mine_hard_cases_from_logs(
langfuse_client,
days_back: int = 7,
hard_case_criteria: dict = None,
) -> list[dict]:
"""
从 LangFuse 日志中自动挖掘困难案例
"""
if hard_case_criteria is None:
hard_case_criteria = {
"min_latency_seconds": 5, # 超时的请求(可能上下文过长)
"user_thumbs_down": True, # 用户踩过的
"low_faithfulness": 0.7, # RAGAS 评分低的
}
hard_cases = []
# 从 LangFuse 获取最近 N 天的 Trace
from datetime import datetime, timedelta
end = datetime.now()
start = end - timedelta(days=days_back)
traces = langfuse_client.fetch_traces(
from_timestamp=start,
to_timestamp=end,
limit=1000,
).data
for trace in traces:
is_hard = False
reasons = []
# 检查延迟
if trace.latency and trace.latency > hard_case_criteria["min_latency_seconds"] * 1000:
is_hard = True
reasons.append("high_latency")
# 检查用户反馈
scores = [s for s in (trace.scores or []) if s.name == "user_feedback"]
if scores and scores[0].value < 0.5:
is_hard = True
reasons.append("user_thumbs_down")
# 检查 RAGAS 分数
faithfulness_scores = [s for s in (trace.scores or []) if s.name == "faithfulness"]
if faithfulness_scores and faithfulness_scores[0].value < hard_case_criteria["low_faithfulness"]:
is_hard = True
reasons.append("low_faithfulness")
if is_hard:
hard_cases.append({
"trace_id": trace.id,
"question": trace.input.get("query", "") if trace.input else "",
"answer": trace.output.get("answer", "") if trace.output else "",
"hard_reasons": reasons,
})
return hard_cases

Golden Dataset 维护规范

import json
from pathlib import Path
from datetime import datetime
class GoldenDataset:
"""
黄金标注数据集管理
- 存储经过人工验证的高质量问答对
- 用于定期评估模型退化
- 版本化管理,支持数据集迭代
"""
def __init__(self, dataset_path: str = "golden_dataset.json"):
self.path = Path(dataset_path)
self.data = self._load()
def _load(self) -> list[dict]:
if self.path.exists():
with open(self.path, encoding="utf-8") as f:
return json.load(f)
return []
def add(
self,
question: str,
ground_truth_answer: str,
context: list[str],
annotator: str,
difficulty: str = "medium", # easy / medium / hard
domain: str = "general",
) -> None:
entry = {
"id": f"gd_{len(self.data):04d}",
"question": question,
"ground_truth": ground_truth_answer,
"contexts": context,
"metadata": {
"annotator": annotator,
"difficulty": difficulty,
"domain": domain,
"created_at": datetime.now().isoformat(),
}
}
self.data.append(entry)
self._save()
def _save(self) -> None:
with open(self.path, "w", encoding="utf-8") as f:
json.dump(self.data, f, ensure_ascii=False, indent=2)
def get_by_difficulty(self, difficulty: str) -> list[dict]:
return [d for d in self.data if d["metadata"]["difficulty"] == difficulty]
def export_for_ragas(self) -> dict:
"""导出为 RAGAS 评估格式"""
return {
"question": [d["question"] for d in self.data],
"ground_truth": [d["ground_truth"] for d in self.data],
"contexts": [d["contexts"] for d in self.data],
}

评估驱动的开发工作流

将评估嵌入开发流程,确保每次变更都有数据支撑:

flowchart TD
    START["修改 Prompt / 换模型 / 调整检索策略"]
    RAGAS["1. 自动化评估(RAGAS)<br>对 Golden Dataset 跑四指标<br>与上一版本对比,检查有无退化<br>耗时:&lt; 5 分钟"]
    JUDGE["2. LLM-as-Judge 评估<br>对 100 条测试用例打分<br>与 Control 版本做 Pairwise 比较<br>统计显著性检验<br>耗时:&lt; 30 分钟"]
    GRAY["3. 灰度上线(1% → 10% → 50% → 100%)<br>监控实时用户反馈(点赞率)<br>监控 LangFuse 中的质量指标"]
    FULL["4. 全量上线 + 更新 Golden Dataset"]

    START --> RAGAS
    RAGAS -->|"通过(无退化)"| JUDGE
    RAGAS -->|"退化,终止"| START
    JUDGE -->|"新版本显著更好(p &lt; 0.05)"| GRAY
    JUDGE -->|"差异不显著,继续收集数据"| START
    GRAY -->|"反馈正向"| FULL
    GRAY -->|"反馈负向,回滚"| START
def evaluation_gate(
new_prompt_version: str,
current_prompt_version: str,
golden_dataset_path: str,
min_improvement: float = 0.02, # 至少提升 2%
) -> dict:
"""
评估门禁:自动化决策新版本是否可以上线
"""
golden_dataset = GoldenDataset(golden_dataset_path)
# 对两个版本分别生成回答
current_answers = generate_answers(
golden_dataset.data, prompt_version=current_prompt_version
)
new_answers = generate_answers(
golden_dataset.data, prompt_version=new_prompt_version
)
# RAGAS 评估
current_scores = run_ragas_eval(current_answers, golden_dataset)
new_scores = run_ragas_eval(new_answers, golden_dataset)
# 综合得分对比
current_overall = sum(current_scores.values()) / len(current_scores)
new_overall = sum(new_scores.values()) / len(new_scores)
improvement = new_overall - current_overall
should_deploy = improvement >= min_improvement
return {
"current_version": current_prompt_version,
"new_version": new_prompt_version,
"current_overall": current_overall,
"new_overall": new_overall,
"improvement": improvement,
"should_deploy": should_deploy,
"scores_detail": {
"current": current_scores,
"new": new_scores,
},
"recommendation": (
f"建议上线:新版本综合分提升 {improvement:.1%}"
if should_deploy
else f"不建议上线:提升不足({improvement:.1%} < {min_improvement:.1%})"
),
}

小结

LLM 评估的三个核心原则:

1. 分层评估,对应不同场景

  • 频繁迭代:RAGAS 自动化评估(快、便宜)
  • 版本上线前:LLM-as-Judge(准、可扩展)
  • 基准建立:人工评估(准确、不可替代)

2. Golden Dataset 是最重要的资产

  • 比模型本身更难复制
  • 需要持续维护和迭代
  • 建议从生产日志中挖掘困难案例填充

3. 评估要驱动决策

  • 不是为了出报告,是为了支撑上线决策
  • 建立明确的质量门禁:评估不通过就不上线

系列导航

  • LLMOps体系全景 — 回到全景视图
  • LLM可观测性与监控 — 生产环境的质量感知
  • Prompt工程管理 — Prompt 变更的评估闭环
  • LLM成本控制与优化 — 评估成本的控制

相关文档

  • MLOps最佳实践 — 传统 ML 评估体系对比
  • RAG检索增强生成实战 — RAGAS 在 RAG 场景的应用
  • AI数据标注与数据飞轮 — 人工评估与标注体系

#LLMOps #LLM评估 #RAGAS #LLM-as-Judge #幻觉检测 #AI质量保障


本文节选自数据从业者全栈知识库。知识库包含 2300+ 篇体系化技术文档,覆盖数据分析、数据工程、数据治理、AI 等全栈领域。了解更多 →

Elazer (石头)
Elazer (石头)

11 年数据老兵,从分析师到架构专家。用真实经历帮数据人少走弯路。

加入免费社群

和数据从业者一起交流成长

了解详情 →

成为会员

解锁全部内容 + 知识库

查看权益 →
← 上一篇 写给数据人的 2026:当技术护城河被填平,我们靠什么端稳饭碗? 下一篇 → Agentic RAG工程实战