
RAG 系统上线之后,大多数团队会卡在同一个问题:我怎么知道这次改的是变好了还是变坏了?没有可观测的离线评估流水线,RAG 优化就会变成”靠感觉调 prompt”,改完一段指令,凭印象判断有没有用。本文给出一套 30 分钟能跑起来的方案:用 Ragas 做指标计算 + 用 Langfuse 做 trace 可视化,搭配一个 GitHub Action 定时任务,实现”改完自动评估、自动出报告”。
为什么需要离线评估,不是只看线上日志
线上日志能告诉你”用户点踩了”,但不能告诉你”为什么点踩”。可能是检索没召回到正确文档,可能是 LLM 没读懂上下文,可能是 prompt 模板让模型偷懒省略了关键信息。没有 ground truth 的指标,调优就是开盲盒。离线评估的核心是构造一个固定的”问题-参考答案-上下文”数据集,每次改检索、改 prompt、改模型,跑同一份数据集,对比指标变化。
Ragas 是目前最主流的 RAG 评估框架,核心指标包括:
- Context Precision:检索召回的 top-k 里,真正相关的占比。
- Context Recall:ground truth 答案所需信息,被检索覆盖的比例。
- Faithfulness:答案里的所有事实,是否都能在上下文中找到依据(衡量”瞎编”程度)。
- Answer Relevancy:答案和问题的语义匹配度。
30 分钟搭建流水线
环境准备需要三样:Python 3.11+、一份评估数据集(100-500 条问答)、一个 Langfuse 实例(免费云版或自托管)。依赖安装:
pip install ragas langfuse datasets langchain-openai
评估数据集建议从历史工单、人工标注、客服对话里抽 200 条左右,每条至少包含三个字段:question、ground_truth(参考答案)、contexts(理想情况下召回的文档列表,可以人工先标注一批”金标准”上下文)。
评估脚本核心片段
下面这段代码可以直接复制使用,假设你已经有了一个 run_rag(query) 函数,返回答案 + 实际召回到的 contexts:
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
context_precision, context_recall,
faithfulness, answer_relevancy,
)
from langfuse import Langfuse
langfuse = Langfuse()
trace = langfuse.trace(name="ragas-eval")
def eval_one(item):
out = run_rag(item["question"])
return {
"question": item["question"],
"answer": out["answer"],
"contexts": out["contexts"],
"ground_truth": item["ground_truth"],
}
rows = [eval_one(it) for it in dataset]
ds = Dataset.from_list(rows)
result = evaluate(ds, metrics=[
context_precision, context_recall,
faithfulness, answer_relevancy,
])
trace.score(name="context_precision", value=result["context_precision"])
trace.score(name="faithfulness", value=result["faithfulness"])
print(result)
关键点有三个:第一,run_rag 必须返回真实检索路径上的 contexts,而不是临时拼出来的;第二,Ragas 的指标会调 LLM 做评判,推荐用 GLM-5.3 或 Sonnet 级别模型,避免用小模型导致指标本身不可信;第三,每一次评估都要打 Langfuse trace,后面才能对比。
用 Langfuse 看 trace 找问题
指标只是入口,真正能定位问题的是 Langfuse 里的 trace。每一条评估样本的 trace 会记录:用户问题 → 检索召回的 top-k 文档(每条带相似度分数)→ LLM 拿到的 prompt 全文 → 生成的答案 → 四个指标的子分数。点击某条低分样本,可以直接看到”Faithfulness 0.62 是因为模型在第 3 段编了一个不在上下文里的数字”。
实际调优时,有几个常见模式值得记下来:
- Context Recall 偏低:检查 chunk size 和 overlap,大概率是文档切太碎或者切太大,关键信息被切走。
- Context Precision 偏低:检查 embedding 模型,或者加 re-ranker(开源 BGE-reranker 性价比最高)。
- Faithfulness 偏低:加”如果你不确定就回答不知道”的指令,或者把 prompt 模板里的”请基于以下信息”改成”仅基于以下信息,不要使用外部知识”。
- Answer Relevancy 偏低:检查是否召回了多个相关文档互相干扰,可以加 self-RAG 风格的”先判断文档相关性再回答”。
用 GitHub Action 自动跑
把上面的脚本放到 scripts/eval_rag.py,再配一个 GitHub Action 定时跑:
name: RAG eval
on:
schedule: [{cron: "0 2 * * *"}]
workflow_dispatch:
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: {python-version: "3.11"}
- run: pip install -r requirements.txt
- run: python scripts/eval_rag.py
env:
LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PK }}
LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SK }}
OPENAI_API_KEY: ${{ secrets.OPENAI_KEY }}
每天凌晨 2 点自动跑一次评估,结果直接落到 Langfuse 的 dashboard,谁动了 prompt 引发指标下滑一目了然。新人入职第一周看一周 trace,基本能搞懂整个 RAG 系统的结构。
几点经验
最后给几条踩过坑的建议:评估数据集要分 train/eval 两份,train 用来调 prompt 模板,eval 用来做最终对比,避免在 eval 上”刷分”;指标数字别追求极致,Context Recall 0.85 已经能覆盖 90% 的业务问题,再往上每 0.01 都可能带来 10 倍的 token 成本;一旦指标稳定,就把当前 prompt 模板、检索参数、模型版本一起存成”基线快照”,后续 A/B 都要和基线对比,而不是和上一次的随机结果比。
RAG 不是上线就完事,真正的工作在评估和调优里。把评估流水线搭起来,RAG 工程化才算真正开始。



