摘要
你喂给AI的信息真的有用吗?模型真的用了你给它的上下文吗?幻觉了多少?这篇文章手把手教你评估上下文质量——从基础的忠实度检测,到RAGAS评估框架,再到最新的幻觉检测技术。看完你就能给AI应用做”体检”了。
先问个问题:为什么要评估上下文质量?
想象这两个场景
场景A(没做评估):
用户:苹果公司是哪年成立的?
AI:根据上下文信息,苹果公司成立于1976年。
(实际上上下文里根本没提这个日期,AI瞎编的!)
场景B(做了评估):
用户:苹果公司是哪年成立的?
AI:我检查了您提供的上下文,里面没有提到具体的成立年份。
所以我无法回答这个问题。
(上下文忠实度:LOW → 触发降级回复)
这就是上下文质量评估的价值——让AI知道自己”不知道”什么。
一、上下文质量评估的四大金刚
评估维度一览
┌─────────────────────────────────────────────────────────────┐
│ RAG/上下文评估四大维度 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📊 上下文质量 │
│ ├─ Context Precision:上下文里有多少是相关的? │
│ └─ Context Recall:答案需要的信息,上下文覆盖了多少? │
│ │
│ ✅ 答案质量 │
│ ├─ Faithfulness:AI有没有瞎编? │
│ └─ Answer Relevance:答案和问题相关吗? │
│ │
│ 🔍 幻觉检测 │
│ ├─ Factual Accuracy:事实对不对? │
│ └─ Citation Accuracy:引用准不准? │
│ │
└─────────────────────────────────────────────────────────────┘
核心指标速查表
| 指标 | 测量什么 | 理想值 | 评估方式 |
|---|---|---|---|
| Context Precision | 上下文相关比例 | 1.0 | 自动 |
| Context Recall | 相关内容召回 | 1.0 | 人工/LLM |
| Faithfulness | 内容忠实度 | 1.0 | 自动 |
| Answer Relevance | 答案相关性 | 1.0 | 自动 |
| Hallucination Rate | 瞎编比例 | 0.0 | 混合 |
二、Faithfulness(忠实度)评估
什么是忠实度?
忠实度衡量的就是:AI有没有老老实实根据你给的上下文回答,还是在瞎编?
打个比方:
你给AI一份菜单(上下文):
- 宫保鸡丁:58元
- 鱼香肉丝:52元
用户问:哪个菜便宜?
AI答:宫保鸡丁便宜,52元。← ❌ 不忠实!(把58说成52)
AI答:鱼香肉丝便宜,52元。← ✅ 忠实!
评估忠实度的方法
方法1:声明提取法
class FaithfulnessEvaluator:
"""忠实度评估器"""
def __init__(self, llm_client):
self.llm = llm_client
def evaluate(
self,
question: str,
context: str,
answer: str
) -> dict:
"""
评估忠实度
核心思路:
1. 从答案中提取所有"声明"(事实陈述)
2. 检查每个声明是否被上下文支持
3. 计算被支持的声明比例
"""
# 1️⃣ 提取声明
claims = self._extract_claims(answer)
# 2️⃣ 检查每个声明
supported = []
unsupported = []
for claim in claims:
if self._is_supported(claim, context):
supported.append(claim)
else:
unsupported.append(claim)
# 3️⃣ 计算分数
score = len(supported) / len(claims) if claims else 1.0
return {
'score': score,
'total_claims': len(claims),
'supported_claims': supported,
'unsupported_claims': unsupported,
'level': self._get_level(score)
}
def _extract_claims(self, answer: str) -> list:
"""从答案中提取所有事实声明"""
prompt = f"""从以下答案中提取所有可验证的事实声明。
每个声明应该是一个独立的事实陈述。
答案:
{answer}
要求:
1. 只提取明确的事实陈述
2. 每个声明用一行输出
3. 不要提取观点、感受、通用描述
声明列表:"""
result = self.llm.generate(prompt)
claims = [line.strip() for line in result.split('\n') if line.strip()]
return claims
def _is_supported(self, claim: str, context: str) -> bool:
"""检查声明是否被上下文支持"""
prompt = f"""判断以下声明是否可以从提供的上下文中推断或验证。
声明:{claim}
上下文:
{context}
判断标准:
- 如果上下文明确支持或能推断出该声明,返回"支持"
- 如果上下文未提及或与声明矛盾,返回"不支持"
判断结果:"""
result = self.llm.generate(prompt).strip()
return "支持" in result
def _get_level(self, score: float) -> str:
"""获取等级描述"""
if score >= 0.9:
return "Excellent (优秀)"
elif score >= 0.7:
return "Good (良好)"
elif score >= 0.5:
return "Fair (一般)"
else:
return "Poor (较差)"方法2:句子级评估
class SentenceLevelFaithfulness:
"""句子级忠实度评估"""
def __init__(self, llm_client):
self.llm = llm_client
def evaluate_sentence_level(
self,
context: str,
answer: str
) -> dict:
"""逐句评估忠实度"""
# 按句子分割答案
sentences = self._split_sentences(answer)
results = []
for sentence in sentences:
verdict = self._evaluate_single_sentence(sentence, context)
results.append({
'sentence': sentence,
'supported': verdict['supported'],
'reason': verdict.get('reason', ''),
})
# 计算整体分数
supported_count = sum(1 for r in results if r['supported'])
overall_score = supported_count / len(results) if results else 1.0
return {
'overall_score': overall_score,
'sentence_results': results,
'unsupported_sentences': [r for r in results if not r['supported']]
}
def _split_sentences(self, text: str) -> list:
"""按句子分割"""
import re
sentences = re.split(r'[。!?\n]', text)
return [s.strip() for s in sentences if s.strip()]
def _evaluate_single_sentence(
self,
sentence: str,
context: str
) -> dict:
"""评估单个句子"""
prompt = f"""判断以下句子是否完全由上下文支持。
句子:{sentence}
上下文:
{context}
分析步骤:
1. 检查句子中的每个事实是否在上下文中有依据
2. 检查句子的推断是否合理
3. 检查是否有添加上下文中不存在的信息
判断结果和理由:"""
result = self.llm.generate(prompt)
supported = "支持" in result or "一致" in result
reason = result.split("理由:")[-1].strip() if "理由" in result else ""
return {
'supported': supported,
'reason': reason,
'llm_analysis': result
}实战:调用示例
# 使用忠实度评估器
evaluator = FaithfulnessEvaluator(llm_client)
result = evaluator.evaluate(
question="苹果公司是哪年成立的?",
context="苹果公司由史蒂夫·乔布斯、史蒂夫·沃兹尼亚克等人于1976年在美国加利福尼亚州创立。",
answer="苹果公司成立于1976年,由乔布斯等人创立。"
)
print(f"忠实度得分: {result['score']:.2f}")
print(f"等级: {result['level']}")
print(f"总声明数: {result['total_claims']}")
print(f"被支持的声明: {result['supported_claims']}")
print(f"未被支持的声明: {result['unsupported_claims']}")三、Answer Relevance(答案相关性)评估
什么是答案相关性?
答案相关性衡量的是:答案和问题有没有对上,答非所问了吗?
问题:苹果公司是哪年成立的?
答案A:苹果公司成立于1976年。← ✅ 高相关
答案B:苹果公司是一家美国科技公司。← 🟡 中等相关(提到了苹果,但没回答成立年份)
答案C:橙子是富含维生素C的水果。← ❌ 不相关
评估方法
class AnswerRelevanceEvaluator:
"""答案相关性评估"""
def __init__(self, llm_client, embedding_model=None):
self.llm = llm_client
self.embedding = embedding_model
def evaluate(
self,
question: str,
answer: str
) -> dict:
"""
评估答案相关性
核心思路:
1. 根据问题和答案,生成多个等价问题
2. 如果答案真的相关,它应该能回答这些等价问题
3. 计算等价问题的回答质量
"""
# 1️⃣ 生成等价问题
equivalent_questions = self._generate_equivalent_questions(
question, answer
)
# 2️⃣ 计算相似度
if self.embedding:
similarities = self._calculate_embedding_similarity(
answer, equivalent_questions
)
else:
similarities = self._calculate_keyword_similarity(
answer, equivalent_questions
)
# 3️⃣ 综合评分
score = sum(similarities) / len(similarities)
return {
'score': score,
'equivalent_questions': equivalent_questions,
'similarities': similarities,
'relevance_level': self._get_level(score)
}
def _generate_equivalent_questions(
self,
question: str,
answer: str
) -> list:
"""生成问题的等价表述"""
prompt = f"""基于以下问题和答案,生成3-5个与原问题语义等价但表达不同的问法。
原问题:{question}
答案:
{answer}
要求:
1. 生成的问题应该能够被同样的答案回答
2. 使用不同的词汇和句式
3. 每个问题一行
等价问题:"""
result = self.llm.generate(prompt)
questions = [q.strip() for q in result.split('\n') if q.strip()]
return questions[:5]
def _calculate_keyword_similarity(
self,
answer: str,
questions: list
) -> list:
"""基于关键词计算相似度"""
answer_keywords = set(answer.lower().split())
similarities = []
for q in questions:
q_keywords = set(q.lower().split())
if not q_keywords:
similarities.append(0)
continue
overlap = len(answer_keywords & q_keywords)
similarity = overlap / len(q_keywords)
similarities.append(similarity)
return similarities四、Context Precision与Recall
Context Precision(上下文精确度)
问:上下文里有多少是真正有用的?
假设你检索到了10个文档块
但只有3个和问题真正相关
Context Precision = 3/10 = 0.3 (30%)
class ContextPrecisionEvaluator:
"""上下文精确度评估"""
def __init__(self, llm_client):
self.llm = llm_client
def evaluate(
self,
question: str,
contexts: list
) -> dict:
"""
评估上下文精确度
Context Precision = 相关文档数 / 总文档数
"""
if not contexts:
return {'score': 0, 'precision': 0, 'details': []}
# 评估每个上下文的相关性
relevance_scores = []
for i, ctx in enumerate(contexts):
relevance = self._assess_relevance(question, ctx)
relevance_scores.append({
'context_id': i,
'context_preview': ctx[:100] + '...',
'relevance': relevance,
'is_relevant': relevance >= 0.5
})
# 计算精确度
relevant_count = sum(1 for r in relevance_scores if r['is_relevant'])
precision = relevant_count / len(contexts)
return {
'score': precision,
'precision': precision,
'relevant_count': relevant_count,
'total_count': len(contexts),
'details': relevance_scores
}
def _assess_relevance(self, question: str, context: str) -> float:
"""评估单个上下文的 relevance"""
prompt = f"""评估以下上下文对于回答问题的相关程度。
问题:{question}
上下文:
{context}
评分标准(0-1):
- 1.0: 上下文直接包含回答问题所需的关键信息
- 0.7: 上下文包含大部分相关信息
- 0.5: 上下文包含部分相关信息
- 0.3: 上下文相关度较低
- 0.0: 上下文与问题完全无关
相关度评分(只输出数字0-1):"""
try:
result = self.llm.generate(prompt).strip()
return float(result)
except:
return 0.5Context Recall(上下文召回率)
问:回答问题需要的信息,上下文覆盖了多少?
问题需要的信息点:
1. 苹果公司成立年份 ✓(上下文有)
2. 创始人名字 ✓(上下文有)
3. 公司总部位置 ✗(上下文没有)
Context Recall = 2/3 = 0.67 (67%)
class ContextRecallEvaluator:
"""上下文召回率评估"""
def __init__(self, llm_client):
self.llm = llm_client
def evaluate(
self,
contexts: list,
ground_truth: str
) -> dict:
"""
评估上下文召回率
Context Recall = 上下文覆盖的ground truth信息点 / 总信息点
"""
if not contexts:
return {'score': 0, 'recall': 0, 'details': []}
# 合并上下文
combined_context = '\n\n'.join(contexts)
# 提取ground truth中的关键信息点
gt_key_points = self._extract_key_points(ground_truth)
# 检查每个信息点是否被覆盖
covered_points = []
uncovered_points = []
for point in gt_key_points:
if self._is_covered(point, combined_context):
covered_points.append(point)
else:
uncovered_points.append(point)
recall = len(covered_points) / len(gt_key_points) if gt_key_points else 0
return {
'score': recall,
'recall': recall,
'total_points': len(gt_key_points),
'covered_points': covered_points,
'uncovered_points': uncovered_points,
'coverage_ratio': f"{len(covered_points)}/{len(gt_key_points)}"
}
def _extract_key_points(self, text: str) -> list:
"""提取关键信息点"""
prompt = f"""从以下文本中提取所有关键信息点。
文本:
{text}
要求:
1. 提取具体的事实、数据、定义
2. 每个信息点一行
3. 不要提取通用描述
关键信息点:"""
result = self.llm.generate(prompt)
points = [p.strip() for p in result.split('\n') if p.strip()]
return points五、RAGAS评估框架
RAGAS是什么?
RAGAS(Retrieval Augmented Generation Assessment)是2023年提出的RAG系统评估标准框架,提供了一套完整的评估指标:
┌─────────────────────────────────────────────────────────────┐
│ RAGAS评估体系 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📊 Faithfulness(忠实度) │
│ └─ 答案有多少内容被上下文支持? │
│ │
│ 📊 Answer Relevance(答案相关性) │
│ └─ 答案和问题有多相关? │
│ │
│ 📊 Context Precision(上下文精确度) │
│ └─ 检索到的内容有多少相关? │
│ │
│ 📊 Context Recall(上下文召回率)[需ground truth] │
│ └─ 需要的信息召回了多少? │
│ │
└─────────────────────────────────────────────────────────────┘
RAGAS完整实现
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class RAGASResult:
"""RAGAS评估结果"""
faithfulness: float
answer_relevance: float
context_precision: float
context_recall: Optional[float]
overall_score: float
class RAGASEvaluator:
"""RAGAS评估框架"""
def __init__(
self,
llm_client,
embedding_model=None
):
self.llm = llm_client
self.embedding = embedding_model
self.faithfulness_eval = FaithfulnessEvaluator(llm_client)
self.relevance_eval = AnswerRelevanceEvaluator(llm_client, embedding_model)
self.precision_eval = ContextPrecisionEvaluator(llm_client)
self.recall_eval = ContextRecallEvaluator(llm_client)
def evaluate(
self,
question: str,
answer: str,
contexts: List[str],
ground_truth: str = None
) -> RAGASResult:
"""完整RAGAS评估"""
# 1️⃣ Faithfulness
faithfulness_result = self.faithfulness_eval.evaluate(
question, '\n\n'.join(contexts), answer
)
faithfulness = faithfulness_result['score']
# 2️⃣ Answer Relevance
relevance_result = self.relevance_eval.evaluate(question, answer)
answer_relevance = relevance_result['score']
# 3️⃣ Context Precision
precision_result = self.precision_eval.evaluate(question, contexts)
context_precision = precision_result['precision']
# 4️⃣ Context Recall(需要ground truth)
context_recall = None
if ground_truth:
recall_result = self.recall_eval.evaluate(contexts, ground_truth)
context_recall = recall_result['recall']
# 5️⃣ Overall Score
overall = self._calculate_overall(
faithfulness,
answer_relevance,
context_precision,
context_recall
)
return RAGASResult(
faithfulness=faithfulness,
answer_relevance=answer_relevance,
context_precision=context_precision,
context_recall=context_recall,
overall_score=overall
)
def _calculate_overall(
self,
faithfulness: float,
answer_relevance: float,
context_precision: float,
context_recall: Optional[float]
) -> float:
"""计算综合分数"""
# 无ground truth时
if context_recall is None:
return (0.4 * faithfulness +
0.3 * answer_relevance +
0.3 * context_precision)
# 有ground truth时
return (0.35 * faithfulness +
0.25 * answer_relevance +
0.2 * context_precision +
0.2 * context_recall)批量评估与报告
class BatchRAGASEvaluator:
"""批量RAGAS评估"""
def __init__(self, evaluator: RAGASEvaluator):
self.evaluator = evaluator
def evaluate_dataset(
self,
test_cases: List[dict]
) -> dict:
"""
批量评估测试集
test_cases格式:
{
'question': str,
'answer': str,
'contexts': List[str],
'ground_truth': Optional[str]
}
"""
results = []
for i, case in enumerate(test_cases):
try:
result = self.evaluator.evaluate(
question=case['question'],
answer=case['answer'],
contexts=case['contexts'],
ground_truth=case.get('ground_truth')
)
results.append({
'case_id': i,
'success': True,
'result': result
})
except Exception as e:
results.append({
'case_id': i,
'success': False,
'error': str(e)
})
# 汇总统计
successful_results = [r['result'] for r in results if r['success']]
if successful_results:
stats = {
'faithfulness': np.mean([r.faithfulness for r in successful_results]),
'answer_relevance': np.mean([r.answer_relevance for r in successful_results]),
'context_precision': np.mean([r.context_precision for r in successful_results]),
'overall_score': np.mean([r.overall_score for r in successful_results])
}
else:
stats = {}
return {
'total_cases': len(test_cases),
'successful': len(successful_results),
'failed': len(test_cases) - len(successful_results),
'stats': stats,
'detailed_results': results
}
def generate_report(self, results: dict) -> str:
"""生成评估报告"""
stats = results['stats']
return f"""
# RAG系统评估报告
## 评估概览
- 测试用例总数:{results['total_cases']}
- 成功评估:{results['successful']}
- 失败评估:{results['failed']}
## 核心指标
| 指标 | 平均分数 | 评估 |
|------|---------|------|
| Faithfulness(忠实度) | {stats.get('faithfulness', 0):.3f} | {'✓' if stats.get('faithfulness', 0) > 0.7 else '✗'} |
| Answer Relevance(相关性) | {stats.get('answer_relevance', 0):.3f} | {'✓' if stats.get('answer_relevance', 0) > 0.6 else '✗'} |
| Context Precision(精确度) | {stats.get('context_precision', 0):.3f} | {'✓' if stats.get('context_precision', 0) > 0.5 else '✗'} |
| Overall Score(综合分) | {stats.get('overall_score', 0):.3f} | - |
## 改进建议
{self._generate_recommendations(stats)}
---
*报告生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
"""
def _generate_recommendations(self, stats: dict) -> str:
"""生成改进建议"""
recommendations = []
if stats.get('faithfulness', 0) < 0.7:
recommendations.append(
"1. **提升忠实度**:检查上下文是否充分支持生成内容"
)
if stats.get('answer_relevance', 0) < 0.6:
recommendations.append(
"2. **提升答案相关性**:优化检索策略,确保检索到更相关的内容"
)
if stats.get('context_precision', 0) < 0.5:
recommendations.append(
"3. **提升上下文精确度**:使用更精细的重排和过滤机制"
)
if not recommendations:
recommendations.append("✓ 系统表现良好,继续保持当前策略。")
return "\n".join(recommendations)六、幻觉检测
什么是幻觉?
幻觉就是AI编造了上下文中不存在的信息:
上下文:苹果公司成立于1976年,总部位于加州库比蒂诺。
幻觉例子:
❌ "苹果公司成立于1975年"(年份错误)
❌ "苹果公司总部在纽约"(地点错误)
❌ "乔布斯是苹果公司唯一的创始人"(遗漏创始人)
非幻觉例子:
✓ "苹果公司成立于1976年"(正确引用)
✓ "苹果公司由多人创立"(正确泛化)
Self-RAG检测法
Self-RAG通过自我反思来检测幻觉:
class SelfRAGDetector:
"""Self-RAG幻觉检测"""
def __init__(self, llm_client):
self.llm = llm_client
def detect_hallucination(
self,
context: str,
answer: str
) -> dict:
"""
检测幻觉
核心思路:
1. 从答案中提取所有事实声明
2. 逐个验证是否被上下文支持
3. 计算幻觉率
"""
# 1️⃣ 提取声明
claims = self._extract_factual_claims(answer)
# 2️⃣ 逐个验证
verified_claims = []
hallucinated_claims = []
for claim in claims:
is_hallucinated, confidence = self._verify_claim(claim, context)
if is_hallucinated:
hallucinated_claims.append({
'claim': claim,
'confidence': confidence,
'severity': self._assess_severity(claim, confidence)
})
else:
verified_claims.append(claim)
# 3️⃣ 计算幻觉率
hallucination_rate = len(hallucinated_claims) / len(claims) if claims else 0
return {
'hallucination_rate': hallucination_rate,
'total_claims': len(claims),
'verified_claims': verified_claims,
'hallucinated_claims': hallucinated_claims,
'risk_level': 'High' if hallucination_rate > 0.3 else 'Medium' if hallucination_rate > 0.1 else 'Low'
}
def _extract_factual_claims(self, text: str) -> list:
"""提取事实声明"""
prompt = f"""从以下文本中提取所有可验证的事实声明。
忽略观点、感受、通用描述。
文本:
{text}
每个声明一行:"""
result = self.llm.generate(prompt)
return [c.strip() for c in result.split('\n') if c.strip()]
def _verify_claim(
self,
claim: str,
context: str
) -> tuple:
"""
验证声明
返回:(是否幻觉, 置信度)
"""
prompt = f"""判断以下声明是否与上下文一致。
声明:{claim}
上下文:
{context}
判断:
A. 完全一致 - 上下文明确支持
B. 基本一致 - 上下文暗示或可推断
C. 不确定 - 上下文未提及
D. 不一致 - 上下文与声明矛盾
判断结果和置信度(0-1):"""
result = self.llm.generate(prompt)
if "A. 完全一致" in result or "完全一致" in result:
return False, 0.95
elif "B. 基本一致" in result or "基本一致" in result:
return False, 0.75
elif "D. 不一致" in result or "不一致" in result:
return True, 0.9
else:
return True, 0.5 # 不确定视为可能的幻觉无参考幻觉检测(Self-CheckGPT风格)
有时候我们没有参考上下文,这时候可以用自洽性检测:
class SelfConsistencyChecker:
"""自洽性检测(无参考幻觉检测)"""
def __init__(self, llm_client):
self.llm = llm_client
def check(
self,
answer: str,
question: str = None
) -> dict:
"""
无参考幻觉检测
通过检测答案内部的一致性来判断可靠性
"""
# 1️⃣ 提取关键陈述
statements = self._extract_statements(answer)
# 2️⃣ 检查自洽性
consistency = self._check_self_consistency(statements)
# 3️⃣ 检测过度自信
overconfidence = self._detect_overconfidence(answer)
# 4️⃣ 综合评分
risk_score = self._calculate_risk(
consistency, overconfidence
)
return {
'risk_score': risk_score,
'risk_level': 'High' if risk_score > 0.5 else 'Medium' if risk_score > 0.2 else 'Low',
'consistency_score': consistency,
'overconfidence_detected': overconfidence,
'statements_checked': len(statements)
}
def _extract_statements(self, text: str) -> list:
"""提取关键陈述"""
import re
sentences = re.split(r'[。!?\n]', text)
return [s.strip() for s in sentences if s.strip() and len(s) > 10]
def _check_self_consistency(self, statements: list) -> float:
"""检查自洽性"""
if len(statements) < 2:
return 1.0
prompt = f"""分析以下陈述之间是否存在逻辑矛盾。
陈述列表:
{chr(10).join([f"{i+1}. {s}" for i, s in enumerate(statements)])}
判断:
- 如果所有陈述逻辑一致,返回"一致"
- 如果存在矛盾,指出矛盾之处
分析结果:"""
result = self.llm.generate(prompt)
if "一致" in result:
return 1.0
elif "矛盾" in result or "冲突" in result:
return 0.3
else:
return 0.7
def _detect_overconfidence(self, answer: str) -> dict:
"""检测过度自信"""
overconfidence_markers = [
'绝对', '肯定', '一定', '毫无疑问',
'所有人', '绝对不会', '100%', '必然'
]
found = [m for m in overconfidence_markers if m in answer]
return {
'markers_found': found,
'count': len(found),
'is_suspicious': len(found) > 2
}
def _calculate_risk(
self,
consistency: float,
overconfidence: dict
) -> float:
"""计算风险分数"""
score = consistency
if overconfidence['is_suspicious']:
score *= 0.8
return max(0, min(1, score))七、实战评估流程
完整评估流程示例
def evaluate_rag_system(
rag_system,
test_questions: list,
ground_truths: list = None
):
"""
完整的RAG系统评估流程
"""
# 1️⃣ 初始化评估器
evaluator = RAGASEvaluator(llm_client, embedding_model)
hallucination_detector = SelfRAGDetector(llm_client)
results = []
for i, question in enumerate(test_questions):
# 2️⃣ 获取RAG响应
response = rag_system.query(question)
answer = response['answer']
contexts = response['contexts']
# 3️⃣ Faithfulness评估
faithfulness = evaluator.faithfulness_eval.evaluate(
question, '\n\n'.join(contexts), answer
)
# 4️⃣ 幻觉检测
hallucination = hallucination_detector.detect_hallucination(
'\n\n'.join(contexts), answer
)
# 5️⃣ 答案相关性
relevance = evaluator.relevance_eval.evaluate(question, answer)
results.append({
'question': question,
'faithfulness': faithfulness['score'],
'hallucination_rate': hallucination['hallucination_rate'],
'answer_relevance': relevance['score'],
'contexts': contexts
})
# 6️⃣ 生成报告
batch_evaluator = BatchRAGASEvaluator(evaluator)
report = batch_evaluator.generate_report({'stats': {
'faithfulness': np.mean([r['faithfulness'] for r in results]),
'answer_relevance': np.mean([r['answer_relevance'] for r in results]),
}})
return report, results一图总结
┌─────────────────────────────────────────────────────────────┐
│ 上下文质量评估速查表 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 📊 四大评估维度 │
│ ├─ Faithfulness:有没有瞎编? │
│ ├─ Answer Relevance:答非所问? │
│ ├─ Context Precision:检索了多少垃圾? │
│ └─ Context Recall:关键信息漏了多少? │
│ │
│ 🔍 幻觉检测 │
│ ├─ Self-RAG:有参考,逐个验证 │
│ └─ Self-CheckGPT:无参考,自洽性检测 │
│ │
│ 📈 评估流程 │
│ 1. 提取声明/关键陈述 │
│ 2. 逐个验证/检查自洽性 │
│ 3. 计算分数/比率 │
│ 4. 生成报告/改进建议 │
│ │
└─────────────────────────────────────────────────────────────┘
相关主题
- RAG上下文优化指南 - 如何优化上下文质量
- 上下文压缩技术 - 压缩时如何保持质量
- 上下文缓存 - 缓存与质量的平衡
参考文献
- Es, S., et al. (2023). RAGAS: Automated Evaluation of Retrieval Augmented Generation. arXiv.
- Manakul, P., et al. (2023). SelfCheckGPT: Zero-Resource Black-Box Hallucination Detection in Generated Text. arXiv.
- Shi, W., et al. (2023). Augmenting Language Models with Plug-in Memory. arXiv.