RAG 检索增强

RAG 质量取决于分块粒度、检索策略与引用绑定三个环节。本页给出三种分块策略对比、BM25+向量混合检索的实现代码、引用格式规范,以及「检索到了但没用到」的常见失败模式分析。

RAG 管线「分块 → 嵌入 → 检索 → 重排 → 拼装 → 生成」每一步都有独立的失败模式。调试时先验证「召回是否包含正确答案块」,再查「重排是否把它顶进 top-k」,最后才调生成提示词。

RAG 流水线(示意)

下列 ASCII 描述概念顺序;实现上可把「查询改写」「权限过滤」插在检索前后不同位置,但元数据与引用 id 应自洽贯通。

  [ 原始文档 / API / 爬虫 ]
              │
              ▼
        [ 清洗:去重 / 版本 / 许可标记 ]
              │
              ▼
        [ 分块 + 元数据:标题路径 / URI / 段落锚点 ]
              │
              ▼
        [ 嵌入写入向量索引 ] ◄──── [ 稀疏索引:BM25 等 ]
              │
              ▼
  ┌─────────────────────────────────────┐
  │  查询侧:改写(可选)→ 混合检索 top-N   │
  │           → 交叉编码器重排 top-k      │
  │           → 上下文预算内拼装 + 引用表   │
  └─────────────────────────────────────┘
              │
              ▼
        [ LLM:仅依据片段作答 / 拒答 / 输出引用 ]
  • 表格、代码块、列表建议单独分块策略,避免与叙述混切导致语义断裂。
  • 嵌入模型语种与业务语料一致;跨语种场景显式标注或分索引。

分块策略对比 — 何时用哪种

三种主流分块策略各有适用场景,参数选择直接影响检索命中率:

┌──────────────┬────────────────┬──────────────────────────┬────────────────────────────┐
│ 策略          │ chunk_size     │ 适合场景                  │ 主要风险                    │
├──────────────┼────────────────┼──────────────────────────┼────────────────────────────┤
│ 固定大小      │ 512–1024 token │ 纯文本、日志、无结构文档   │ 截断句子/段落,语义断裂      │
│              │ overlap: 10%   │                          │                            │
├──────────────┼────────────────┼──────────────────────────┼────────────────────────────┤
│ 语义分块      │ 自适应         │ 文章/论文/有段落结构的文档  │ 块大小不均,大块占用 token 多 │
│ (NLTK/spaCy) │ avg 300–600 tok│                          │                            │
├──────────────┼────────────────┼──────────────────────────┼────────────────────────────┤
│ 递归分块      │ 先按 \n\n,    │ Markdown/HTML/代码库      │ 需维护分隔符优先级列表        │
│ (LangChain   │ 再 \n,再空格  │ 有标题结构的文档           │                            │
│  RecursiveTC)│ max 1024 token │                          │                            │
└──────────────┴────────────────┴──────────────────────────┴────────────────────────────┘

# 推荐参数(Python / LangChain):
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,        # 字符数,中文文档约 500–800,英文约 800–1200
    chunk_overlap=80,      # overlap = chunk_size × 10%,降低边界截断
    separators=["\n\n", "\n", "。", ".", " ", ""],  # 优先级从高到低
    length_function=len,   # 改为 tiktoken 计数可得到精确 token 数
)

# metadata 必须写入:
{
  "source": "docs/install-guide.md",    # 文档路径
  "section": "§3.2 环境变量配置",        # 标题路径(H1 > H2 > H3)
  "chunk_index": 7,                     # 块在文档中的顺序
  "updated_at": "2024-03-01",           # 文档更新时间,用于过期过滤
  "doc_version": "v2.4.1"               # 文档版本号
}
  • overlap 计算:chunk_size=800 时,overlap=80(10%)是经验下限;中文叙述文档可提高到 15%(120 字),因为中文每句信息密度更高。
  • 表格/代码块:整体作为一个块,不做内部切分;超过 max 时截断前加注释 # (truncated, full at {uri})

检索与重排

纯向量检索易漏精确词与专有名词;关键词稀疏检索易噪声大。常见做法:两路各取候选,融合分数后再用小型交叉编码器对 top-N 重排,仅把 top-k 送入生成。

  • 查询改写:多查询扩展或 HyDE 视场景启用,并在 SKILL 中写明副作用(延迟、成本、漂移)。
  • 融合:RRF、加权线性或学习排序;记录各路的命中贡献便于调参。
  • 重排:交叉编码器 batch 与截断长度固定,避免线上与离线评测不一致。
  • 空结果:定义降级路径(扩召回、换索引、提示用户收窄问题),并监控「检索为空率」。
调试顺序:先看「召回是否含正确答案块」,再看重排是否把正确答案顶进 top-k,最后才调提示词。

引用与生成约束

提示中要求模型仅依据检索片段作答;每条论断绑定引用 id(与向量库 metadata 一致)。无足够依据时输出结构化拒答,而非编造。

  • 引用格式:例如 [doc_id § 小节][^chunk_uuid],与 UI 可点击锚点一致。
  • 冲突片段:若检索结果互相矛盾,要求模型列出矛盾点并降低结论确定性。
  • SKILL 清单项:索引更新频率、权限过滤、PII 脱敏规则、许可证是否允许摘要外传。

分块字符估算器

下方为纯前端示意:用常见经验比值把「目标 token/块」换算成大致字符上限,并用固定字符窗口对样本文本做 naive 分块计数(不调用真实 tokenizer,仅供配置初值)。

块数:—(请先输入文本)

Token→字符按英文约 1∶3.5–4、中日文约 1∶1.2–1.8 的区间展示;真实以所用 tokenizer 为准。

评测与运维

离线:命中率、MRR、nDCG、人工相关性抽检;线上:检索为空率、拒答率、引用点击率、用户纠错回流。防止索引静默退化(嵌入模型更换未全量重嵌入等)。

  • 查询改写:记录改写前后召回差异,避免「改写放大漂移」。
  • 版本:索引 schema、嵌入模型版本、重排模型版本写入发布说明与回滚预案。
---
name: rag-retrieval-pipeline
description: 设计或审查 RAG 检索与引用流程
---
# 步骤
1. 分块与元数据、索引更新
2. 检索:向量/关键词/重排
3. 生成:引用格式、拒答与评测

返回技能库 更多技能入口