Ch38: 挑战深读①——检索最后一公里
Part 10: 16 挑战大师课(Phase F)· 对应挑战 #1 完整版:技术挑战 §1 · 前置:Ch25 RRF · 半 Agentic:Ch12
结论先行:用户要的是 正确答案,不是 相关文档。RAG 的「最后一公里」发生在召回之后——chunk 语义相关却不足以构造答案、答案分散在多个 chunk、或新旧文档时效冲突。解法不是再加一路召回,而是 融合 → Rerank → 查询改写 → 半 Agentic 二次检索 → 拒答 的分层防线。
一、日常类比:为什么「相关」不够
你在百度搜「Python 怎么读取 Excel」,标题完全匹配的文章是 2018 年写的,用的是已在 2023 年停更 xlsx 支持的 xlrd。搜索引擎认为相关度很高,对你却 有害——RAG 里 LLM 不会说「我不知道」,更倾向基于不完整上下文 编造 一个看起来合理的数字或步骤。
传统搜索把判断交给 人脑;RAG 把判断交给 模型,而模型对「谈论 X」与「给出 X 的精确值」几乎无法区分——这就是最后一公里比搜索引擎更难的根本原因。
二、三种失败形态与根因
| 形态 | 典型 query | 检索表现 | 根因 |
|---|---|---|---|
| 语义相关但答案错误 | 「WeKnora 支持几个向量库?」 | 命中讨论向量检索 设计理念 的段落,无具体数字 | 嵌入把「讨论向量库」与「列出个数」映射到相近向量;LLM 补全幻觉 |
| 答案跨 chunk | 「三路混合检索的完整流程?」 | BM25 在 A、向量在 B、图谱在 C、RRF 在 D 各一块 | 信息按作者表达组织,检索按 chunk 孤立 评分,无「组合可答性」 |
| 时效性冲突 | 「当前支持几个向量库?」 | 旧版「8 个」与新版「10 个」同时进 context | 评分只有语义/关键词,无时间维;元数据 rarely 参与 Rerank |
三种形态在 benchmark 中已有标注样例:zh-006 专测 版本冲突与来源可信度;zh-007 定义 最后一公里 概念本身(见 lab/benchmark/smoke-10.jsonl)。贡献 benchmark 时建议单独建 last-mile 子集,覆盖上述三类而非混在 factual 题里。
三、五平台对策矩阵
| 手段 | WeKnora | RAGFlow | Dify | FastGPT | AnythingLLM |
|---|---|---|---|---|---|
| 多路召回 | ★★★ 三路 BM25+向量+图谱 | ★★ 双路+DeepDoc 结构 | ★★ 可编排多节点 | ★★ 向量+$text | ★ 纯向量 |
| RRF + Rerank | ★★★ 复合三信号 0.6/0.3/0.1 | ★★ 单 Rerank | ★★ 节点可配 | ★ 线性插值 | ★ 无 Rerank |
| 来源/时效权重 | ★★ source_credibility | ☆ 结构≠时效 | ☆ 需人工 Workflow | ☆ | ☆ Memory 可能加剧矛盾 |
| 查询扩展 | ☆ 可自研 | ☆ | ★★ 迭代节点 | ★★ QA 扩展 | ☆ |
| 拒答/低分阈值 | 需自实现 | 部分 | ★ 条件分支 | 配额 | Memory 兜底 |
读矩阵的方法:FastGPT 的 QA 扩展解决 召回覆盖率,不解决 答案可构造性;RAGFlow DeepDoc 保证结构正确,不等于内容最新;WeKnora 复合 Rerank 是当前五平台中对最后一公里 最深 的内建设计,但来源可信度仍依赖元数据规则而非自动推断。
四、大师诊断流程
用户答案错
└─ 检索到的 top chunk 是否含 ground truth 事实?
├─ 否 → 召回问题(Ch24–26:BM25/向量/图谱/RRF)
├─ 是但排序靠后 → Rerank 或 top_k 问题(Ch25)
├─ 部分在各 chunk → 跨 chunk / 需二次检索 / 分块策略(Ch40)
└─ 是但新旧矛盾 → 时效 + 来源可信度(Ch31 Wiki lint)
└─ 召回对、生成仍编 → prompt / faithfulness / 拒答
区分 召回失败 与 最后一公里失败 是改代码前的第一步:前者加 top_k 有用;后者加 top_k 只会把更多「相关但无用」的 chunk 塞进 context,加剧幻觉。
五、半 Agentic 低分重试(生产默认)
全 Agentic 让 LLM 自主决定查几次,延迟与成本不可控(见 Ch12)。半 Agentic 保留固定管线,仅在低置信度分支触发二次检索:
query → hybrid_search(top_k=5) → Rerank → max_score
├─ score ≥ θ → 直接生成 + 强制 citation
└─ score < θ → query_rewrite(缺什么事实?) → 第二次检索(top_k=10)
├─ 仍 < θ → 拒答:「知识库无直接答案」
└─ ≥ θ → 生成,引用两次检索 union 的 chunk
WeKnora 可贡献点:在 Rerank 后挂 rewrite 钩子(非全 Agent 循环);source_credibility 与 document.version 进入第二次 Rerank 加权 Ch31;Citation 强制——无 chunk 分数超过 θ 则拒答,避免 Chain-of-Note 式的额外 LLM 轮次也可先用规则 θ 替代。
六、实验:Ch20 脚本与 hard 题扩展
Ch20 中文 RAG Benchmark 提供评估闭环:
| 资产 | 路径 |
|---|---|
| 冒烟集(含 zh-006/007) | research/rag-knowledge/benchmark/smoke-10.jsonl |
| 评估脚本 | eval_weknora_ragas.py(Ch20 §四) |
| 语料 | lab/corpus/faq-version-conflict.md(zh-006 关联) |
建议消融(最后一公里专向):
- 在 smoke-10 基础上 加 5 条跨 chunk hard 题(如「从 ingest 到检索的完整链路」需 3+ chunk)
- 对比
top_k=5vs10vs 半 Agentic 二次检索 - 记录 RAGAS Context Precision + 人工判「是否含可构造事实」——后者是 RAGAS 盲区,但对挑战 #1 更敏感
前沿参考:Query-Aware Rerank、Chain-of-Note。竞赛 PR 优先 last-mile 子集 + 消融表。耦合:#3 分块 → Ch40;#6 向量 → Ch43;#14 评估 → Ch47。
章末自检
- 用一句话向非技术同学解释「最后一公里」与「召回率」的区别
- 举一例时效冲突,并说明为何纯向量检索无法自动消解
- 画出半 Agentic 流程:θ、rewrite、拒答各在什么条件下触发
- 在 smoke-10.jsonl 中找到 zh-006、zh-007 并解释其 tags