背景
当前仓库定位为「面向千问 Qwen 生态的 RAG 评估脚手架」,代码结构中模型调用、向量库构建、RAG 工作流和评估逻辑存在一定耦合。随着后续规划的扩展(支持不同 base_url 的模型网关、增加负记忆 RAG、扩展 CMRC 数据集 split),有必要做一轮系统性的重构,将项目升级为 provider-agnostic 的通用 RAG 评估与闭环框架。
本 Issue 用于记录这次重构的整体目标、设计思路和任务拆分。
目标
- 将项目从「Qwen 专用」升级为「以 Qwen 为默认 provider 的通用 RAG 评估脚手架」,在命名和架构上都不再绑定单一厂商。
- 明确并落地五个核心模块,统一使用
invoke 作为执行入口:
1)VectorDatabaseBuilder:消费样本数据,构建向量库并返回 VectorStoreManager
2)RagRunner:基于单个 VectorStoreManager 和 LLM,执行普通 RAG,invoke(question) -> dict
3)EvalEngine:消费 RagRunner,跑批量评估,默认 backend 为 RAGAS,后续可扩展其他评估框架
4)NegativePoolBuilder:消费评估结果,筛选负例并构建“负记忆”向量库的 VectorStoreManager
5)NegativeRAG:同时消费正向与负向两个 VectorStoreManager,执行带负记忆的 RAG,invoke(question) -> dict
- 将模型调用逻辑简化为“在 RAG 工作流中通过 LangChain client 调用模型”,通过
api_key + base_url + model_name 实现多模型支持,默认仍为 Qwen。
- 扩展数据集支持:在现有 CMRC2018 基础上,支持 train / dev / val 三个 split,并允许将多个 split 合并为统一的 samples 与 chunks。
设计概要
1. 项目定位与命名
- 仓库从
qwen-rag-eval-scaffold 升级为通用 RAG 评估脚手架,暂定名例如:
1)仓库:rag-eval-scaffold(或其他同类命名)
2)包名:rag_eval
- README 第一段说明:
1)框架是 provider-agnostic 的 RAG 评估与闭环脚手架
2)Qwen 和 DashScope 是默认支持最好的一档,但用户可以通过 base_url 接入自建或第三方网关
2. 模块化结构与职责划分
参考的新结构大致为:
-
rag_eval/vector_db:向量库相关
1)VectorStoreManager:封装 Chroma 与 retriever
2)VectorDatabaseBuilder:从 samples / chunks 构建向量库并返回 manager
-
rag_eval/rag:RAG 工作流相关
1)NormalRag:单库 RAG 工作流(可基于 LangGraph)
2)RagRunner:封装向量库和 AgentHelper,暴露 invoke(question)
3)NegativeRAG:双库 RAG,暴露 invoke(question),内部区分正例上下文与负例案例
-
rag_eval/eval_engine:评估引擎
1)RagBatchRunner:批量调用任意实现了 invoke(question) 的 runner
2)EvalEngine:统一评估入口,默认 backend 为 RAGAS
3)为兼容现有代码,在 __init__.py 中保留 RagasEvaluator = EvalEngine 别名
-
rag_eval/feedback:负记忆与闭环
1)NegativePoolBuilder:消费 EvalReport,筛选负例样本并构建负例向量库
2)strategies:不同负例筛选策略(按 metric 阈值或 error_type)
-
rag_eval/datasets/cmrc2018:数据集处理
1)loader.py:按 split 加载 train / dev / val 原始数据
2)sampling.py:根据配置的 split 列表构建 merged samples
3)chunking.py:只对 ground_truth_context 做切块,生成统一 chunks
3. 模型调用策略(LangChain + base_url)
- 不再单独抽一层 provider 目录,模型逻辑集中放在
utils/agent_helper.py。
- 在
config/application.yaml 中新增或规范化 llm 段:
1)llm.base_url:为空时使用默认(例如 DashScope / 千问官方),非空时使用 OpenAI-style 接口
2)llm.model_name:默认 Qwen 模型名,可按需切换
3)llm.api_key_env:从哪个环境变量读取 API Key
AgentHelper 统一通过 LangChain(例如 ChatOpenAI 风格接口)创建 LLM 对象,供 RagRunner / NegativeRAG 使用,其他模块不直接接触模型细节。
4. CMRC2018 train/dev/val 支持
- 在
datasets/raw 中规范 train / dev / val 三个原始文件路径。
- 在
application.yaml 的 dataset 段中增加:
1)dataset.cmrc_splits:例如 ["dev"] 或 ["train", "dev", "val"]
2)由构建流程自动合并对应 split,生成
1)统一的 samples(如 cmrc2018_samples_merged.json)
2)统一的 chunks(如 cmrc2018_chunks_merged.jsonl)
- 评估阶段默认对合并后的 samples 进行评估,也可以在后续引入更细粒度的 split 选择策略。
任务拆分建议
可以将本次重构拆分为几批次提交:
-
第一阶段:主链路模块化
1)引入 VectorDatabaseBuilder、RagRunner、EvalEngine
2)迁移 quick_start.py 到新接口,保持现有行为不变
-
第二阶段:负记忆闭环
1)实现 NegativePoolBuilder 与 NegativeRAG
2)增加 quick_start_negative.py 或命令行入口,用于跑闭环版本
-
第三阶段:模型与数据集扩展
1)在 application.yaml 中规范 llm.* 配置,并在 AgentHelper 中使用 LangChain client 接入
2)在 datasets/cmrc2018 中支持 train / dev / val,更新样本与 chunks 构建逻辑
-
第四阶段:文档与示例
1)更新 README / README_zh 中的介绍与使用示例
2)明确说明 Qwen 是默认 provider,但框架本身是 provider-agnostic 的
兼容性与迁移
- 对现有用户,保持以下兼容性:
1)保留 RagasEvaluator 名称作为 EvalEngine 的别名
2)保留原有 quick_start.py 的基础用法(只是在内部接入新模块)
- 对自身开发:
1)优先保证“当前主路径可跑通”(构建向量库 + 普通 RAG + RAGAS 评估)
2)然后再逐步启用负记忆与更多数据集扩展,分阶段合并到主分支
背景
当前仓库定位为「面向千问 Qwen 生态的 RAG 评估脚手架」,代码结构中模型调用、向量库构建、RAG 工作流和评估逻辑存在一定耦合。随着后续规划的扩展(支持不同 base_url 的模型网关、增加负记忆 RAG、扩展 CMRC 数据集 split),有必要做一轮系统性的重构,将项目升级为 provider-agnostic 的通用 RAG 评估与闭环框架。
本 Issue 用于记录这次重构的整体目标、设计思路和任务拆分。
目标
invoke作为执行入口:1)VectorDatabaseBuilder:消费样本数据,构建向量库并返回 VectorStoreManager
2)RagRunner:基于单个 VectorStoreManager 和 LLM,执行普通 RAG,
invoke(question) -> dict3)EvalEngine:消费 RagRunner,跑批量评估,默认 backend 为 RAGAS,后续可扩展其他评估框架
4)NegativePoolBuilder:消费评估结果,筛选负例并构建“负记忆”向量库的 VectorStoreManager
5)NegativeRAG:同时消费正向与负向两个 VectorStoreManager,执行带负记忆的 RAG,
invoke(question) -> dictapi_key + base_url + model_name实现多模型支持,默认仍为 Qwen。设计概要
1. 项目定位与命名
qwen-rag-eval-scaffold升级为通用 RAG 评估脚手架,暂定名例如:1)仓库:
rag-eval-scaffold(或其他同类命名)2)包名:
rag_eval1)框架是 provider-agnostic 的 RAG 评估与闭环脚手架
2)Qwen 和 DashScope 是默认支持最好的一档,但用户可以通过 base_url 接入自建或第三方网关
2. 模块化结构与职责划分
参考的新结构大致为:
rag_eval/vector_db:向量库相关1)
VectorStoreManager:封装 Chroma 与 retriever2)
VectorDatabaseBuilder:从 samples / chunks 构建向量库并返回 managerrag_eval/rag:RAG 工作流相关1)
NormalRag:单库 RAG 工作流(可基于 LangGraph)2)
RagRunner:封装向量库和 AgentHelper,暴露invoke(question)3)
NegativeRAG:双库 RAG,暴露invoke(question),内部区分正例上下文与负例案例rag_eval/eval_engine:评估引擎1)
RagBatchRunner:批量调用任意实现了invoke(question)的 runner2)
EvalEngine:统一评估入口,默认 backend 为 RAGAS3)为兼容现有代码,在
__init__.py中保留RagasEvaluator = EvalEngine别名rag_eval/feedback:负记忆与闭环1)
NegativePoolBuilder:消费 EvalReport,筛选负例样本并构建负例向量库2)
strategies:不同负例筛选策略(按 metric 阈值或 error_type)rag_eval/datasets/cmrc2018:数据集处理1)
loader.py:按 split 加载 train / dev / val 原始数据2)
sampling.py:根据配置的 split 列表构建 merged samples3)
chunking.py:只对 ground_truth_context 做切块,生成统一 chunks3. 模型调用策略(LangChain + base_url)
utils/agent_helper.py。config/application.yaml中新增或规范化llm段:1)
llm.base_url:为空时使用默认(例如 DashScope / 千问官方),非空时使用 OpenAI-style 接口2)
llm.model_name:默认 Qwen 模型名,可按需切换3)
llm.api_key_env:从哪个环境变量读取 API KeyAgentHelper统一通过 LangChain(例如ChatOpenAI风格接口)创建 LLM 对象,供 RagRunner / NegativeRAG 使用,其他模块不直接接触模型细节。4. CMRC2018 train/dev/val 支持
datasets/raw中规范 train / dev / val 三个原始文件路径。application.yaml的dataset段中增加:1)
dataset.cmrc_splits:例如["dev"]或["train", "dev", "val"]2)由构建流程自动合并对应 split,生成
1)统一的 samples(如
cmrc2018_samples_merged.json)2)统一的 chunks(如
cmrc2018_chunks_merged.jsonl)任务拆分建议
可以将本次重构拆分为几批次提交:
第一阶段:主链路模块化
1)引入
VectorDatabaseBuilder、RagRunner、EvalEngine2)迁移
quick_start.py到新接口,保持现有行为不变第二阶段:负记忆闭环
1)实现
NegativePoolBuilder与NegativeRAG2)增加
quick_start_negative.py或命令行入口,用于跑闭环版本第三阶段:模型与数据集扩展
1)在
application.yaml中规范llm.*配置,并在 AgentHelper 中使用 LangChain client 接入2)在
datasets/cmrc2018中支持 train / dev / val,更新样本与 chunks 构建逻辑第四阶段:文档与示例
1)更新 README / README_zh 中的介绍与使用示例
2)明确说明 Qwen 是默认 provider,但框架本身是 provider-agnostic 的
兼容性与迁移
1)保留
RagasEvaluator名称作为 EvalEngine 的别名2)保留原有
quick_start.py的基础用法(只是在内部接入新模块)1)优先保证“当前主路径可跑通”(构建向量库 + 普通 RAG + RAGAS 评估)
2)然后再逐步启用负记忆与更多数据集扩展,分阶段合并到主分支