RAGAS 框架与实现原理
RAGAS 框架与实现原理
写在前面
学习 RAG 评测,RAGAS 是绝对绕不开的主流框架。它基于LLM-as-a-Judge(大模型当裁判)的核心范式,既解决了人工评测效率低、难规模化的问题,又比传统关键词匹配的评测方式更懂语义,是目前工业界 RAG 效果评估的标配工具。
很多同学入门时会遇到两个痛点:一是 RAGAS 版本迭代快,网上教程的 API 很容易过时;二是只知道指标名字,搞不懂分数到底是怎么算出来的。这篇笔记就从整体流程、核心原理、可运行代码三个维度,把 RAGAS 最核心的 5 个指标拆解清楚,同时标注了新手容易踩的版本、稳定性等坑点,跟着步骤就能跑通完整的 RAG 评测。
一、RAGAS 整体评估流程
RAGAS 的评估逻辑非常清晰,是标准的「输入 - 处理 - 输出」三段式结构,底层靠「大模型语义判断 + 向量相似度计算 + 数学统计」三者配合实现自动化评测。
1. 输入数据源(Input Data)
一次完整的评估最多需要 4 个核心元素,根据不同指标按需传入:
- Question(用户问题):用户提出的原始查询,是所有评估的基准
- Context(检索上下文):RAG 系统从向量库中召回的文档片段,对应检索环节的输出
- Answer(生成答案):大模型基于检索上下文生成的最终回答,对应生成环节的输出
- Ground Truth(标准答案):人工标注的参考正确答案,部分指标需要用到
2. 评估处理引擎(Evaluation Engine)
这是 RAGAS 的核心,三个组件协同工作:
- LLM 大模型:负责语义层面的判断,比如识别内容是否相关、拆解事实声明、检测幻觉
- Embedding 向量模型:负责文本向量化,计算语义相似度
- 计算引擎:负责执行 Precision、Recall、F1、MAP 等数学统计计算
3. 输出评估指标(Output Metrics)
最终输出 0~1 之间的量化分数,分数越高代表质量越好。核心覆盖 5 个高频指标,分别对应检索、生成、端到端三个环节,后面我们会逐个拆解。
二、环境准备(新手必看・避坑前置)
💡重点提示:RAGAS 版本差异非常大,高版本 API 改动很多,网上大部分教程的代码在最新版里都跑不通。教学和学习推荐锁定0.4.3 版本,稳定性和资料丰富度都最好。
1. 环境搭建步骤
# 1. 创建并进入项目目录 mkdir ragas_demo && cd ragas_demo # 2. 创建虚拟环境(推荐用uv,pip也可以) uv venv # 激活虚拟环境 # Linux/macOS source .venv/bin/activate # Windows .venv\Scripts\activate2. 依赖与配置
创建requirements.txt:
ragas==0.4.3 openai>=1.0.0 python-dotenv>=1.0.0安装依赖:
uv pip install -r requirements.txt创建.env配置文件,这里用阿里云通义千问的兼容 OpenAI 接口,国内学生不用翻墙就能用:
OPENAI_API_KEY=sk-你的API密钥 OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1💡模型选择建议:评估模型推荐用qwen3.6-plus,实测比高版本的 qwen3.7-max 打分更稳定,波动更小。
三、5 个核心指标逐一带练
1. Context Precision 上下文精准度
是什么
衡量检索系统的查准质量 + 排序质量,核心看两件事:召回的内容里有多少是真相关的,以及相关的内容有没有排在更靠前的位置。它是检索环节的核心指标,直接反映 “检索结果的信噪比高不高”。
计算原理
核心是Precision@k 加权平均,公式逻辑:
- 对每个位置 k,计算
Precision@k = 前k条中相关内容数 / k - 用每个位置的相关性标识
v_k(相关为 1,不相关为 0)做加权 - 最终得分 = 所有相关位置的 Precision@k 之和 ÷ 总相关内容数
📌 关键点:内容顺序对得分影响极大。相关内容越靠前,得分越高;哪怕相关内容总数一样,排在后面得分也会低很多。
代码实战
我们用 “北京故宫有哪些著名景点?” 做示例,故意混入一条无关内容:
importasyncioimportosfromopenaiimportAsyncOpenAIfromdotenvimportload_dotenvfromragas.llmsimportllm_factoryfromragas.metrics.collectionsimportContextPrecision load_dotenv()# 初始化大模型裁判openai_client=AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))llm=llm_factory("qwen3.6-plus",client=openai_client,temperature=0.1,# 调低温度,让打分更稳定seed=42# 固定种子,结果可复现)scorer=ContextPrecision(llm=llm)asyncdefmain():print("=== 上下文精准度评估 ===")result=awaitscorer.ascore(user_input="北京故宫有哪些著名景点?",reference="北京故宫的著名景点包括太和殿、乾清宫、御花园和角楼。",retrieved_contexts=["太和殿是故宫外朝的核心建筑,也是中国现存最大的木结构大殿。","乾清宫是明清两代皇帝的寝宫,位于故宫内廷。","御花园是故宫的皇家园林,位于中轴线北端。","杭州西湖是中国著名的淡水湖,有十景之称。"# 无关干扰项])print(f"得分:{result.value:.4f}")if__name__=="__main__":asyncio.run(main())手动演算验证
上面的例子中,前 3 条相关、最后 1 条无关:
| 位置 k | 内容 | 是否相关 | Precision@k |
|---|---|---|---|
| 1 | 太和殿 | 是 | 1/1 = 1.0 |
| 2 | 乾清宫 | 是 | 2/2 = 1.0 |
| 3 | 御花园 | 是 | 3/3 = 1.0 |
| 4 | 西湖 | 否 | 3/4 = 0.75 |
分子加权和 = 1.0 + 1.0 + 1.0 = 3.0分母总相关数 = 3最终得分 = 3.0 / 3 = 1.0实际运行得分会接近 1,LLM 可能会因为语义严苛度有微小扣减。
如果把无关内容放到第一位,得分会直接降到 0.6 左右,这也验证了排序对精准度的巨大影响。
2. Context Recall 上下文召回率
是什么
衡量检索系统的查全能力,核心看:回答这个问题需要的所有关键信息,有没有都被检索出来。它关注的是 “漏不漏”,和精准度刚好互补 —— 精准度怕掺假,召回率怕遗漏。
计算原理
采用「声明拆解法」,三步计算:
- 拆解声明:把标准答案拆成若干个独立的、不可拆分的事实陈述句(Claims)
- 匹配验证:拿着每一条声明,去检索上下文中找依据,判断是否能被支持
- 计算得分:得分 = 能被支持的声明数 ÷ 总声明数
代码实战
importasyncioimportosfromopenaiimportAsyncOpenAIfromdotenvimportload_dotenvfromragas.llmsimportllm_factoryfromragas.metrics.collectionsimportContextRecall load_dotenv()openai_client=AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))llm=llm_factory("qwen3.6-plus",client=openai_client,temperature=0.1,seed=42)scorer=ContextRecall(llm=llm)asyncdefmain():print("=== 上下文召回率评估 ===")result=awaitscorer.ascore(user_input="北京故宫有哪些著名景点?",reference="北京故宫的著名景点包括太和殿、乾清宫、御花园和角楼。",retrieved_contexts=["太和殿是故宫外朝的核心建筑。","乾清宫是明清两代皇帝的寝宫。","御花园是故宫的皇家园林。",# 缺少“角楼”相关内容])print(f"得分:{result.value:.4f}")if__name__=="__main__":asyncio.run(main())手动演算验证
标准答案可以拆成 4 条独立声明:
- 故宫有太和殿 ✅ 有依据
- 故宫有乾清宫 ✅ 有依据
- 故宫有御花园 ✅ 有依据
- 故宫有角楼 ❌ 无依据
总声明数 4,被支持的 3 个,得分 = 3/4 = 0.75运行结果会在 0.75 左右浮动,和我们的手动计算完全吻合。
3. Answer Relevancy 答案相关性
是什么
衡量生成的答案和用户问题的匹配程度,也就是 “有没有答非所问”。这个指标不需要标准答案,属于无参考评估,非常适合没有标注数据的场景。
计算原理
采用很巧妙的反向重构法,核心逻辑是:一个高质量的相关答案,一定能反向推导出用户原本的问题。三步计算:
- 用 LLM 根据生成答案,反向生成 N 个可能的用户问题
- 计算这些反向问题与原始问题的语义向量相似度
- 取所有相似度的平均值,作为最终得分
代码实战
importasyncioimportosfromopenaiimportAsyncOpenAIfromdotenvimportload_dotenvfromragas.llmsimportllm_factoryfromragas.embeddings.baseimportembedding_factoryfromragas.metrics.collectionsimportAnswerRelevancy load_dotenv()openai_client=AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))llm=llm_factory("qwen3.6-plus",client=openai_client,temperature=0.1,seed=42)# 用通义的向量模型计算相似度embeddings=embedding_factory("openai",model="text-embedding-v4",client=openai_client)scorer=AnswerRelevancy(llm=llm,embeddings=embeddings)asyncdefmain():print("=== 答案相关性评估 ===")# 相关答案测试result1=awaitscorer.ascore(user_input="Python是什么类型的编程语言?",response="Python是一种解释型、面向对象的高级编程语言,语法简洁易读。")print(f"相关答案得分:{result1.value:.4f}")# 无关答案测试result2=awaitscorer.ascore(user_input="Python是什么类型的编程语言?",response="巴黎是法国的首都,位于欧洲西部。")print(f"无关答案得分:{result2.value:.4f}")if__name__=="__main__":asyncio.run(main())💡 踩坑提示:这个指标的分数会有一定波动,因为 LLM 反向生成问题有随机性。解决方法就是调低 temperature、固定随机种子,多次评估取平均值。
4. Faithfulness 忠实度(事实一致性)
是什么
也叫忠诚度、 groundedness,专门用来检测幻觉。它衡量生成的答案是不是严格基于检索上下文生成的,有没有编造上下文里没有的信息。这是生成环节最重要的指标,直接决定 RAG 系统的可信度。
计算原理
和召回率逻辑相反,是从答案出发验证:
- 把生成的答案拆解成若干独立的事实声明
- 逐一验证每条声明是否能从检索上下文中推断出来
- 得分 = 能被上下文支持的声明数 ÷ 答案总声明数
代码实战
我们故意构造一个有事实错误的答案(日期写错):
importasyncioimportosfromopenaiimportAsyncOpenAIfromdotenvimportload_dotenvfromragas.llmsimportllm_factoryfromragas.metrics.collectionsimportFaithfulness load_dotenv()openai_client=AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))llm=llm_factory("qwen3.6-plus",client=openai_client,temperature=0.1,seed=42)scorer=Faithfulness(llm=llm)asyncdefmain():print("=== 忠实度评估 ===")result=awaitscorer.ascore(user_input="图灵是什么时候出生的?",response="图灵1912年6月23日出生在英国伦敦。",retrieved_contexts=["Alan Turing was born on 23 June 1912 in Maida Vale, London, England."])print(f"得分:{result.value:.4f}")if__name__=="__main__":asyncio.run(main())如果把答案里的日期改成错误的 “1915 年”,得分会直接降到 0.5 左右,因为两条声明(出生年份、出生地)里有一条不成立。
5. Answer Correctness 答案正确性
是什么
端到端的 “金标准” 指标,综合衡量生成答案和人工标准答案的一致程度。它是最接近人工评估结果的指标,适合最终的效果验收。
计算原理
两个维度加权平均:
- 语义相似度:用向量计算两个答案的语义接近程度
- 事实正确性:基于 F1 分数计算事实点的重合度,区分 TP(都有的事实)、FP(答案多出来的事实)、FN(答案漏掉的事实)
可以通过weights参数调整两个维度的权重,默认事实正确性权重更高。
代码实战
importasyncioimportosfromopenaiimportAsyncOpenAIfromdotenvimportload_dotenvfromragas.llmsimportllm_factoryfromragas.embeddings.baseimportembedding_factoryfromragas.metrics.collectionsimportAnswerCorrectness load_dotenv()openai_client=AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))llm=llm_factory("qwen3.6-plus",client=openai_client,temperature=0.1,seed=42)embeddings=embedding_factory("openai",model="text-embedding-v4",client=openai_client)scorer=AnswerCorrectness(llm=llm,embeddings=embeddings)asyncdefmain():print("=== 答案正确性评估 ===")result=awaitscorer.ascore(user_input="图灵是什么时候出生的?",response="图灵1915年出生在英国。",reference="图灵1912年出生在英国伦敦。")print(f"得分:{result.value:.4f}")if__name__=="__main__":asyncio.run(main())四、一图速查:指标依赖对比
不同指标需要的输入不一样,适用场景也不同,整理成表格方便复习:
| 指标 | 用户问题 | 生成答案 | 检索上下文 | 标准答案 | 依赖 LLM | 依赖 Embedding |
|---|---|---|---|---|---|---|
| Context Precision 上下文精准度 | ✅ | - | ✅ | ✅ | ✅ | - |
| Context Recall 上下文召回率 | ✅ | - | ✅ | ✅ | ✅ | - |
| Answer Relevancy 答案相关性 | ✅ | ✅ | - | - | ✅ | ✅ |
| Faithfulness 忠实度 | ✅ | ✅ | ✅ | - | ✅ | - |
| Answer Correctness 答案正确性 | ✅ | ✅ | - | ✅ | ✅ | ✅ |
📌 场景选择建议:
- 只优化检索模块:选 Context Precision + Context Recall
- 只优化生成模块:选 Faithfulness + Answer Relevancy
- 端到端最终验收:选 Answer Correctness
五、学习总结与避坑指南
1. 核心逻辑总结
RAGAS 的本质是LLM 语义判断 + 数学统计计算的结合。大模型负责做语义层面的 “好不好、对不对” 的判断,再用经典的信息检索指标(Precision、Recall、F1)做量化,最终输出稳定可对比的分数。
2. 新手避坑清单
- 版本锁死:学习阶段一定要用 0.4.3 版本,新版 API 改动极大,很容易跑不通教程
- 结果波动:所有基于 LLM 的指标都有随机性,调低 temperature、固定 seed、多次取平均可以大幅提升稳定性
- 不要迷信单一指标:RAG 质量是多维度的,要结合检索、生成多个指标综合判断,避免单点优化过度
- 先跑通单条,再批量测试:先把单个指标的单条用例跑通,再接入自己的测试数据集,排查问题更高效
3. 后续学习方向
入门之后,可以进一步研究:
- 批量测试集的构建与自动评估
- 自定义指标的编写
- 把 RAGAS 集成到 CI/CD 流水线,做自动化回归测试
- 结合业务场景做权重调优,找到最贴合业务的评估标准