Skip to content

Latest commit

 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EasyRAG

文档层级建模、多粒度 embedding 和父子上下文扩展。模块化、可恢复、可解释的 RAG 库, 使用 LanceDB 作为向量数据库.

========================================================================
  🏆 EasyRAG 评测综合指标汇总 (Overall Metrics | 样本数: 150)
========================================================================
   • 执行状态: 检索成功 150/150 | 生成成功 148/150 | 失败 2
   • 数据集 SHA256: 8fbec02b8dc1bb2869d3401223401e86573ef400c44ab346ae70bc220f4ca35f
   • 索引 SHA256:   7df478c3ed5e887f4402c686a8298c3f8d0b4a08322e97ea74dcac903fe714c5
【1. 检索召回评测指标 (Retrieval Quality)】
   • Hit Rate@1:   68.99%   | 首条命中率
   • Hit Rate@3:   79.84%   | Top-3 命中率
   • Hit Rate@5:   85.27%   | Top-5 命中率
   • Hit Rate@K:   87.60%   | Top-K 总体命中率
   • MRR:         0.7483    | 平均倒数排名 (Mean Reciprocal Rank)
   • NDCG@10:      0.7074    | 归一化折损累积增益 (相关度加权)
   • Precision@10:  11.40%   | 检索精确率
   • Recall@10:     71.60%   | 检索召回率

【2. 回答生成与裁判指标 (Generation Quality)】
   • Correctness:        71.40%   | 语义正确性与事实一致度
   • Faithfulness:       92.93%   | 上下文忠实度 (无幻觉率)
   • Relevance:          88.07%   | 回答针对性与切题度
   • Refusal Accuracy:   57.14%   | 不可回答问题正确拒答率
   • False Refusal Rate:  6.20%   | 可回答问题错误拒答率 (过度拒答率)
   • 成功裁判样本口径: Correctness=72.36% | Faithfulness=94.19% | Relevance=89.26% (148 条)

------------------------------------------------------------------------
问题类型 (Type)              | 样本   | Hit@K   | MRR     | Correctness | Faithfulness
------------------------------------------------------------------------
comparison               |   21 |  95.2% |  0.726 |       67.1% | 88.1%
multi_hop_fact           |   22 |  95.5% |  0.826 |       74.5% | 95.5%
multi_hop_reasoning      |   21 |  95.2% |  0.790 |       73.3% | 100.0%
single_hop_fact          |   22 | 100.0% |  0.964 |      100.0% | 99.5%
single_hop_reasoning     |   22 |  90.9% |  0.879 |       90.9% | 100.0%
summary                  |   21 |  47.6% |  0.286 |       34.3% | 95.2%
unanswerable             |   21 |   0.0% |  0.000 |       57.1% | 71.4%
========================================================================

🚀 快速上手

# 1. 配置环境变量
cp .env.example .env

# 2. 安装项目依赖
uv sync

当前推荐命令

以下命令以当前默认配置为准:默认使用 two_stage 两阶段检索,并自动启用问题类型路由。

# 建库:增量索引(首次使用或文档变更后执行)
uv run main.py index tests/docs/

# 查看检索结果与完整 trace
uv run main.py search "你的问题" --detail

# 直接问答(默认流式输出)
uv run main.py query "你的问题"

# 仅评估检索质量,适合快速比较参数
uv run eval.py run -d data/eval_dataset.json -o data/eval_report_retrieval.json --mode retrieval --reranker two_stage

# 综合评测:检索 + 回答生成 + Judge
uv run eval.py run -d data/eval_dataset.json -o data/eval_report.json --mode all --reranker two_stage

# 与旧版 Frequency + Diversity 链路做基线对照
uv run eval.py run -d data/eval_dataset.json -o data/eval_report_baseline.json --mode retrieval --reranker both

评测时建议先运行 --mode retrieval 做检索链路 A/B,再运行 --mode all 检查回答质量。all 模式会额外调用回答模型和评判模型,耗时与 API 消耗更高。

📖 各阶段功能与常用命令

阶段 1:数据预处理与文档建模 (Preprocessing & Modeling)

纯本地离线运行,不调用外部 API,用于执行文档解析、断句分段、四层建树以及效果预览校验。

功能 执行命令 参数与说明 API / Token 消耗
单文件预处理 uv run main.py preprocess tests/docs/太白金星有点烦.txt 解析文件、切分分块并打印各层级节点生成统计 ❌ 零消耗 (纯本地)
单文件预处理并导出 JSON uv run main.py preprocess tests/docs/太白金星有点烦.txt --output-dir data/processed/ --output-dir:将结构化文档树导出为 JSON 文件 ❌ 零消耗 (纯本地)
批量目录预处理 uv run main.py preprocess data/ --output-dir data/processed/ 递归扫描目录内所有文档并批量导出结构化分块数据 ❌ 零消耗 (纯本地)
基础树状结构预览 uv run main.py preview tests/docs/太白金星有点烦.txt --limit 2 --limit 2:每个层级最多展示 2 个子节点,折叠超长内容 ❌ 零消耗 (纯本地)
完整树状结构展开 uv run main.py preview tests/docs/太白金星有点烦.txt --limit 0 --limit 0:展开所有章节、段落与叶子句子 ❌ 零消耗 (纯本地)
章节/段落大纲预览 uv run main.py preview tests/docs/太白金星有点烦.txt --max-depth 3 --max-depth 3:仅展示至段落级,不展开底层句子 ❌ 零消耗 (纯本地)
终端直接输出 JSON uv run main.py preview tests/docs/太白金星有点烦.txt --json --json:直接在终端打印可序列化的节点树 JSON ❌ 零消耗 (纯本地)

阶段 2:向量存储与增量同步注册表 (Storage & Indexing)

执行完整的向量化计算、LanceDB 向量入库与 SHA-256 哈希增量同步。

功能 执行命令 参数与说明 API / Token 消耗
创建/索引单文件 uv run main.py index tests/docs/太白金星有点烦.txt 解析分块、计算向量并登记入库(文件未改动则自动跳过,--force重新执行) 🟢 仅新文件消耗 Embedding
自定义文档标题索引 uv run main.py index tests/docs/太白金星有点烦.txt --title "太白金星" --title:指定知识库中的文档标题 🟢 仅新文件消耗 Embedding
批量增量索引目录 uv run main.py index tests/docs/ 递归扫描目录,根据哈希只索引新增/修改的文件 🟢 仅增量变更消耗
强制全量重建索引 uv run main.py index tests/docs/ --force --force:无视哈希缓存,强制重新切块并重新计算向量 ⚠️ 消耗全部文件 Embedding
查看已索引文档清单 uv run main.py list 列出当前知识库已入库的文档 ID、分块数、文件大小 ❌ 零消耗
查看知识库统计信息 uv run main.py stats 查看文档总数、分层节点总数、存储路径与所用模型 ❌ 零消耗
删除指定文档 uv run main.py delete <doc_id> 同步从 LanceDB 和注册表中清理该文档及所有分层节点 ❌ 零消耗
清空重置知识库 uv run main.py reset 清空 LanceDB 向量表及 doc_registry.json 元数据,允许-y参数 ❌ 零消耗

索引会同时写入 index_manifest.json,记录 Embedding 模型、维度、分块格式和段落向量模式。非空索引缺少清单或与当前配置不一致时,系统会明确拒绝检索/增量写入,避免把维度错误静默表现成“未检索到资料”。首次升级到该版本时,旧索引需要执行 uv run main.py reset -y 后重新索引。


阶段 3:多路召回、重排序与分层上下文延展 (Retrieval & Reranking)

both(双重重排序)将 频次共识重排(Frequency Consensus)层级多样性重排(Diversity & Deduplication) 串联在一起,兼顾了相关度置信度信息覆盖面

🚀 Small-to-Big 分层上下文追溯(--parent-depth / --child-depth: 检索时以最细粒度的 句子 (Sentence) 参与语义与关键词匹配;召回后通过 ContextGraph 自动沿 parent_id 向上回溯至 完整段落 (Paragraph)章节 (Section),或通过 child_depth 向下递归聚合子节点内容,实现“精细召回,完整呈现”。

flowchart TD
    Raw[初始召回的候选节点列表 Matches] --> Step1{是否启用了 Multi-Query?}
    
    Step1 -- 是 --> Freq[第 1 阶:FrequencyReranker 频次共识重排,按命中子查询次数从大到小排序,取 top_k*2]
    Step1 -- 否 (单查询) --> Bypass[跳过频次统计]
    
    Freq --> Div[第 2 阶:DiversityReranker 层级多样性打散,按 parent_id 限制同段落最多 2 句,最终取 top_k]
    Bypass --> Div
    
    Div --> Graph[第 3 阶:ContextGraph 分层图扩展,按 parent_depth 向上回溯段落/章节,按 child_depth 向下聚合]
    Graph --> Output[最终精排上下文片段 Snippets]
Loading
阶段 解决的核心痛点 具体做法
第 1 阶段:频次共识 (Frequency) 避免单一角度检索产生的偶然偏差和语义遗漏 在开启多查询(--multi-query)时,LLM 会扩展出 3 个不同问法并发检索。被多个子查询同时命中的段落,说明置信度极高,会优先排在最前面。
第 2 阶段:层级多样性 (Diversity) 避免检索结果被同一段话里的连续句子霸屏 限制来自同一个父段落(parent_id)的句子最多只保留 2 个(可通过 --diversity-max-per-parent 调整),把名额留给其他段落。
第 3 阶段:分层上下文延展 (ContextGraph) 避免句子碎片孤立无上下文,或段落太长导致向量匹配不准 Small-to-Big 扩展
--parent-depth 1(默认):句子 $\to$ 向上回溯所属完整段落。
--parent-depth 2:句子 $\to$ 段落 $\to$ 继续回溯所属完整章节。
--parent-depth 0:不延展,仅输出匹配的单句。
功能 执行命令 参数与说明 API / Token 消耗
默认两阶段检索 (Hybrid + Rerank) uv run main.py search "太白金星 李长庚" --top-k 5 Dense/BM25 → RRF → 段落聚合 → Cross-Encoder → Coverage/MMR → Small-to-Big;默认 two_stage 🟢 Embedding + Reranker API
纯向量检索 (Dense) uv run main.py search "太白金星" --no-hybrid --no-hybrid:仅使用向量余弦相似度匹配 🟢 消耗 1 次 Query Embedding
多查询意图扩展检索 uv run main.py search "李长庚的坐骑" --multi-query --multi-query:使用 LLM 生成同义搜索词并发召回,并通过频次共识重排 🟢 消耗 LLM 生成 + Embedding
向上延展至完整章节 uv run main.py search "织女" --parent-depth 2 --parent-depth 2:由句子命中向上回溯并聚合整个章节的上下文 🟢 消耗 1 次 Query Embedding
纯句子级精准命中 (不延展) uv run main.py search "老鹤" --parent-depth 0 --parent-depth 0:关闭向上回溯,直接展示命中的单句 🟢 消耗 1 次 Query Embedding
指定仅多样性重排序 uv run main.py search "太白金星" --reranker diversity --diversity-max-per-parent 1 --reranker diversity:限制单父节点命中上限,防止同段落垄断 🟢 消耗 1 次 Query Embedding
禁用重排序 (纯相似度截断) uv run main.py search "太白金星" --reranker none --reranker none:跳过频次与多样性重排,按原始分数排序截断 🟢 消耗 1 次 Query Embedding

阶段 4 & 5:上下文组装、LLM 生成与交互问答 (Generation & CLI)

执行端到端完整 RAG 问答,支持流式生成、精准引用溯源(Citations)与终端交互多轮聊天。

1. 核心问答功能与常用命令

功能 执行命令 参数与说明 API / Token 消耗
默认流式单次提问 uv run main.py query "孙悟空对李长庚说:很多事须怪不到你头上,而李长庚后来反复琢磨这句话,这暗示了什么?" 默认开启流式打字机输出,文末自动打印精准引用溯源 🟢 消耗 Embedding + LLM
查看详细检索上下文 uv run main.py query "孙悟空对李长庚说:很多事须怪不到你头上,而李长庚后来反复琢磨这句话,这暗示了什么?" --detail --detail:打印参与 Prompt 组装的上下文原始片段及相似度 🟢 消耗 Embedding + LLM
延展至章节上下文提问 uv run main.py query "织女下凡的经过" --parent-depth 2 --parent-depth 2:将命中句子向上延展至所属完整章节作为 Prompt 上下文 🟢 消耗 Embedding + LLM
纯句子级窄上下文提问 uv run main.py query "老鹤的名字是什么?" --parent-depth 0 --parent-depth 0:仅使用命中的精简句子回答,节省 Prompt Token 🟢 消耗 Embedding + LLM
多查询扩展 + 多样性问答 uv run main.py query "孙悟空对李长庚说:很多事须怪不到你头上,而李长庚后来反复琢磨这句话,这暗示了什么?" --multi-query --reranker diversity --diversity-max-per-parent 1 开启多意图扩展,并严格控制同段落仅出 1 句 🟢 消耗 Embedding + LLM
非流式单次提问 uv run main.py query "问题内容" --no-stream --no-stream:等待模型完整生成后一次性打印输出 🟢 消耗 Embedding + LLM
终端交互式多轮对话 uv run main.py chat 进入终端连续问答模式(支持 --parent-depth 等所有检索参数,输入 exitq 退出) 🟢 按每次问答消耗

2. query / chat 命令行完整参数速查表

参数类别 命令行参数 类型 / 默认值 作用与说明
问答输出 question 字符串 (必填) 用户提问内容(chat 模式下无需输入)。
--stream / --no-stream 布尔值 (默认 --stream) 是否开启打字机流式输出。
--detail 布尔开关 (默认关闭) 在回答下方打印检索到的详细候选上下文片段与得分。
检索召回 --top-k 整数 (默认 5) 最终注入 LLM 上下文的片段数量 (Top-K)。
--hybrid / --no-hybrid 布尔值 (默认 --hybrid) 是否启用 Dense 向量 + BM25 混合检索。
--rule-query-expansion / --no-rule-query-expansion 布尔值 (默认开启) 是否启用本地规则查询扩展;与 LLM 多查询独立控制。
--multi-query 布尔开关 (默认关闭) 是否开启 LLM 多查询意图拆解并发检索。
重排序 --reranker two_stage | both | diversity | frequency | none (默认 two_stage) 两阶段检索默认执行段落聚合、Cross-Encoder 重排和 Coverage/MMR 去重。
--diversity-max-per-parent 整数 (默认 2) 每个父段落最多保留的候选句子数。
上下文延展 --parent-depth 整数 (默认 1) 向上回溯父级深度:0 为仅句子,1 为段落,2 为章节。
--child-depth 整数 (默认 0) 向下展开子级深度:递归聚合子节点文本内容。

各阶段如何实现的

flowchart TD
    subgraph S1["阶段 1:数据预处理与文档建模"]
        A["输入文档 (.txt / .md / .pdf)"] --> B["Factory 路由解析器 + MetadataExtractor"]
        B --> C["HeadingDetector 标题与层级检测"]
        C --> D["HierarchicalChunker 四级建树<br>Doc -> Section -> Paragraph -> Sentence"]
    end

    subgraph S2["阶段 2:向量存储与增量同步注册表"]
        D --> E["DocRegistry 文件 SHA-256 哈希校验"]
        E -->|未变更| Skip["跳过索引"]
        E -->|新增/变更| F["EmbeddingPropagator 向量化<br>仅向量化叶子句子,向上均值池化聚合段落/章节/文档"]
        F --> G["LanceDBNodeStore 持久化节点表 + 内存快速缓存"]
        G --> H["更新 doc_registry.json 状态"]
    end

    subgraph S3["阶段 3:多路召回、重排序与分层上下文延展"]
        Q["用户 Query"] --> MR{"是否启用 Multi-Query?"}
        MR -- 是 --> MQ["MultiQueryRetriever LLM 扩展 3 个子查询"]
        MR -- 否 --> HR["HybridRetriever 混合检索"]
        MQ --> HR
        HR --> DR["Dense 向量余弦检索"] & BR["BM25 倒排关键词检索"]
        DR & BR --> RRF["RRF 倒数排名融合评分"]
        RRF --> FR["FrequencyReranker 频次共识重排"]
        FR --> DVR["DiversityReranker 基于 parent_id 多样性打散"]
        DVR --> CG["ContextGraph 上下文图追溯<br>Small-to-Big 沿 parent_id 向上回溯段落/章节"]
    end

    subgraph S4["阶段 4 & 5:上下文组装、LLM 生成与交互问答"]
        CG --> CB["ContextBuilder 组装带 [ref_N] 标记的 Prompt"]
        CB --> LLM["LLMClient 流式 / 非流式推理生成"]
        LLM --> EX["extract_citations 正则解析引用标签"]
        EX --> OUT["Rich 终端流式输出答案 + 精准溯源清单"]
    end
Loading

阶段 1:数据预处理与文档建模 (Preprocessing & Modeling)

  1. 多格式解析分发 (src/parsers/)
    • parsers/factory.py 根据文件后缀自动分发到对应解析器(TextParserMarkdownParserPDFParser)。
    • MetadataExtractor 提取文件元数据(大小、修改时间)并计算文件 SHA-256 哈希作为唯一内容版本指纹。
  2. 章节与层级识别 (HeadingDetector)
    • 通过正则表达式和排版规则识别 Markdown 标题(#)、中文章节(第X章/节)及数字编号(1.1),划分逻辑章节 Section 并记录完整标题路径(heading_path 面包屑)。
  3. 四层文档树构建 (HierarchicalChunker)
    • 将文档自顶向下切分为四级拓扑树:DOCUMENT(文档根) $\to$ SECTION(章节) $\to$ PARAGRAPH(段落 / 图片附件) $\to$ SENTENCE(句子叶子)。
    • text_splitter.py 依据中英文标点将段落递归切分为句子。
    • 为每个节点生成确定性层级 ID(doc_id:sec{N}:p{N}:s{N}),并在节点间绑定 parent_idchildren 双向拓扑引用。

阶段 2:向量存储与增量同步注册表 (Storage & Indexing)

  1. 增量比对与注册表 (DocRegistry)
    • 维护本地 data/doc_registry.json 元数据索引库。
    • 索引前校验文件 SHA-256 哈希:内容未变更时直接跳过;若文件已更新或删除,自动级联清理 LanceDB 中的旧节点与元数据记录。
    • 文档身份由规范化文件路径生成,因此相同内容的不同文件不会互相覆盖;内容更新后文档 ID 保持稳定。
    • 更新采用“新节点 upsert → 清理过期节点 → 提交注册表”的顺序,注册表提交失败时恢复上一版节点。
  2. 多粒度 Embedding 向上聚合传播 (EmbeddingPropagator / EmbeddingManager)
    • 叶子计算:仅将最底层的 SENTENCE 句子节点批量提交给 Embedding API 计算向量,大幅减少 Token 消耗与 API 请求耗时。
    • 向上汇聚:通过树的递归后序遍历,PARAGRAPHSECTIONDOCUMENT 等父级节点的向量由其直属子节点向量经均值池化(Mean Pooling)与 L2 归一化自底向上合成(段落节点亦可配置为直接全量 Embedding 或混合模式)。
  3. LanceDB 向量持久化与内存缓存 (LanceDBNodeStore)
    • 将整棵树展平为 StoredNode,批量持久化写入 LanceDB 向量表。
    • 节点类型和 document_id 条件会在 ANN Top-K 前由 LanceDB 预过滤;底层索引异常会显式抛出,不会伪装成空结果。
    • 建立内存字典缓存(_cache),保证检索后的父子节点图回溯具备 $\mathcal{O}(1)$ 的查找性能。

阶段 3:多路召回、重排序与分层上下文延展 (Retrieval & Reranking)

  1. 多路混合召回 (src/retrievers/)
    • 稠密向量检索 (DenseRetriever):调用 LanceDB 对 Query Embedding 进行余弦相似度匹配,以细粒度句子为主要匹配单元。
    • 稀疏关键词检索 (BM25Retriever):基于内存倒排索引计算词频权重,精准召回专有名词与精确术语。
    • RRF 倒数排名融合 (HybridRetriever):使用 Reciprocal Rank Fusion 算法($\text{Score} = \sum w \cdot \frac{1}{k + \text{rank}}$)融合 Dense 与 BM25 的排名结果并归一化。
    • 多查询扩展 (MultiQueryRetriever):可选通过 LLM 将用户问题拆解/扩展为多个不同视角的子查询并发检索,拓宽召回边界。
  2. 两阶段级联重排序 (src/rerankers/)
    • 候选归并 (ParagraphCandidateAggregator):把 Dense/BM25 命中的多个句子合并为唯一段落,同时保留命中子节点与查询来源。
    • 语义重排 (CrossEncoderReranker):默认将前 30 个段落交给 Qwen/Qwen3-Reranker-0.6B 做 Query-Document 联合打分;接口失败时保留融合排序,不中断问答。
    • 覆盖度与去重 (CoverageMMRSelector):先覆盖不同查询意图,再以 Reranker 相关性和向量相似度执行 MMR,最终返回 8~12 个上下文(默认 10)。
    • 原有 FrequencyRerankerDiversityReranker 仍可通过 --reranker both 用于基线对照。
  3. Small-to-Big 分层上下文追溯 (ContextGraph)
    • parent_depth 表示语义目标层:0 为句子、1 为段落、2 为最近章节;不会因起始节点类型不同而意外多升一级。
    • 去重合并后生成包含完整上下文语义的 ContextSnippet,并保留触发该片段的全部叶子节点 ID。

阶段 4 & 5:上下文组装、LLM 生成与交互问答 (Generation & CLI)

  1. 上下文结构化组装 (ContextBuilder)
    • ContextSnippet 转义后放入明确标记为“不可信外部数据”的 <reference> 块,为每个片段分配唯一引用标记(如 [ref_1], [ref_2])。
    • 系统提示明确禁止执行参考资料中的指令、角色切换、工具调用或提示词泄露要求,降低知识库 Prompt Injection 风险。
  2. LLM 推理与流式输出 (LLMClient)
    • 封装 OpenAI 兼容接口,支持非流式完整生成(acomplete)与异步迭代器打字机流式生成(acomplete_stream)。
  3. 可核验引用解析 (extract_citations)
    • 提取 [ref_X] 标签后,对标签前的陈述与来源执行实体、术语、数值词法支撑校验;无支撑的装饰性或错误引用不会进入结构化引用清单。
  4. 统一引擎驱动与 CLI 交互 (engine.py / main.py)
    • EasyRAG 门面类提供统一的高层 API(indexretrievequerychatpreview 等)。
    • 多轮问答会把近期 user/assistant 历史加入检索查询,用于消解“他/它/后来”等指代和省略。

评测

评测数据生成

从原始知识库文档中采样真实内容,并基于采样内容自动生成评测问题。

原始文档
  ↓
采样文档 / Chunk
  ↓
生成问题
  ↓
基于原文生成 Reference Answer
  ↓
记录对应 Evidence
  ↓
生成结构化 Evaluation Dataset

生成器默认启用质量闭环:

  1. 先过滤寒暄、转场、短反问等低信息段落;多跳与对比题通过实体桥梁 + BM25 选择“主题相关但信息不同”的段落,不再随机硬拼。
  2. 总结题自顶向下读取完整章节(超长章节按 EVAL_SECTION_MAX_CHARS 顺序截断)。
  3. Evidence 的 quote 必须逐字存在于本次出题上下文,node ID 必须与真实句子一致;无法核验的样本直接废弃,不生成兜底证据。
  4. 独立 Critic 只读取 Evidence 反向答题;不可回答题会先在完整段落库检索最相关候选,再确认全库确实缺少答案。建议通过 EVAL_CRITIC_MODEL 配置不同于出题模型的 Critic。
  5. 断点续传前会重新核对已有 Evidence 的节点 ID、文档 ID 和原文;语料、分块或文档身份规则变化时拒绝混合续跑,并提示使用 --force 全量重建。
  6. 正式评测会在检索和模型调用前执行相同的索引兼容性预检,旧评测集不会再产生整组虚假 0 分。

每条评测数据同时保存:

  • id: id
  • question:评测问题
  • reference_answer:基于原文生成的参考答案
  • evidence:答案对应的原始证据
  • difficulty:问题难度
  • question_type:问题类型
  • answerable:当前知识库是否能够回答该问题

这样一份数据既可以用于 RAG 检索评测,也可以用于 最终回答质量评测

可回答问题

ok = {
    "id": "qa_001",
    "question": "李长庚为什么心疼老鹤?",
    "reference_answer": "因为老鹤寿元将尽,羽毛不容易重新长出。",
    "evidence": [
        {
            "document_id": "xxx",
            "node_id": "xxx:sec1:p3:s1",
            "quote": "这鹤太老了,再想长出新羽可不容易。",
            "relevance": 3,
        },
    ],
    "difficulty": "easy",
    "question_type": "single_hop_reasoning",
    "answerable": True,
}

不可回答问题

not_ok = {
    "id": "qa_002",
    "question": "李长庚第一次见到老鹤是在什么时候?",
    "reference_answer": None,
    "evidence": [],
    "difficulty": "easy",
    "question_type": "unanswerable",
    "answerable": False,
}

Question Type

  • single_hop_fact:单个 Evidence 即可直接找到答案。
  • single_hop_reasoning:基于单个或连续上下文,需要简单推理才能得到答案。
  • multi_hop_fact:需要组合多个 Evidence 中的事实才能回答。
  • multi_hop_reasoning:需要组合多个 Evidence,并进一步进行推理。
  • summary:需要总结一段或多段内容。
  • comparison:需要比较两个或多个对象、事件或观点。
  • unanswerable:现有知识库中不存在足够证据回答。

Evidence Relevance

  • 0 = irrelevant (无关)
  • 1 = weakly relevant (弱相关 / 背景补充)
  • 2 = supporting evidence (关键支撑依据)
  • 3 = direct / necessary evidence (直接 / 必要证据)

评测常用命令

功能阶段 执行命令 参数与说明 API / Token 消耗
自动生成评测集 uv run eval.py generate -i tests/docs/太白金星有点烦.txt -o data/eval_dataset.json -n 100 --force重跑,从文档中分层采样并生成 20 条覆盖 7 种题型的评测样本 🟢 消耗 LLM 生成
从知识库生成评测集 uv run eval.py generate -o data/eval_dataset.json -n 100 直接从当前 LanceDB 已索引知识库中采样 🟢 消耗 LLM 生成
生成指定题型样本 uv run eval.py generate -i tests/docs/太白金星有点烦.txt -t single_hop_fact,multi_hop_fact,unanswerable -n 15 -t / --types:指定生成的题型子集 🟢 消耗 LLM 生成
查看评测集统计分布 uv run eval.py stats -d data/eval_dataset.json 查看样本数、可回答/拒答分布、题型与难度统计 ❌ 零消耗
查看评测集样本明细 uv run eval.py inspect -d data/eval_dataset.json -n 5 -n / --limit:预览前 5 条样本及其精确证据引用 ❌ 零消耗
筛选特定题型查看 uv run eval.py inspect -d data/eval_dataset.json -t unanswerable -t / --type:按题型过滤查看样本 ❌ 零消耗
运行全链路综合评测 uv run eval.py run -d data/eval_dataset.json -o data/eval_report.json 执行检索(Hit@K, MRR, NDCG)与回答质量(LLM-Judge)综合评测 🟢 消耗 Embedding + LLM
仅运行检索质量评测 uv run eval.py run -d data/eval_dataset.json --mode retrieval --top-k 5 --mode retrieval:跳过回答生成与裁判,仅评估召回率与排序 🟢 仅消耗 Embedding
关闭规则扩展做消融 uv run eval.py run -d data/eval_dataset.json --mode retrieval --no-rule-query-expansion 独立关闭本地规则扩展,不影响 LLM 多查询开关 🟢 仅消耗 Embedding
多查询扩展 + 重排序评测 uv run eval.py run -d data/eval_dataset.json --multi-query --reranker both 评测在开启意图扩展与双重重排下的综合召回表现 🟢 消耗 Embedding + LLM

评测报告默认保存 Dense、BM25、RRF、重排和最终上下文各阶段的候选与得分;可用 --no-retrieval-trace 关闭。生成指标同时报告“失败样本保留在分母中的端到端口径”和“仅成功裁判样本口径”。索引 SHA256 是逻辑内容指纹:由文件哈希、节点身份/文本及 Embedding 配置组成,不包含每次重建都会变化的 indexed_at。因此相同文件和配置重新建库后指纹保持稳定;重建时间仍会单独保留在文档元数据中。

问题类型路由(第三阶段)

aretrieve/query 会先识别问题类型并选择检索链路:事实题走 Hybrid → Cross-Encoder → Small-to-Big;比较题拆成两个实体子查询并交错保留双方证据;多跳题拆解后分别召回,候选不足时自动补充检索;章节总结优先返回章节节点并补充段落;全库主题总结以章节节点作为 map 单元。路由结果写入 retrieval trace 的 query_route 字段。

About

文档层级建模、多粒度 embedding 和父子上下文扩展。模块化、可恢复、可解释的 RAG 库, 使用 LanceDB 作为向量数据库.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages