资讯动态

三AI考官协作打分:让RAG评估从拍脑袋到有数可依

发布时间:2026/10/25 16:35:00 来源:尧图企业网站定制
1. 为什么单考官打分不靠谱做过 RAG 评估的人大概都有这种体验你精心搭了一套检索增强生成流程召回率看着不错生成的内容也像模像样但真到了要判断“这次改动到底有没有让系统变好”的时候就抓瞎了。上一版回答和这一版回答摆在一起肉眼看着都挺对可到底哪个更准、哪个更全、哪个更少胡说八道谁也说不清。这就是 RAG 评估最核心的痛点生成质量是一个多维度的模糊概念单一指标或者单一评判者根本覆盖不了。你用 BLEU、ROUGE 这类传统指标去算它们只能衡量字面重叠度对于“意思对了但措辞不同”的情况直接判低分误杀率极高。你换用单个 LLM 当裁判又会遇到另一个问题——每个模型都有自己的偏好和盲区。有的模型偏爱长回答看到字数多就给高分有的模型对格式敏感回答里没有分点列举就扣分还有的模型在特定领域知识上存在系统性偏差你让它评判它不熟悉的领域它给出的分数基本是噪声。我在实际项目里就踩过这个坑。当时用单个模型给一批问答对打分跑出来的分数分布特别集中几乎全在 7 到 9 分之间区分度极差。后来换了另一个模型重新评同一批数据的分差直接拉大到 3 到 9 分。这说明什么说明单考官打出来的分数很大程度上反映的是考官的偏好而不是被评估系统的真实水平。所以这一篇要解决的问题很明确怎么用三个 AI 考官协作打分把 RAG 评估从“拍脑袋”变成“有数可依”。我会把整套方案的选型逻辑、提示词设计、分数聚合方法、以及实操中遇到的坑全部拆开讲清楚。适合正在做 RAG 系统迭代、需要量化评估来指导优化的朋友参考也适合对 LLM 评估方法论感兴趣的同学。2. 三考官评估体系的整体设计2.1 为什么是三个而不是两个或五个三个考官这个数字不是拍脑袋定的。我从两个角度来论证这个选择。从统计学角度看评估的本质是在估计一个“真实质量分数”。单个考官的评分可以看作一次带噪声的观测多个考官的评分取平均可以降低噪声。但考官数量不是越多越好——每增加一个考官成本线性增长而噪声降低的边际收益递减。两个考官的问题在于当两人打分出现分歧时你没有第三方来打破平局最终还是要靠人来裁决自动化程度不够。三个考官则可以在多数情况下通过多数表决或者中位数聚合得到稳定结果同时在成本上仍然可控。从评估维度覆盖角度看RAG 生成质量至少包含三个核心维度忠实度回答是否基于检索到的上下文有没有编造、相关性回答是否切题有没有答非所问、完整性回答是否覆盖了问题的所有关键点。让一个考官同时评三个维度它很容易顾此失彼或者把多个维度混在一起给一个笼统的分数。让三个考官各自聚焦一个维度每个考官的评判标准更清晰打分也更稳定。注意三个考官不一定是三个不同的模型。你也可以用同一个模型配合三套不同的提示词分别引导它从忠实度、相关性、完整性三个角度评判。但实测下来用不同模型做考官评分多样性更好能捕捉到单一模型忽略的问题。2.2 考官角色的分工与提示词设计三个考官的分工如下考官编号角色定位核心评判维度推荐模型类型考官 A事实核查员忠实度回答是否完全基于检索上下文推理能力强的模型考官 B用户代言人相关性回答是否直接解决了用户问题指令遵循好的模型考官 C质量审计员完整性回答是否覆盖所有关键信息点知识面广的模型每个考官的提示词设计遵循同一个骨架角色设定 评分标准 评分范围 输出格式约束。以考官 A 为例提示词的核心部分是这样的EXAMINER_A_PROMPT 你是一个严格的事实核查员。你的任务是判断【回答】中的每一句话是否都能在【检索上下文】中找到依据。 评分标准 - 10分回答中所有事实性陈述都能在上下文中找到直接依据无任何编造。 - 7-9分回答基本忠实但有1-2处细节与上下文有轻微出入。 - 4-6分回答中有明显编造内容但核心信息仍来自上下文。 - 1-3分回答大量编造或与上下文矛盾。 - 0分回答完全脱离上下文。 请先逐句分析回答中的事实性陈述然后给出最终分数。输出格式 分析过程... 最终分数X 这个提示词的关键设计点在于要求考官先分析再打分。我试过直接让模型输出分数结果发现模型经常“偷懒”给一个中间分就完事。强制它先逐句分析相当于让它把推理过程展开分数就有了依据可解释性也强很多。考官 B 的提示词侧重相关性核心问题是“这个回答如果给到提问的用户用户会觉得被回答了还是被敷衍了”。考官 C 的提示词侧重完整性要求它先列出问题涉及的关键信息点再逐一检查回答是否覆盖。2.3 分数聚合策略从三个分数到一个决策三个考官各自打分之后怎么合成一个最终结论这里有好几种策略我逐一分析利弊。策略一简单平均。把三个分数加起来除以三。优点是简单缺点是当三个考官分歧很大时比如 3、6、9平均值 6 分完全掩盖了分歧本身。而分歧大恰恰说明这个样本值得人工复核。策略二中位数。取三个分数的中间值。这个策略对异常值更鲁棒比如一个考官给了极端低分中位数能把它拉回来。但缺点是丢失了“分歧程度”这个信息。策略三加权平均 分歧标记。给每个考官设一个权重比如事实核查员权重 0.5另外两个各 0.25同时计算三个分数的标准差。标准差超过阈值就标记为“需人工复核”。这是我目前最推荐的策略既给出了综合分又保留了分歧信号。import numpy as np def aggregate_scores(score_a, score_b, score_c, weights(0.5, 0.25, 0.25)): scores np.array([score_a, score_b, score_c]) weighted_avg np.average(scores, weightsweights) std np.std(scores) needs_review std 2.0 return { final_score: round(weighted_avg, 2), std: round(std, 2), needs_review: needs_review }这个聚合函数跑下来大部分样本的标准差在 1 以内说明三个考官的一致性还不错。标准差超过 2 的样本大约占 10% 到 15%这些就是最值得人工去看的“争议样本”。3. 实操环境搭建与核心代码实现3.1 环境准备与依赖安装整套评估流程基于 Python 生态核心依赖包括 LangChain 用于编排评估链、openevals 用于标准化评估接口、以及至少两个不同厂商的 LLM API 用于充当考官。pip install langchain langchain-openai openevals pandas numpy tqdm如果你用的是本地模型可以通过 Ollama 或者 vLLM 起一个兼容 OpenAI 接口的服务然后在 LangChain 里用ChatOpenAI指向本地地址即可。我实测下来本地 7B 级别的模型做考官在忠实度判断上已经够用但在完整性判断上跟大模型还有明显差距。如果预算允许建议至少有一个考官用能力更强的模型。3.2 评估数据集的准备评估数据集的质量直接决定评估结果的可信度。一个合格的 RAG 评估集至少包含以下字段字段名说明示例question用户原始问题“LangChain 的 Memory 组件有哪些类型”context检索到的上下文从知识库召回的文档片段answer待评估的回答RAG 系统生成的回答reference参考答案可选人工撰写的标准答案我建议评估集规模至少 50 条覆盖不同类型的问题事实型、对比型、推理型、多跳型。如果评估集太小分数波动会很大今天跑 7.2 明天跑 7.5你根本分不清是系统改进了还是随机波动。import pandas as pd eval_data pd.read_json(eval_dataset.jsonl, linesTrue) print(f评估集大小{len(eval_data)}) print(eval_data[[question, answer]].head())3.3 三考官并行评估的实现串行调用三个考官太慢50 条数据乘以 3 个考官就是 150 次 API 调用按每次 3 秒算要跑将近 8 分钟。用并发可以把时间压到 3 分钟左右。from concurrent.futures import ThreadPoolExecutor from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate def create_examiner(model_name, prompt_template): llm ChatOpenAI(modelmodel_name, temperature0) prompt ChatPromptTemplate.from_template(prompt_template) return prompt | llm examiner_a create_examiner(gpt-4o, EXAMINER_A_PROMPT) examiner_b create_examiner(claude-3-5-sonnet, EXAMINER_B_PROMPT) examiner_c create_examiner(gpt-4o-mini, EXAMINER_C_PROMPT) def evaluate_single(row): inputs { question: row[question], context: row[context], answer: row[answer] } result_a examiner_a.invoke(inputs) result_b examiner_b.invoke(inputs) result_c examiner_c.invoke(inputs) return { score_a: parse_score(result_a.content), score_b: parse_score(result_b.content), score_c: parse_score(result_c.content), raw_a: result_a.content, raw_b: result_b.content, raw_c: result_c.content } with ThreadPoolExecutor(max_workers5) as executor: results list(executor.map(evaluate_single, eval_data.to_dict(records)))这里有个细节要注意temperature0是必须的。评估任务需要的是稳定、可复现的判断不是创意写作。温度调高会让同一个样本在不同运行中拿到不同分数评估就失去了意义。3.4 分数解析与结果落盘LLM 输出的分数格式可能五花八门有的写“最终分数8”有的写“Final Score: 8/10”还有的会在分析过程中提到其他数字。解析函数要足够健壮。import re def parse_score(text): patterns [ r最终分数[:]\s*(\d(?:\.\d)?), rFinal Score[:]\s*(\d(?:\.\d)?), r分数[:]\s*(\d(?:\.\d)?) ] for pattern in patterns: match re.search(pattern, text) if match: return float(match.group(1)) return None解析失败的样本要单独记录下来不能直接丢弃。我遇到过大约 3% 的样本解析失败检查后发现是模型在输出里用了全角冒号或者加了额外空格。把解析规则补全之后失败率降到 0.5% 以下。结果落盘用 JSONL 格式每行一条记录包含原始输入、三个考官的原始输出、解析后的分数、聚合分数和分歧标记。这样后续做错误分析的时候可以随时回溯到原始输出。4. 评估结果的分析与问题排查4.1 分数分布分析与系统诊断拿到评估结果之后第一步是看分数分布。如果所有样本的分数都集中在 8 到 10 分说明评估集太简单或者考官太宽松需要调整。如果分数分布呈现双峰说明系统在某些类型的问题上表现好在另一些类型上表现差需要进一步拆解。import matplotlib.pyplot as plt df pd.DataFrame(results) df[final_score] df.apply(lambda r: aggregate_scores( r[score_a], r[score_b], r[score_c])[final_score], axis1) df[final_score].hist(bins10, range(0, 10)) plt.xlabel(综合评分) plt.ylabel(样本数量) plt.title(RAG 系统综合评分分布) plt.show()我最近一次评估的结果是平均分 7.3标准差 1.8分布大致呈正态但左尾略长。左尾那些低分样本我逐条看了原始输出发现主要问题集中在两类一是检索上下文本身不包含答案模型硬编了一个二是问题涉及多个文档的交叉信息模型只用了其中一个文档就作答。4.2 考官分歧的典型模式与处理三个考官打分不一致的情况我总结了几种典型模式分歧模式表现可能原因处理建议A低B高C高事实核查员给低分另两个给高分回答流畅但存在编造优先信任考官A人工复核A高B低C高用户代言人给低分回答事实正确但答非所问检查问题理解是否有偏差A高B高C低质量审计员给低分回答正确但遗漏关键点检查检索召回是否充分三者都低一致低分系统在该样本上确实失败作为 bad case 重点分析这个表格是我踩了很多坑之后总结出来的。最开始我不理解为什么考官A和考官B会给出截然不同的分数后来把原始输出调出来看才明白考官A关注的是“说的对不对”考官B关注的是“说的有没有用”这两个维度确实可能背离。一个回答可以做到每句话都有依据但完全没回答用户的问题也可以做到切题但夹杂编造。4.3 常见报错与排查速查表在实际跑评估的过程中我遇到过的报错和解决方法整理如下报错信息可能原因解决方法RateLimitErrorAPI 调用频率超限降低并发数加指数退避重试ContextLengthExceeded检索上下文太长截断上下文或换用长上下文模型JSONDecodeError模型输出不是合法 JSON改用正则解析或在提示词中强制 JSON 格式分数解析为 None输出格式不符合预期补充解析规则记录原始输出人工检查评估结果波动大temperature 未设为 0检查所有考官的温度参数提示如果评估结果在不同运行之间波动超过 0.5 分优先检查 temperature 设置和模型版本是否一致。我有一次评估结果突然整体下降 1 分排查半天发现是 API 提供方悄悄更新了模型版本。4.4 从评估结果到系统优化的闭环评估本身不是目的驱动优化才是。我的做法是每次评估后把低分样本和争议样本单独导出按问题类型归类然后针对性地调整检索策略或生成提示词。比如有一轮评估发现“多跳问题”的完整性分数普遍偏低原因是检索只召回了单跳相关的文档。后来在检索阶段加了查询改写把多跳问题拆成多个子查询分别检索再合并完整性分数从 5.8 提升到 7.4。这个提升是实打实测出来的不是感觉出来的。low_score_samples df[df[final_score] 6.0] disputed_samples df[df[std] 2.0] print(f低分样本数{len(low_score_samples)}) print(f争议样本数{len(disputed_samples)}) low_score_samples.to_json(low_score_cases.jsonl, orientrecords, linesTrue) disputed_samples.to_json(disputed_cases.jsonl, orientrecords, linesTrue)这两个文件就是下一轮优化的输入。低分样本告诉你系统在哪里失败争议样本告诉你评估体系本身在哪里需要校准。5. 成本控制与评估频率的平衡5.1 三考官方案的成本估算三个考官意味着三倍的 API 调用成本。以 50 条评估集为例每条数据三个考官各调用一次总共 150 次调用。如果每次调用平均消耗 2000 token输入加输出总 token 消耗约 30 万。按主流模型的价格算一轮评估的成本在几块钱到几十块钱之间取决于你用的模型档次。这个成本对于迭代期的项目来说完全可以接受。但如果你每天跑十轮评估成本就会累积。我的建议是全量评估每周跑一到两次日常迭代用抽样评估。抽样评估从评估集里随机抽 20 条成本降到全量的 40%但分数趋势仍然能看出来。5.2 考官模型的选型权衡不是所有考官都需要用最贵的模型。我的实测经验是考官 A事实核查需要较强的推理能力建议用能力强的模型。忠实度判断涉及逐句比对弱模型容易漏判。考官 B相关性对模型能力要求相对低中等模型即可胜任。相关性判断更多是语义匹配不需要复杂推理。考官 C完整性需要一定的知识面建议用中等偏上的模型。太弱的模型自己都不知道问题涉及哪些关键点没法判断回答是否完整。这样搭配下来成本比三个考官都用最强模型降低约 40%而评估结果的一致性用标准差衡量只下降了不到 10%。5.3 评估流水线的自动化集成评估不应该是一个手动触发的脚本而应该集成到 CI/CD 流程里。我的做法是每次 RAG 系统的提示词或检索策略有变更自动触发一轮抽样评估评估结果写入数据库并在变更记录里附上分数对比。def run_evaluation_and_log(config_version): results run_full_evaluation() summary { version: config_version, timestamp: datetime.now().isoformat(), avg_score: results[final_score].mean(), std: results[final_score].std(), low_score_count: len(results[results[final_score] 6.0]) } log_to_database(summary) return summary这样每次改动都有据可查回滚的时候也知道回滚到哪个版本分数最高。我吃过一次亏改了一版提示词感觉回答变好了直接上线结果一周后用户反馈变差。回头想对比改之前的分数发现根本没记录只能凭记忆。从那以后评估结果全部落库。6. 几个容易踩的坑和实操心得第一个坑是评估集泄漏。如果你用评估集里的样本去调提示词调完之后再拿同一个评估集去评分数肯定虚高。正确的做法是评估集分两份一份用于日常迭代参考一份作为“测试集”只在最终验收时用。测试集不能用来调参。第二个坑是考官提示词过拟合。我一开始为了让考官给出符合预期的分数反复调整提示词里的评分标准描述结果考官确实按我想要的分布打分了但那个分布是我主观期望的不是真实质量分布。后来我把提示词固定下来不再根据评估结果去调考官评估才变得可信。第三个坑是忽略检索质量对生成评估的干扰。RAG 系统的最终回答质量受检索和生成两个环节影响。如果检索没召回相关文档生成环节再强也答不好。所以在评估生成质量的同时要单独评估检索的召回率和准确率。否则你看到生成分数低以为是生成模型的问题拼命调生成提示词实际上问题出在检索。提示建议把检索评估和生成评估分开跑。检索评估用召回率、MRR、NDCG 这些指标生成评估用三考官方案。两者结合才能定位问题到底出在哪个环节。第四个心得是保留原始输出。聚合分数只是最终结论但排查问题时你需要看考官的分析过程。我遇到过好几次聚合分数正常但考官分析过程里已经指出了潜在问题的情况。如果只存分数不存原始输出这些信号就丢了。最后分享一个实用技巧给考官加一个“不确定”选项。当考官觉得信息不足以判断时允许它输出“无法判断”而不是强行给一个中间分。这样可以把真正模糊的样本筛出来而不是让它们污染分数分布。我加了“不确定”选项之后大约 5% 的样本被标记为不确定这些样本人工复核后发现确实大部分是边界情况强行打分没有意义。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑