CMRC2018 + Chroma + RAGAS:在 Qwen 生态下搭一条可复用的中文 RAG 评测链路

77 阅读7分钟

最近在做 RAG 相关的实验时,我发现自己在这套流程中耗费了比较多的时间:

  1. 找一份还算靠谱的中文问答数据集
  2. 把原始数据加工成评估样本,再切成 chunks 写进向量库
  3. 把向量库检索和生成模型串成一条 RAG 链路
  4. 再搭一条评估链路,用 RAGAS 这类指标看一看效果到底如何

每一步单独看都不算难,但接口、格式、路径和配置都不统一。
如果只是想“快速验证一个 RAG 方案”,从头搭一遍这条链路,性价比其实不高。

于是我干脆把这条链路抽出来,做成了一个可以直接复用的小脚手架:
qwen-rag-eval-scaffold

它面向 Qwen 千问 API,做的事情可以概括为一条链路:

CMRC2018 → Chroma Vector Store → RAG Workflow → RAGAS Evaluation

只需要准备一个 DashScope API Key,一条命令就能从数据跑到评估结果。

一、项目定位:我想解决什么问题?

这个脚手架的目标不是“写一个最强的 RAG 系统”,而是提供一条可复现、可复用的中文 RAG 评测链路

对我自己来说,更在意的是下面几件事:

  1. 数据从哪里来、格式怎么约定,能不能一劳永逸
  2. 向量库怎么建,后面改 workflow 的时候不用反复重来
  3. RAG 工作流可以随便折腾,但对外暴露的接口尽量简单、统一
  4. 评估这一层抽象出来,不因为换了 RAG 写法就重写一遍评测脚本

qwen-rag-eval-scaffold 在这个目标下做了一个取舍:
与其做一个“什么都能配”的大而全框架,不如先在 Qwen + 中文问答 这个场景里,把那条从数据集到评估的链路打通、固化下来,作为一个基线工程。

二、整体设计:从数据到评估的四层

整个脚手架可以拆成四层,每一层只负责一件事情。

1. 数据层:CMRC2018 标准化样本

默认使用 CMRC2018 作为中文阅读理解基准数据集,在此基础上约定了一种通用的样本格式:

{
  "id": "...",
  "question": "...",
  "ground_truth": "...",
  "ground_truth_context": "..."
}

只要你的数据满足这四个字段,就可以直接作为评估样本使用。

其中:

  1. question 是用户问题
  2. ground_truth 是期望回答
  3. ground_truth_context 是支持这个回答的原文片段(后面会被切成 chunks,写入向量库)

2. 向量库层:Chroma + DashScope Embedding

在向量库这一层,脚手架做了两件事:

  1. 使用 DashScope 的向量模型构建 embedding
  2. 使用 Chroma 作为本地向量库实现

从流程上看就是:

CMRC2018 samples → 只挑 ground_truth_context → 切分成多个 chunk → 写入 Chroma collection。

这一层的实现被封装在 qwen_rag_eval/vector 里,可以单独复用。

3. 执行层:Runner 抽象 + 默认 RAG 工作流

真正的 RAG 逻辑被抽象成一个 Runner,只约定一个极薄的接口:

def invoke(self, question: str) -> dict:
    return {
        "question": question,
        "generation": "...",   # 模型最终回答
        "contexts": [...],     # 检索到的上下文,可以是 str 或带 page_content 的对象
    }

脚手架默认提供了一条基于 LangGraph 的 NormalRag 工作流,暴露成 DefaultRunner
但你可以完全忽略它,直接把自己的 RAG workflow 包成一个 Runner 丢进来,只要遵守这个返回格式即可。

4. 评估层:RagBatchRunner + RagasEvaluator

评估层做了两件事情:

  1. RagBatchRunner 批量调用 Runner,把每条样本变成 question + generation + contexts 的记录
  2. RagasEvaluator 调用 RAGAS,对这些记录打分,输出整体指标和逐样本评分 CSV

对于使用者来说,评估接口大致是:

from qwen_rag_eval.evaluation import RagBatchRunner, RagasEvaluator

runner = MyRunner()
records = RagBatchRunner(runner, mode="my_runner").run_batch(eval_samples)
result = RagasEvaluator("config/application.yaml").evaluate(records)

其中 records 会被规整成内部的 RagEvalRecord 列表,然后交给 RAGAS 进行打分。

三、Quick Start:一条命令跑通

整个脚手架的使用门槛尽量控制在“安装依赖 + 配置一个环境变量”。

1. 环境准备

  1. Python 版本:建议 3.10+
  2. 安装依赖:
pip install -r requirements.txt
  1. 配置 DashScope API Key:

Windows 示例:

set API_KEY_Qwen=your-dashscope-api-key
python quick_start.py

Linux / macOS 示例:

export API_KEY_Qwen="your-dashscope-api-key"
python quick_start.py

2. 一条命令:python quick_start.py

在项目根目录执行:

python quick_start.py

会自动做四件事:

  1. 从原始 CMRC2018 构建评估样本(samples),写入 datasets/processed
  2. 基于 ground_truth_context 切分 chunks,构建 Chroma 向量库
  3. 使用 DefaultRunner 批量跑 RAG,生成 question–answer–contexts 记录
  4. 调用 RAGAS 做自动评估,打印整体指标,并导出逐样本评分 CSV

只要环境变量和依赖安装正确,这一条命令就能完成从数据到评估结果的完整闭环。

四、如何接入自己的 RAG 工作流?

如果你已经有一条自己的 RAG 链路(不管是 LangChain、LangGraph 还是纯手写 pipeline),可以很轻量地接进这个脚手架进行评估。

核心就是:实现一个 Runner,满足前面提到的接口约定。

示例:

class MyRunner:
    def __init__(self, retriever, llm):
        self.retriever = retriever
        self.llm = llm

    def invoke(self, question: str) -> dict:
        contexts = self.retriever.get_relevant_documents(question)
        answer = self.llm.invoke({
            "question": question,
            "contexts": contexts,
        })

        return {
            "question": question,
            "generation": answer,
            "contexts": contexts,
        }

然后用统一评估接口:

from qwen_rag_eval.evaluation import RagBatchRunner, RagasEvaluator
from qwen_rag_eval.dataset_tools.loader import load_cmrc_samples

# 1. 加载评估样本
config_path = "config/application.yaml"
eval_samples = load_cmrc_samples(config_path)

# 2. 初始化你的 Runner
runner = MyRunner(retriever=..., llm=...)

# 3. 批量跑 RAG
records = RagBatchRunner(runner, mode="my_runner").run_batch(eval_samples)

# 4. 调用 RAGAS 评估
evaluator = RagasEvaluator(config_path)
result = evaluator.evaluate(records)

这样你只需要关心“怎么做检索 + 生成”,评估流程不需要每个项目重新写一份。

五、替换数据集与重建向量库

默认使用 CMRC2018 只是为了给出一条“开箱即用”的中文评测链路,但脚手架本身支持替换数据集。

只要你能把自己的数据整理成下面这种样本格式:

{
  "id": "...",
  "question": "...",
  "ground_truth": "...",
  "ground_truth_context": "..."
}

就可以直接:

  1. 把它保存成 samples.json
  2. 使用 build_vector_store_from_samples 直接基于样本构建向量库:
from qwen_rag_eval.vector import build_vector_store_from_samples

build_vector_store_from_samples(
    "path/to/samples.json",
    collection_name="my_collection",
    overwrite=True,
)

后续评估逻辑保持不变。
这意味着你可以在不同任务、不同领域下重用同一套评估代码和 Runner,实现真正的“多场景复用”。

六、适用人群与应用场景

我自己在写这个脚手架时,心里对应的是几类典型使用者:

  1. 想入门 RAG,但不想被“找数据集 + 建库 + 写评测”拖住节奏的人
  2. 已经有 RAG 工作流,希望有一条统一评测链路做方案对比的人
  3. 在 Qwen / DashScope 生态里做应用,需要一个干净工程基线的人

对这些人来说,qwen-rag-eval-scaffold 更像是一个实验底座,而不是一个“什么都替你做好”的大框架。
它负责把那条“中文数据集 → 向量库 → RAG 工作流 → RAGAS 评估”的路径铺平,让你可以在这条路径上持续迭代自己的想法。

七、仓库地址与后续计划

仓库地址:
github.com/syy12335/qw…

目前版本是一个初始测试版,主要提供:

  1. CMRC2018 → Chroma → DefaultRunner → RAGAS 的完整评测链路
  2. Runner 接入协议和评估封装
  3. Streamlit 控制台作为调试与展示入口

后续计划包括:

  1. 补充更多 Runner 示例(不同检索策略、多跳链路等)
  2. 引入更多中文数据集与预设配置
  3. 在评估侧支持更灵活的指标组合与评估配置

如果你刚好在做中文 RAG,或者在 Qwen 生态下需要一条可复用的评测链路,希望这个脚手架能帮你少踩一点重复的坑。