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\activate

2. 依赖与配置

创建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 加权平均,公式逻辑:

  1. 对每个位置 k,计算Precision@k = 前k条中相关内容数 / k
  2. 用每个位置的相关性标识v_k(相关为 1,不相关为 0)做加权
  3. 最终得分 = 所有相关位置的 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 上下文召回率

是什么

衡量检索系统的查全能力,核心看:回答这个问题需要的所有关键信息,有没有都被检索出来。它关注的是 “漏不漏”,和精准度刚好互补 —— 精准度怕掺假,召回率怕遗漏。

计算原理

采用「声明拆解法」,三步计算:

  1. 拆解声明:把标准答案拆成若干个独立的、不可拆分的事实陈述句(Claims)
  2. 匹配验证:拿着每一条声明,去检索上下文中找依据,判断是否能被支持
  3. 计算得分:得分 = 能被支持的声明数 ÷ 总声明数
代码实战
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 条独立声明:

  1. 故宫有太和殿 ✅ 有依据
  2. 故宫有乾清宫 ✅ 有依据
  3. 故宫有御花园 ✅ 有依据
  4. 故宫有角楼 ❌ 无依据

总声明数 4,被支持的 3 个,得分 = 3/4 = 0.75运行结果会在 0.75 左右浮动,和我们的手动计算完全吻合。


3. Answer Relevancy 答案相关性

是什么

衡量生成的答案和用户问题的匹配程度,也就是 “有没有答非所问”。这个指标不需要标准答案,属于无参考评估,非常适合没有标注数据的场景。

计算原理

采用很巧妙的反向重构法,核心逻辑是:一个高质量的相关答案,一定能反向推导出用户原本的问题。三步计算:

  1. 用 LLM 根据生成答案,反向生成 N 个可能的用户问题
  2. 计算这些反向问题与原始问题的语义向量相似度
  3. 取所有相似度的平均值,作为最终得分
代码实战
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 系统的可信度。

计算原理

和召回率逻辑相反,是从答案出发验证:

  1. 把生成的答案拆解成若干独立的事实声明
  2. 逐一验证每条声明是否能从检索上下文中推断出来
  3. 得分 = 能被上下文支持的声明数 ÷ 答案总声明数
代码实战

我们故意构造一个有事实错误的答案(日期写错):

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 答案正确性

是什么

端到端的 “金标准” 指标,综合衡量生成答案和人工标准答案的一致程度。它是最接近人工评估结果的指标,适合最终的效果验收。

计算原理

两个维度加权平均:

  1. 语义相似度:用向量计算两个答案的语义接近程度
  2. 事实正确性:基于 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 流水线,做自动化回归测试
  • 结合业务场景做权重调优,找到最贴合业务的评估标准