第19章 RAG(Retrieval-Augmented Generation)

第19章 RAG(Retrieval-Augmented Generation)

本章目标:

理解 RAG 的完整流程,包括 Chunk、Embedding、Retrieval、Reranker 和 Prompt 设计。


本章目录

  • 19.1 为什么需要 RAG? ------ LLM 的知识截止与幻觉问题,RAG 如何解决
  • 19.2 RAG 的完整流程 ------ 从文档入库到检索生成的全链路
  • 19.3 Chunking(文档分块) ------ RAG 中对效果影响最大的环节
    • 19.3.1 为什么要分块?
    • 19.3.2 Chunk Size 的选择
    • 19.3.3 Chunk Overlap(重叠)
    • 19.3.4 分块策略
    • 19.3.5 变长切分:chunk 大小不必统一
    • 19.3.6 语义切分及其缺陷(含论文场景的超长块问题)
    • 19.3.7 进阶:LLM 切分与 Contextual Retrieval
    • 19.3.8 没有万能切法:按文档类型选择策略
  • 19.4 Tokenizer Splitter ------ 按 token 精确控制 chunk 长度
  • 19.5 Embedding 与存储 ------ 向量库存的是"向量 + 原文",embedding 不可逆
  • 19.6 Retriever(检索器) ------ Top-K 召回相关 chunk
  • 19.7 Reranker(重排序) ------ 两阶段检索,用 Cross-Encoder 精排
  • 19.8 Prompt 设计 ------ 把检索结果拼进 Prompt 交给 LLM
  • 19.9 完整 RAG 系统 ------ 端到端可运行代码
  • 19.10 RAG 的评估 ------ 如何量化对比两次切分/改动的优劣
    • 19.10.1 核心思想:评估下游效果,不是切分本身
    • 19.10.2 检索层评估(Recall@K / MRR / NDCG)
    • 19.10.3 回答层评估(Faithfulness / Answer Relevance)
    • 19.10.4 线上评估(A/B 测试)
    • 19.10.5 关键:控制变量
    • 19.10.6 最小可行流程
    • 19.10.7 测试集是评估的地基
  • 19.11 RAG 的常见问题与解决方案

19.1 为什么需要 RAG?

LLM 有两个核心问题:

  1. 知识截止:训练数据有截止日期,不知道最新信息
  2. 幻觉(Hallucination):LLM 会自信地说出错误信息

RAG 的解决方案:
在生成回答之前,先从知识库中检索相关文档,然后把文档内容提供给 LLM。
#mermaid-svg-rBVSGEpLYEFgp7np{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rBVSGEpLYEFgp7np .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rBVSGEpLYEFgp7np .error-icon{fill:#552222;}#mermaid-svg-rBVSGEpLYEFgp7np .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rBVSGEpLYEFgp7np .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rBVSGEpLYEFgp7np .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rBVSGEpLYEFgp7np .marker.cross{stroke:#333333;}#mermaid-svg-rBVSGEpLYEFgp7np svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rBVSGEpLYEFgp7np p{margin:0;}#mermaid-svg-rBVSGEpLYEFgp7np .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rBVSGEpLYEFgp7np .cluster-label text{fill:#333;}#mermaid-svg-rBVSGEpLYEFgp7np .cluster-label span{color:#333;}#mermaid-svg-rBVSGEpLYEFgp7np .cluster-label span p{background-color:transparent;}#mermaid-svg-rBVSGEpLYEFgp7np .label text,#mermaid-svg-rBVSGEpLYEFgp7np span{fill:#333;color:#333;}#mermaid-svg-rBVSGEpLYEFgp7np .node rect,#mermaid-svg-rBVSGEpLYEFgp7np .node circle,#mermaid-svg-rBVSGEpLYEFgp7np .node ellipse,#mermaid-svg-rBVSGEpLYEFgp7np .node polygon,#mermaid-svg-rBVSGEpLYEFgp7np .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rBVSGEpLYEFgp7np .rough-node .label text,#mermaid-svg-rBVSGEpLYEFgp7np .node .label text,#mermaid-svg-rBVSGEpLYEFgp7np .image-shape .label,#mermaid-svg-rBVSGEpLYEFgp7np .icon-shape .label{text-anchor:middle;}#mermaid-svg-rBVSGEpLYEFgp7np .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rBVSGEpLYEFgp7np .rough-node .label,#mermaid-svg-rBVSGEpLYEFgp7np .node .label,#mermaid-svg-rBVSGEpLYEFgp7np .image-shape .label,#mermaid-svg-rBVSGEpLYEFgp7np .icon-shape .label{text-align:center;}#mermaid-svg-rBVSGEpLYEFgp7np .node.clickable{cursor:pointer;}#mermaid-svg-rBVSGEpLYEFgp7np .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rBVSGEpLYEFgp7np .arrowheadPath{fill:#333333;}#mermaid-svg-rBVSGEpLYEFgp7np .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rBVSGEpLYEFgp7np .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rBVSGEpLYEFgp7np .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rBVSGEpLYEFgp7np .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rBVSGEpLYEFgp7np .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rBVSGEpLYEFgp7np .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rBVSGEpLYEFgp7np .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rBVSGEpLYEFgp7np .cluster text{fill:#333;}#mermaid-svg-rBVSGEpLYEFgp7np .cluster span{color:#333;}#mermaid-svg-rBVSGEpLYEFgp7np div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rBVSGEpLYEFgp7np .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rBVSGEpLYEFgp7np rect.text{fill:none;stroke-width:0;}#mermaid-svg-rBVSGEpLYEFgp7np .icon-shape,#mermaid-svg-rBVSGEpLYEFgp7np .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rBVSGEpLYEFgp7np .icon-shape p,#mermaid-svg-rBVSGEpLYEFgp7np .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rBVSGEpLYEFgp7np .icon-shape .label rect,#mermaid-svg-rBVSGEpLYEFgp7np .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rBVSGEpLYEFgp7np .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rBVSGEpLYEFgp7np .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rBVSGEpLYEFgp7np :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户问题
检索器

Retriever
知识库

向量数据库
相关文档
LLM
基于文档的回答


19.2 RAG 的完整流程

#mermaid-svg-MiuWPaCnpLGekYar{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MiuWPaCnpLGekYar .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MiuWPaCnpLGekYar .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MiuWPaCnpLGekYar .error-icon{fill:#552222;}#mermaid-svg-MiuWPaCnpLGekYar .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MiuWPaCnpLGekYar .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MiuWPaCnpLGekYar .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MiuWPaCnpLGekYar .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MiuWPaCnpLGekYar .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MiuWPaCnpLGekYar .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MiuWPaCnpLGekYar .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MiuWPaCnpLGekYar .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MiuWPaCnpLGekYar .marker.cross{stroke:#333333;}#mermaid-svg-MiuWPaCnpLGekYar svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MiuWPaCnpLGekYar p{margin:0;}#mermaid-svg-MiuWPaCnpLGekYar .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MiuWPaCnpLGekYar .cluster-label text{fill:#333;}#mermaid-svg-MiuWPaCnpLGekYar .cluster-label span{color:#333;}#mermaid-svg-MiuWPaCnpLGekYar .cluster-label span p{background-color:transparent;}#mermaid-svg-MiuWPaCnpLGekYar .label text,#mermaid-svg-MiuWPaCnpLGekYar span{fill:#333;color:#333;}#mermaid-svg-MiuWPaCnpLGekYar .node rect,#mermaid-svg-MiuWPaCnpLGekYar .node circle,#mermaid-svg-MiuWPaCnpLGekYar .node ellipse,#mermaid-svg-MiuWPaCnpLGekYar .node polygon,#mermaid-svg-MiuWPaCnpLGekYar .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MiuWPaCnpLGekYar .rough-node .label text,#mermaid-svg-MiuWPaCnpLGekYar .node .label text,#mermaid-svg-MiuWPaCnpLGekYar .image-shape .label,#mermaid-svg-MiuWPaCnpLGekYar .icon-shape .label{text-anchor:middle;}#mermaid-svg-MiuWPaCnpLGekYar .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MiuWPaCnpLGekYar .rough-node .label,#mermaid-svg-MiuWPaCnpLGekYar .node .label,#mermaid-svg-MiuWPaCnpLGekYar .image-shape .label,#mermaid-svg-MiuWPaCnpLGekYar .icon-shape .label{text-align:center;}#mermaid-svg-MiuWPaCnpLGekYar .node.clickable{cursor:pointer;}#mermaid-svg-MiuWPaCnpLGekYar .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MiuWPaCnpLGekYar .arrowheadPath{fill:#333333;}#mermaid-svg-MiuWPaCnpLGekYar .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MiuWPaCnpLGekYar .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MiuWPaCnpLGekYar .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MiuWPaCnpLGekYar .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MiuWPaCnpLGekYar .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MiuWPaCnpLGekYar .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MiuWPaCnpLGekYar .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MiuWPaCnpLGekYar .cluster text{fill:#333;}#mermaid-svg-MiuWPaCnpLGekYar .cluster span{color:#333;}#mermaid-svg-MiuWPaCnpLGekYar div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MiuWPaCnpLGekYar .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MiuWPaCnpLGekYar rect.text{fill:none;stroke-width:0;}#mermaid-svg-MiuWPaCnpLGekYar .icon-shape,#mermaid-svg-MiuWPaCnpLGekYar .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MiuWPaCnpLGekYar .icon-shape p,#mermaid-svg-MiuWPaCnpLGekYar .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MiuWPaCnpLGekYar .icon-shape .label rect,#mermaid-svg-MiuWPaCnpLGekYar .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MiuWPaCnpLGekYar .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MiuWPaCnpLGekYar .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MiuWPaCnpLGekYar :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 在线阶段 检索生成
离线阶段 建库
原始文档

PDF/Word/网页
文档解析
Chunking

分块
Embedding

向量化
向量数据库

存储
用户 Query
Query Embedding
向量检索

Top-K
Reranker

重排序
构建 Prompt
LLM 生成
最终回答


19.3 Chunking(文档分块)

19.3.1 为什么要分块?

  • Embedding Model 有最大长度限制(通常 512 Token)
  • 太长的文档向量化后语义模糊
  • 检索时需要精确定位相关段落

19.3.2 Chunk Size 的选择

Chunk Size 优点 缺点
小(128-256 Token) 精确,语义集中 可能截断完整语义
中(512 Token) 平衡 常用选择
大(1024+ Token) 上下文完整 语义模糊,检索不精确

19.3.3 Chunk Overlap(重叠)

为了避免在 Chunk 边界截断重要信息,通常设置重叠:

text 复制代码
Chunk 1: [Token 1 ... Token 512]
Chunk 2: [Token 462 ... Token 973]  ← 重叠 50 Token
Chunk 3: [Token 923 ... Token 1434]

#mermaid-svg-ImoEVIvjaXaO7FsG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ImoEVIvjaXaO7FsG .error-icon{fill:#552222;}#mermaid-svg-ImoEVIvjaXaO7FsG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ImoEVIvjaXaO7FsG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ImoEVIvjaXaO7FsG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ImoEVIvjaXaO7FsG .marker.cross{stroke:#333333;}#mermaid-svg-ImoEVIvjaXaO7FsG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ImoEVIvjaXaO7FsG p{margin:0;}#mermaid-svg-ImoEVIvjaXaO7FsG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster-label text{fill:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster-label span{color:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster-label span p{background-color:transparent;}#mermaid-svg-ImoEVIvjaXaO7FsG .label text,#mermaid-svg-ImoEVIvjaXaO7FsG span{fill:#333;color:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG .node rect,#mermaid-svg-ImoEVIvjaXaO7FsG .node circle,#mermaid-svg-ImoEVIvjaXaO7FsG .node ellipse,#mermaid-svg-ImoEVIvjaXaO7FsG .node polygon,#mermaid-svg-ImoEVIvjaXaO7FsG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ImoEVIvjaXaO7FsG .rough-node .label text,#mermaid-svg-ImoEVIvjaXaO7FsG .node .label text,#mermaid-svg-ImoEVIvjaXaO7FsG .image-shape .label,#mermaid-svg-ImoEVIvjaXaO7FsG .icon-shape .label{text-anchor:middle;}#mermaid-svg-ImoEVIvjaXaO7FsG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ImoEVIvjaXaO7FsG .rough-node .label,#mermaid-svg-ImoEVIvjaXaO7FsG .node .label,#mermaid-svg-ImoEVIvjaXaO7FsG .image-shape .label,#mermaid-svg-ImoEVIvjaXaO7FsG .icon-shape .label{text-align:center;}#mermaid-svg-ImoEVIvjaXaO7FsG .node.clickable{cursor:pointer;}#mermaid-svg-ImoEVIvjaXaO7FsG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ImoEVIvjaXaO7FsG .arrowheadPath{fill:#333333;}#mermaid-svg-ImoEVIvjaXaO7FsG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ImoEVIvjaXaO7FsG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ImoEVIvjaXaO7FsG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ImoEVIvjaXaO7FsG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ImoEVIvjaXaO7FsG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ImoEVIvjaXaO7FsG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster text{fill:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG .cluster span{color:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ImoEVIvjaXaO7FsG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ImoEVIvjaXaO7FsG rect.text{fill:none;stroke-width:0;}#mermaid-svg-ImoEVIvjaXaO7FsG .icon-shape,#mermaid-svg-ImoEVIvjaXaO7FsG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ImoEVIvjaXaO7FsG .icon-shape p,#mermaid-svg-ImoEVIvjaXaO7FsG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ImoEVIvjaXaO7FsG .icon-shape .label rect,#mermaid-svg-ImoEVIvjaXaO7FsG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ImoEVIvjaXaO7FsG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ImoEVIvjaXaO7FsG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ImoEVIvjaXaO7FsG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 文档
Chunk 1

1-512
Chunk 2

462-973

重叠50
Chunk 3

923-1434

重叠50

19.3.4 分块策略

策略 说明 适用场景
固定大小 按 Token 数量切分 简单,通用
句子分割 按句子边界切分 保持语义完整
段落分割 按段落切分 结构化文档
语义分割 按语义相似度切分 效果最好,复杂
递归分割 先大后小,递归切分 LangChain 默认

19.3.5 变长切分:chunk 大小不必统一

一个常见误解是"一篇文档必须用统一的 chunk size"。其实完全可以变长,而且这往往是更好的做法。因为一篇文档内部的语义单元本来就有长有短:

  • 一段简短的定义 → 切成小 chunk(几十 token)
  • 一段复杂的推导 → 保留成大 chunk(几百 token)
  • 一张表格 → 整张表作为一个 chunk(不拦腰切断)

只要每个 chunk 是"一个完整、独立、能被理解的语义单元"即可。前面提到的按段落、按句子、按结构切,天然产生的就是不等长的 chunk------固定 size 反而是为了实现简单而做的妥协。

19.3.6 语义切分及其缺陷

语义切分(Semantic Chunking) 的思路是:不按字数硬切,而是逐句计算 Embedding,在"语义突变"处下刀。

text 复制代码
逐句算 embedding → 相邻句子相似度高 = 同一主题,合在一起
                → 相似度突然下降 = 话题变了,在这里切一刀

它比固定字数切更能保持语义完整,比 LLM 切分便宜(LlamaIndex、LangChain 都有现成的 SemanticChunker)。但它有一个重要缺陷:
对于话题高度连贯的文档(如论文的某一节) ,相邻句子相似度一直很高,语义切分找不到"突变点",会把一整节切成一个巨大的 chunk,从而超过 Embedding 模型的长度上限。
#mermaid-svg-M0ttsZPum70jOHOw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-M0ttsZPum70jOHOw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-M0ttsZPum70jOHOw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-M0ttsZPum70jOHOw .error-icon{fill:#552222;}#mermaid-svg-M0ttsZPum70jOHOw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-M0ttsZPum70jOHOw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-M0ttsZPum70jOHOw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-M0ttsZPum70jOHOw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-M0ttsZPum70jOHOw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-M0ttsZPum70jOHOw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-M0ttsZPum70jOHOw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-M0ttsZPum70jOHOw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-M0ttsZPum70jOHOw .marker.cross{stroke:#333333;}#mermaid-svg-M0ttsZPum70jOHOw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-M0ttsZPum70jOHOw p{margin:0;}#mermaid-svg-M0ttsZPum70jOHOw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-M0ttsZPum70jOHOw .cluster-label text{fill:#333;}#mermaid-svg-M0ttsZPum70jOHOw .cluster-label span{color:#333;}#mermaid-svg-M0ttsZPum70jOHOw .cluster-label span p{background-color:transparent;}#mermaid-svg-M0ttsZPum70jOHOw .label text,#mermaid-svg-M0ttsZPum70jOHOw span{fill:#333;color:#333;}#mermaid-svg-M0ttsZPum70jOHOw .node rect,#mermaid-svg-M0ttsZPum70jOHOw .node circle,#mermaid-svg-M0ttsZPum70jOHOw .node ellipse,#mermaid-svg-M0ttsZPum70jOHOw .node polygon,#mermaid-svg-M0ttsZPum70jOHOw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-M0ttsZPum70jOHOw .rough-node .label text,#mermaid-svg-M0ttsZPum70jOHOw .node .label text,#mermaid-svg-M0ttsZPum70jOHOw .image-shape .label,#mermaid-svg-M0ttsZPum70jOHOw .icon-shape .label{text-anchor:middle;}#mermaid-svg-M0ttsZPum70jOHOw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-M0ttsZPum70jOHOw .rough-node .label,#mermaid-svg-M0ttsZPum70jOHOw .node .label,#mermaid-svg-M0ttsZPum70jOHOw .image-shape .label,#mermaid-svg-M0ttsZPum70jOHOw .icon-shape .label{text-align:center;}#mermaid-svg-M0ttsZPum70jOHOw .node.clickable{cursor:pointer;}#mermaid-svg-M0ttsZPum70jOHOw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-M0ttsZPum70jOHOw .arrowheadPath{fill:#333333;}#mermaid-svg-M0ttsZPum70jOHOw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-M0ttsZPum70jOHOw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-M0ttsZPum70jOHOw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M0ttsZPum70jOHOw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-M0ttsZPum70jOHOw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M0ttsZPum70jOHOw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-M0ttsZPum70jOHOw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-M0ttsZPum70jOHOw .cluster text{fill:#333;}#mermaid-svg-M0ttsZPum70jOHOw .cluster span{color:#333;}#mermaid-svg-M0ttsZPum70jOHOw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-M0ttsZPum70jOHOw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-M0ttsZPum70jOHOw rect.text{fill:none;stroke-width:0;}#mermaid-svg-M0ttsZPum70jOHOw .icon-shape,#mermaid-svg-M0ttsZPum70jOHOw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M0ttsZPum70jOHOw .icon-shape p,#mermaid-svg-M0ttsZPum70jOHOw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-M0ttsZPum70jOHOw .icon-shape .label rect,#mermaid-svg-M0ttsZPum70jOHOw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M0ttsZPum70jOHOw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-M0ttsZPum70jOHOw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-M0ttsZPum70jOHOw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 论文 3.2 节

话题连贯、语义相似
纯语义切分

找不到突变点
整节 = 一个超大 chunk
❌ 超过 512 上限

被强行截断

解决办法:语义切分必须加"最大长度上限"兜底 ------在语义突变处切;但如果一个语义块还没遇到突变点就已达到 max_tokens,就强制先切一刀:
#mermaid-svg-M9lPoQthOobqJpLa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-M9lPoQthOobqJpLa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-M9lPoQthOobqJpLa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-M9lPoQthOobqJpLa .error-icon{fill:#552222;}#mermaid-svg-M9lPoQthOobqJpLa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-M9lPoQthOobqJpLa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-M9lPoQthOobqJpLa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-M9lPoQthOobqJpLa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-M9lPoQthOobqJpLa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-M9lPoQthOobqJpLa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-M9lPoQthOobqJpLa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-M9lPoQthOobqJpLa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-M9lPoQthOobqJpLa .marker.cross{stroke:#333333;}#mermaid-svg-M9lPoQthOobqJpLa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-M9lPoQthOobqJpLa p{margin:0;}#mermaid-svg-M9lPoQthOobqJpLa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-M9lPoQthOobqJpLa .cluster-label text{fill:#333;}#mermaid-svg-M9lPoQthOobqJpLa .cluster-label span{color:#333;}#mermaid-svg-M9lPoQthOobqJpLa .cluster-label span p{background-color:transparent;}#mermaid-svg-M9lPoQthOobqJpLa .label text,#mermaid-svg-M9lPoQthOobqJpLa span{fill:#333;color:#333;}#mermaid-svg-M9lPoQthOobqJpLa .node rect,#mermaid-svg-M9lPoQthOobqJpLa .node circle,#mermaid-svg-M9lPoQthOobqJpLa .node ellipse,#mermaid-svg-M9lPoQthOobqJpLa .node polygon,#mermaid-svg-M9lPoQthOobqJpLa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-M9lPoQthOobqJpLa .rough-node .label text,#mermaid-svg-M9lPoQthOobqJpLa .node .label text,#mermaid-svg-M9lPoQthOobqJpLa .image-shape .label,#mermaid-svg-M9lPoQthOobqJpLa .icon-shape .label{text-anchor:middle;}#mermaid-svg-M9lPoQthOobqJpLa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-M9lPoQthOobqJpLa .rough-node .label,#mermaid-svg-M9lPoQthOobqJpLa .node .label,#mermaid-svg-M9lPoQthOobqJpLa .image-shape .label,#mermaid-svg-M9lPoQthOobqJpLa .icon-shape .label{text-align:center;}#mermaid-svg-M9lPoQthOobqJpLa .node.clickable{cursor:pointer;}#mermaid-svg-M9lPoQthOobqJpLa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-M9lPoQthOobqJpLa .arrowheadPath{fill:#333333;}#mermaid-svg-M9lPoQthOobqJpLa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-M9lPoQthOobqJpLa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-M9lPoQthOobqJpLa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M9lPoQthOobqJpLa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-M9lPoQthOobqJpLa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M9lPoQthOobqJpLa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-M9lPoQthOobqJpLa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-M9lPoQthOobqJpLa .cluster text{fill:#333;}#mermaid-svg-M9lPoQthOobqJpLa .cluster span{color:#333;}#mermaid-svg-M9lPoQthOobqJpLa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-M9lPoQthOobqJpLa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-M9lPoQthOobqJpLa rect.text{fill:none;stroke-width:0;}#mermaid-svg-M9lPoQthOobqJpLa .icon-shape,#mermaid-svg-M9lPoQthOobqJpLa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M9lPoQthOobqJpLa .icon-shape p,#mermaid-svg-M9lPoQthOobqJpLa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-M9lPoQthOobqJpLa .icon-shape .label rect,#mermaid-svg-M9lPoQthOobqJpLa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M9lPoQthOobqJpLa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-M9lPoQthOobqJpLa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-M9lPoQthOobqJpLa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
逐句累加到当前 chunk
是否遇到语义突变?
在这里切 ✂️
当前长度 >= max_tokens?
强制切一刀 ✂️

防止超上限
开始下一个 chunk

但要注意:如果 max_tokens 频繁被触发(比如论文连贯段落一路没有突变点,全靠上限强制切),语义切分就退化了------它被迫切在"第 400 个 token 处",这个位置很可能正好在一句话中间,效果甚至比简单方法还差。

这其实是一个重要信号:当某个切分方法的"长度上限频繁触发"时,说明这类文档根本不适合这种方法,应该换一种切分策略。

那么问题来了:怎么知道"长度上限频繁触发"了? 这个信号不需要额外的复杂监测------切分是你自己跑的流程,每一刀到底是"因为遇到语义突变而切"还是"因为达到 max_tokens 被强制切",程序自己是知道的。只要在切分时把每一刀的原因记录下来,跑完统计一下比例即可。

方法一(最直接):给每一刀打"切分原因"标记,统计上限占比。 回顾上面的流程图,切分只有两个触发点(语义突变 / 达到上限),在这两处分别打标记:

python 复制代码
from collections import Counter

chunks, reasons = [], []          # reasons: 每个 chunk 是被哪种原因"结束"的
cur = []
for sent in sentences:
    cur.append(sent)
    if is_semantic_boundary(sent, next_sent):   # 语义突变点
        chunks.append(cur); reasons.append("semantic")
        cur = []
    elif token_len(cur) >= max_tokens:           # 触发长度上限
        chunks.append(cur); reasons.append("maxlen")   # ← 关键:标记为"被上限强制切"
        cur = []
if cur:
    chunks.append(cur); reasons.append("tail")

c = Counter(reasons)
maxlen_ratio = c["maxlen"] / len(reasons)
print(f"上限强制切占比: {maxlen_ratio:.0%}  ({c['maxlen']}/{len(reasons)})")

maxlen_ratio 就是"长度上限触发频率"。经验判断:

  • < 10%:语义切分正常工作,绝大多数刀都切在语义突变点。
  • > 30%~50% :就是这里说的"频繁触发",说明这类文档(如话题高度连贯的论文段落)几乎没有明显语义突变点,语义切分已退化成"变相的定长切分",该换策略了。

方法二(不改切分代码,事后从产出的 chunk 反推): 即便拿不到切分原因标记,也能从结果间接判断:

  • 看 chunk 长度分布 :如果大量 chunk 的 token 数几乎都卡在 max_tokens 附近 (如上限 512,结果一堆 chunk 都是 500~512),它们大概率是被上限截断的;自然在语义边界结束的 chunk 长度应该长短不一。
  • 看切点是否落在句中:抽查 chunk 结尾,若很多不是完整句子(断在句中、逗号处),也是上限强制切的典型症状。
  • 对比语义边界数与总 chunk 数:若"语义突变切点数"远小于"总 chunk 数",说明大部分刀不是语义切出来的。

一句话:不要把 max_tokens 当成一个静默的兜底参数,而要把它的触发频率当成一个诊断指标------它频繁触发,就是文档在告诉你"这个切分策略选错了"。

19.3.7 进阶:LLM 切分与 Contextual Retrieval

更前沿的方向是让 LLM 参与切分。

先澄清一个极易混淆的点:LLM 切分 ≠ 语义切分。 上一节的"语义切分"虽然名字里有"语义",但它用的是 Embedding 模型 (如 BGE、E5)------只是把每句话编码成向量、算相邻句子的余弦相似度、在相似度突降处下刀,本质是一种基于向量距离的数值信号处理 ,模型并没有"读懂"文章在讲什么。而这里的 LLM 切分用的是生成式大模型 (如 GPT、Claude),是真正让模型通读全文、理解篇章逻辑、判断该在哪切。二者用的模型和机制完全不同:

维度 语义切分(上一节) LLM 切分(本节)
用什么模型 Embedding 模型(BGE/E5 等) 生成式 LLM(GPT/Claude 等)
机制 算相邻句子向量相似度,找突降点 读懂全文,判断语义/篇章边界
是否理解内容 否,只比较向量距离 是,真正理解论点/举例/转折
成本 便宜(只做 Embedding) 贵(要 LLM 读全文)

一个类比:语义切分像"只会比对指纹、不懂内容的机器"------发现相邻两句指纹突然对不上就切一刀;LLM 切分像"真正读完文章的编辑"------知道这里从'背景'转到了'方法',应该在这分段。

LLM-based / Agentic Chunking:先让 LLM 读一遍文档,由它判断"哪里是自然的语义边界、该在哪下刀",而不是机械按字数切。
#mermaid-svg-88JiKVmN6jCzDbDD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-88JiKVmN6jCzDbDD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-88JiKVmN6jCzDbDD .error-icon{fill:#552222;}#mermaid-svg-88JiKVmN6jCzDbDD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-88JiKVmN6jCzDbDD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-88JiKVmN6jCzDbDD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-88JiKVmN6jCzDbDD .marker.cross{stroke:#333333;}#mermaid-svg-88JiKVmN6jCzDbDD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-88JiKVmN6jCzDbDD p{margin:0;}#mermaid-svg-88JiKVmN6jCzDbDD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-88JiKVmN6jCzDbDD .cluster-label text{fill:#333;}#mermaid-svg-88JiKVmN6jCzDbDD .cluster-label span{color:#333;}#mermaid-svg-88JiKVmN6jCzDbDD .cluster-label span p{background-color:transparent;}#mermaid-svg-88JiKVmN6jCzDbDD .label text,#mermaid-svg-88JiKVmN6jCzDbDD span{fill:#333;color:#333;}#mermaid-svg-88JiKVmN6jCzDbDD .node rect,#mermaid-svg-88JiKVmN6jCzDbDD .node circle,#mermaid-svg-88JiKVmN6jCzDbDD .node ellipse,#mermaid-svg-88JiKVmN6jCzDbDD .node polygon,#mermaid-svg-88JiKVmN6jCzDbDD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-88JiKVmN6jCzDbDD .rough-node .label text,#mermaid-svg-88JiKVmN6jCzDbDD .node .label text,#mermaid-svg-88JiKVmN6jCzDbDD .image-shape .label,#mermaid-svg-88JiKVmN6jCzDbDD .icon-shape .label{text-anchor:middle;}#mermaid-svg-88JiKVmN6jCzDbDD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-88JiKVmN6jCzDbDD .rough-node .label,#mermaid-svg-88JiKVmN6jCzDbDD .node .label,#mermaid-svg-88JiKVmN6jCzDbDD .image-shape .label,#mermaid-svg-88JiKVmN6jCzDbDD .icon-shape .label{text-align:center;}#mermaid-svg-88JiKVmN6jCzDbDD .node.clickable{cursor:pointer;}#mermaid-svg-88JiKVmN6jCzDbDD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-88JiKVmN6jCzDbDD .arrowheadPath{fill:#333333;}#mermaid-svg-88JiKVmN6jCzDbDD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-88JiKVmN6jCzDbDD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-88JiKVmN6jCzDbDD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-88JiKVmN6jCzDbDD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-88JiKVmN6jCzDbDD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-88JiKVmN6jCzDbDD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-88JiKVmN6jCzDbDD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-88JiKVmN6jCzDbDD .cluster text{fill:#333;}#mermaid-svg-88JiKVmN6jCzDbDD .cluster span{color:#333;}#mermaid-svg-88JiKVmN6jCzDbDD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-88JiKVmN6jCzDbDD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-88JiKVmN6jCzDbDD rect.text{fill:none;stroke-width:0;}#mermaid-svg-88JiKVmN6jCzDbDD .icon-shape,#mermaid-svg-88JiKVmN6jCzDbDD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-88JiKVmN6jCzDbDD .icon-shape p,#mermaid-svg-88JiKVmN6jCzDbDD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-88JiKVmN6jCzDbDD .icon-shape .label rect,#mermaid-svg-88JiKVmN6jCzDbDD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-88JiKVmN6jCzDbDD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-88JiKVmN6jCzDbDD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-88JiKVmN6jCzDbDD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} LLM 切分
文档
LLM 阅读

判断语义边界
变长 chunk

每块语义完整
传统切分
文档
按字数/规则硬切
等长 chunk

可能切坏语义

它能同时兼顾"语义完整"和"减少为防切断而设的重复 overlap"。相关的还有:

  • Proposition Chunking:让 LLM 把文档改写成一条条独立、自包含的"命题",每条作为一个 chunk。
  • Contextual Retrieval(Anthropic 提出):让 LLM 给每个 chunk 生成一段"它在全文中的上下文说明",拼在 chunk 前再做 embedding,大幅提升检索准确率。这和"给 chunk 加面包屑(所属标题/章节)"是同一思路的自动化版本。

但 LLM 切分的现实代价 :成本高(要用 LLM 读全部文档)、速度慢、结果可能不完全一致。因此实践中通常只对高价值文档用 LLM 切分,普通文档用更便宜的递归/语义切分。

更完整的做法:把"LLM 切分"和"Contextual Retrieval"合并成一步。 上面两种方法其实都需要"LLM 读懂全文",可以合并------让 LLM 在通读全文、按语义边界切出 chunk 的同时,为每个 chunk 生成一段"它在全文中的上下文说明",再交给 Embedding 编码入库:
#mermaid-svg-cCSE0uohjKevbXXj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cCSE0uohjKevbXXj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cCSE0uohjKevbXXj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cCSE0uohjKevbXXj .error-icon{fill:#552222;}#mermaid-svg-cCSE0uohjKevbXXj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cCSE0uohjKevbXXj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cCSE0uohjKevbXXj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cCSE0uohjKevbXXj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cCSE0uohjKevbXXj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cCSE0uohjKevbXXj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cCSE0uohjKevbXXj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cCSE0uohjKevbXXj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cCSE0uohjKevbXXj .marker.cross{stroke:#333333;}#mermaid-svg-cCSE0uohjKevbXXj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cCSE0uohjKevbXXj p{margin:0;}#mermaid-svg-cCSE0uohjKevbXXj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cCSE0uohjKevbXXj .cluster-label text{fill:#333;}#mermaid-svg-cCSE0uohjKevbXXj .cluster-label span{color:#333;}#mermaid-svg-cCSE0uohjKevbXXj .cluster-label span p{background-color:transparent;}#mermaid-svg-cCSE0uohjKevbXXj .label text,#mermaid-svg-cCSE0uohjKevbXXj span{fill:#333;color:#333;}#mermaid-svg-cCSE0uohjKevbXXj .node rect,#mermaid-svg-cCSE0uohjKevbXXj .node circle,#mermaid-svg-cCSE0uohjKevbXXj .node ellipse,#mermaid-svg-cCSE0uohjKevbXXj .node polygon,#mermaid-svg-cCSE0uohjKevbXXj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cCSE0uohjKevbXXj .rough-node .label text,#mermaid-svg-cCSE0uohjKevbXXj .node .label text,#mermaid-svg-cCSE0uohjKevbXXj .image-shape .label,#mermaid-svg-cCSE0uohjKevbXXj .icon-shape .label{text-anchor:middle;}#mermaid-svg-cCSE0uohjKevbXXj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cCSE0uohjKevbXXj .rough-node .label,#mermaid-svg-cCSE0uohjKevbXXj .node .label,#mermaid-svg-cCSE0uohjKevbXXj .image-shape .label,#mermaid-svg-cCSE0uohjKevbXXj .icon-shape .label{text-align:center;}#mermaid-svg-cCSE0uohjKevbXXj .node.clickable{cursor:pointer;}#mermaid-svg-cCSE0uohjKevbXXj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cCSE0uohjKevbXXj .arrowheadPath{fill:#333333;}#mermaid-svg-cCSE0uohjKevbXXj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cCSE0uohjKevbXXj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cCSE0uohjKevbXXj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cCSE0uohjKevbXXj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cCSE0uohjKevbXXj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cCSE0uohjKevbXXj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cCSE0uohjKevbXXj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cCSE0uohjKevbXXj .cluster text{fill:#333;}#mermaid-svg-cCSE0uohjKevbXXj .cluster span{color:#333;}#mermaid-svg-cCSE0uohjKevbXXj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cCSE0uohjKevbXXj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cCSE0uohjKevbXXj rect.text{fill:none;stroke-width:0;}#mermaid-svg-cCSE0uohjKevbXXj .icon-shape,#mermaid-svg-cCSE0uohjKevbXXj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cCSE0uohjKevbXXj .icon-shape p,#mermaid-svg-cCSE0uohjKevbXXj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cCSE0uohjKevbXXj .icon-shape .label rect,#mermaid-svg-cCSE0uohjKevbXXj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cCSE0uohjKevbXXj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cCSE0uohjKevbXXj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cCSE0uohjKevbXXj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 保留原始正文
整篇文档
LLM 通读全文
一次输出:

每个 chunk 的正文 + 其上下文说明
拼接:上下文说明 + 正文
Embedding 编码
向量入库
命中后交给生成 LLM

这样把"切得准"(LLM 切分)和"补全局上下文、提升检索命中"(Contextual Retrieval)合并成一次 LLM 调用,既省一次全文阅读的开销,又保证切分与上下文说明彼此一致。使用时注意几点:

  • 仍然贵,只对高价值文档用:虽然合并省了一次调用,但还是要 LLM 读全文。
  • 长文档放不进一次上下文:文档超过 LLM 上下文窗口时,无法真正"一次通读全文",需要先粗切成大块分批喂、或用滑动窗口并让 LLM 参考已切结果,这会削弱全局视角。
  • 入库存两份 :向量用「上下文说明 + 正文」编码以提升检索命中率,但检索命中后喂给生成 LLM 的通常是原始正文(上下文说明主要为检索服务)。
  • LLM 与 Embedding 无需匹配:整个过程 LLM 产出文本、Embedding 消费文本,二者是文本接力、可自由搭配;真正需要同一模型/同一向量空间的,是"给 chunk 做 embedding"和"给 Query 做 embedding"这一对。

19.3.8 没有万能切法:按文档类型选择策略

综合前面的讨论,可以得到 chunking 最重要的一条原则:

没有"最优 chunking 方法",只有"最适合这类文档的方法"。切分策略必须 content-aware(内容感知)。

不同文档结构完全不同,硬用同一套策略必然有的场景好、有的场景差:

文档类型 结构特点 推荐切分方法
论文 / 技术文档 有清晰章节、话题连贯 递归/结构切分:先按章节,超长再按段落/句子下钻
FAQ / 问答 天然一问一答 按天然分隔符切,一条 Q&A 一个 chunk
新闻 / 博客 话题可能跳变 段落切分 或 语义切分
合同 / 法律条款 按条款编号 按条款切,一条一个 chunk
对话 / 聊天记录 按轮次 按发言轮次切
代码 按函数/类 按代码块切,别切在函数中间
Markdown 有 # 层级 按标题层级递归切
表格 结构化 整表一个 chunk,别拦腰切

选择切分策略的决策逻辑大致是:
#mermaid-svg-UYaqnsDHqNcC2iAZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UYaqnsDHqNcC2iAZ .error-icon{fill:#552222;}#mermaid-svg-UYaqnsDHqNcC2iAZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UYaqnsDHqNcC2iAZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .marker.cross{stroke:#333333;}#mermaid-svg-UYaqnsDHqNcC2iAZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UYaqnsDHqNcC2iAZ p{margin:0;}#mermaid-svg-UYaqnsDHqNcC2iAZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster-label text{fill:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster-label span{color:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster-label span p{background-color:transparent;}#mermaid-svg-UYaqnsDHqNcC2iAZ .label text,#mermaid-svg-UYaqnsDHqNcC2iAZ span{fill:#333;color:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .node rect,#mermaid-svg-UYaqnsDHqNcC2iAZ .node circle,#mermaid-svg-UYaqnsDHqNcC2iAZ .node ellipse,#mermaid-svg-UYaqnsDHqNcC2iAZ .node polygon,#mermaid-svg-UYaqnsDHqNcC2iAZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .rough-node .label text,#mermaid-svg-UYaqnsDHqNcC2iAZ .node .label text,#mermaid-svg-UYaqnsDHqNcC2iAZ .image-shape .label,#mermaid-svg-UYaqnsDHqNcC2iAZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-UYaqnsDHqNcC2iAZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .rough-node .label,#mermaid-svg-UYaqnsDHqNcC2iAZ .node .label,#mermaid-svg-UYaqnsDHqNcC2iAZ .image-shape .label,#mermaid-svg-UYaqnsDHqNcC2iAZ .icon-shape .label{text-align:center;}#mermaid-svg-UYaqnsDHqNcC2iAZ .node.clickable{cursor:pointer;}#mermaid-svg-UYaqnsDHqNcC2iAZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .arrowheadPath{fill:#333333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UYaqnsDHqNcC2iAZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UYaqnsDHqNcC2iAZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UYaqnsDHqNcC2iAZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster text{fill:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ .cluster span{color:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UYaqnsDHqNcC2iAZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UYaqnsDHqNcC2iAZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-UYaqnsDHqNcC2iAZ .icon-shape,#mermaid-svg-UYaqnsDHqNcC2iAZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UYaqnsDHqNcC2iAZ .icon-shape p,#mermaid-svg-UYaqnsDHqNcC2iAZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UYaqnsDHqNcC2iAZ .icon-shape .label rect,#mermaid-svg-UYaqnsDHqNcC2iAZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UYaqnsDHqNcC2iAZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UYaqnsDHqNcC2iAZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UYaqnsDHqNcC2iAZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 有
没有
跳变多
连贯为主
拿到一篇文档
有清晰结构吗?

标题/条款/轮次
优先按结构切

超长再往下钻
话题是否明显跳变?
语义切分 + 上限
递归切分

段落→句子→字数

工程上不必给每篇文档都写一套精细规则(维护成本太高),更务实的平衡是:

  1. 先分类:把文档分成结构化 / 半结构化 / 纯文本几大类。
  2. 每类配一个默认策略,而不是逐篇调参。
  3. 递归切分作为兜底:拿不准的、混杂的文档用递归切分(先大后小 + 字数上限),它是最稳健的通用默认。
  4. 只对高价值文档做精细化:核心知识库的关键文档才值得用 LLM 切分/语义切分精调。

最后,chunking 有两条本质原则值得记住:

没有万能切分法,方法要匹配文档结构(content-aware)\boxed{\text{没有万能切分法,方法要匹配文档结构(content-aware)}}没有万能切分法,方法要匹配文档结构(content-aware)

"语义完整"和"长度可控"会打架,任何语义优先的方法都需要长度上限兜底\boxed{\text{"语义完整"和"长度可控"会打架,任何语义优先的方法都需要长度上限兜底}}"语义完整"和"长度可控"会打架,任何语义优先的方法都需要长度上限兜底

其中"长度上限频繁触发"本身就是一个信号------它在提示你:这种文档选错了切分方法。


19.4 Tokenizer Splitter

使用 Tokenizer 来精确控制 Chunk 的 Token 数量:

python 复制代码
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-base-zh-v1.5")

def split_by_tokens(text, max_tokens=512, overlap=50):
    tokens = tokenizer.encode(text)
    chunks = []
    start = 0
    while start < len(tokens):
        end = min(start + max_tokens, len(tokens))
        chunk_tokens = tokens[start:end]
        chunk_text = tokenizer.decode(chunk_tokens, skip_special_tokens=True)
        chunks.append(chunk_text)
        start = end - overlap  # 重叠
    return chunks

19.5 Embedding 与存储

在看代码之前,先澄清一个初学者最容易卡住的概念:

向量数据库里存的不只是向量,而是"向量 + 原始文本"一起存。检索时用向量算相似度,但返回给你的是当初一起存进去的原始文本------不是把向量"转回"文本。

这一点非常关键,因为 Embedding 是单向的、不可逆的:从"文本 → 768 维向量"可以,但"向量 → 文本"做不到(768 个数字无法还原出原句)。所以每个 chunk 入库时,实际存的是一条包含三部分的记录:

字段 内容 作用
id 唯一编号,如 doc0_chunk1 标识
vector 768 维向量 只用于算相似度、定位
document(原文)+ metadata chunk 原始文本、来源等 检索时返回给 LLM 用

#mermaid-svg-I5kexwB9ZBAj80L4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-I5kexwB9ZBAj80L4 .error-icon{fill:#552222;}#mermaid-svg-I5kexwB9ZBAj80L4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-I5kexwB9ZBAj80L4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-I5kexwB9ZBAj80L4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-I5kexwB9ZBAj80L4 .marker.cross{stroke:#333333;}#mermaid-svg-I5kexwB9ZBAj80L4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-I5kexwB9ZBAj80L4 p{margin:0;}#mermaid-svg-I5kexwB9ZBAj80L4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster-label text{fill:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster-label span{color:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster-label span p{background-color:transparent;}#mermaid-svg-I5kexwB9ZBAj80L4 .label text,#mermaid-svg-I5kexwB9ZBAj80L4 span{fill:#333;color:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 .node rect,#mermaid-svg-I5kexwB9ZBAj80L4 .node circle,#mermaid-svg-I5kexwB9ZBAj80L4 .node ellipse,#mermaid-svg-I5kexwB9ZBAj80L4 .node polygon,#mermaid-svg-I5kexwB9ZBAj80L4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-I5kexwB9ZBAj80L4 .rough-node .label text,#mermaid-svg-I5kexwB9ZBAj80L4 .node .label text,#mermaid-svg-I5kexwB9ZBAj80L4 .image-shape .label,#mermaid-svg-I5kexwB9ZBAj80L4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-I5kexwB9ZBAj80L4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-I5kexwB9ZBAj80L4 .rough-node .label,#mermaid-svg-I5kexwB9ZBAj80L4 .node .label,#mermaid-svg-I5kexwB9ZBAj80L4 .image-shape .label,#mermaid-svg-I5kexwB9ZBAj80L4 .icon-shape .label{text-align:center;}#mermaid-svg-I5kexwB9ZBAj80L4 .node.clickable{cursor:pointer;}#mermaid-svg-I5kexwB9ZBAj80L4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-I5kexwB9ZBAj80L4 .arrowheadPath{fill:#333333;}#mermaid-svg-I5kexwB9ZBAj80L4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-I5kexwB9ZBAj80L4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-I5kexwB9ZBAj80L4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I5kexwB9ZBAj80L4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-I5kexwB9ZBAj80L4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I5kexwB9ZBAj80L4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster text{fill:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 .cluster span{color:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-I5kexwB9ZBAj80L4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-I5kexwB9ZBAj80L4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-I5kexwB9ZBAj80L4 .icon-shape,#mermaid-svg-I5kexwB9ZBAj80L4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I5kexwB9ZBAj80L4 .icon-shape p,#mermaid-svg-I5kexwB9ZBAj80L4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-I5kexwB9ZBAj80L4 .icon-shape .label rect,#mermaid-svg-I5kexwB9ZBAj80L4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I5kexwB9ZBAj80L4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-I5kexwB9ZBAj80L4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-I5kexwB9ZBAj80L4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Embedding
只用来算相似度

定位是哪几条记录
取出记录里存的
交给 LLM
文本 chunk
向量 768维
Top-K 记录
原始文本
答案

也就是说,向量的唯一作用是"当索引、找位置",一旦定位到是哪几条 chunk,后面全程用的是文本,向量就退场了。 下面的代码里,collection.add(documents=all_chunks, ...) 就是把原文和向量一起存入;检索时 results['documents'] 返回的正是这些原始文本。

python 复制代码
import chromadb
from chromadb.utils import embedding_functions

# 初始化
client = chromadb.PersistentClient(path="./chroma_db")
ef = embedding_functions.SentenceTransformerEmbeddingFunction(
    model_name="BAAI/bge-base-zh-v1.5"
)
collection = client.get_or_create_collection("knowledge_base", embedding_function=ef)

def index_documents(documents, metadatas=None):
    """将文档分块并存入向量数据库"""
    all_chunks = []
    all_ids = []
    all_metas = []

    for i, doc in enumerate(documents):
        chunks = split_by_tokens(doc, max_tokens=512, overlap=50)
        for j, chunk in enumerate(chunks):
            all_chunks.append(chunk)
            all_ids.append(f"doc{i}_chunk{j}")
            all_metas.append({"doc_id": i, "chunk_id": j})

    collection.add(
        documents=all_chunks,
        ids=all_ids,
        metadatas=all_metas
    )
    print(f"已索引 {len(all_chunks)} 个 Chunk")

19.6 Retriever(检索器)

python 复制代码
def retrieve(query, n_results=5):
    """检索最相关的 Chunk"""
    results = collection.query(
        query_texts=[query],
        n_results=n_results
    )
    return results['documents'][0], results['metadatas'][0]

# 测试
docs, metas = retrieve("什么是 Transformer?")
for doc, meta in zip(docs, metas):
    print(f"[Doc {meta['doc_id']}, Chunk {meta['chunk_id']}]")
    print(doc[:100])
    print()

19.7 Reranker(重排序)

向量检索召回的文档可能不够精确,Reranker 对召回结果重新排序:
#mermaid-svg-evUt6cJW6UScJ6QV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-evUt6cJW6UScJ6QV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-evUt6cJW6UScJ6QV .error-icon{fill:#552222;}#mermaid-svg-evUt6cJW6UScJ6QV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-evUt6cJW6UScJ6QV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-evUt6cJW6UScJ6QV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-evUt6cJW6UScJ6QV .marker.cross{stroke:#333333;}#mermaid-svg-evUt6cJW6UScJ6QV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-evUt6cJW6UScJ6QV p{margin:0;}#mermaid-svg-evUt6cJW6UScJ6QV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-evUt6cJW6UScJ6QV .cluster-label text{fill:#333;}#mermaid-svg-evUt6cJW6UScJ6QV .cluster-label span{color:#333;}#mermaid-svg-evUt6cJW6UScJ6QV .cluster-label span p{background-color:transparent;}#mermaid-svg-evUt6cJW6UScJ6QV .label text,#mermaid-svg-evUt6cJW6UScJ6QV span{fill:#333;color:#333;}#mermaid-svg-evUt6cJW6UScJ6QV .node rect,#mermaid-svg-evUt6cJW6UScJ6QV .node circle,#mermaid-svg-evUt6cJW6UScJ6QV .node ellipse,#mermaid-svg-evUt6cJW6UScJ6QV .node polygon,#mermaid-svg-evUt6cJW6UScJ6QV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-evUt6cJW6UScJ6QV .rough-node .label text,#mermaid-svg-evUt6cJW6UScJ6QV .node .label text,#mermaid-svg-evUt6cJW6UScJ6QV .image-shape .label,#mermaid-svg-evUt6cJW6UScJ6QV .icon-shape .label{text-anchor:middle;}#mermaid-svg-evUt6cJW6UScJ6QV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-evUt6cJW6UScJ6QV .rough-node .label,#mermaid-svg-evUt6cJW6UScJ6QV .node .label,#mermaid-svg-evUt6cJW6UScJ6QV .image-shape .label,#mermaid-svg-evUt6cJW6UScJ6QV .icon-shape .label{text-align:center;}#mermaid-svg-evUt6cJW6UScJ6QV .node.clickable{cursor:pointer;}#mermaid-svg-evUt6cJW6UScJ6QV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-evUt6cJW6UScJ6QV .arrowheadPath{fill:#333333;}#mermaid-svg-evUt6cJW6UScJ6QV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-evUt6cJW6UScJ6QV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-evUt6cJW6UScJ6QV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-evUt6cJW6UScJ6QV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-evUt6cJW6UScJ6QV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-evUt6cJW6UScJ6QV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-evUt6cJW6UScJ6QV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-evUt6cJW6UScJ6QV .cluster text{fill:#333;}#mermaid-svg-evUt6cJW6UScJ6QV .cluster span{color:#333;}#mermaid-svg-evUt6cJW6UScJ6QV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-evUt6cJW6UScJ6QV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-evUt6cJW6UScJ6QV rect.text{fill:none;stroke-width:0;}#mermaid-svg-evUt6cJW6UScJ6QV .icon-shape,#mermaid-svg-evUt6cJW6UScJ6QV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-evUt6cJW6UScJ6QV .icon-shape p,#mermaid-svg-evUt6cJW6UScJ6QV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-evUt6cJW6UScJ6QV .icon-shape .label rect,#mermaid-svg-evUt6cJW6UScJ6QV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-evUt6cJW6UScJ6QV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-evUt6cJW6UScJ6QV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-evUt6cJW6UScJ6QV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Query
向量检索

召回 Top-50
Reranker

精确打分
重排后 Top-5
LLM 生成

为什么会有 Reranker?根源在于向量检索为了"快"牺牲了"准"。 向量检索用的是 Bi-Encoder(双编码器) :Query 和 Document 是分开、独立 编码成向量的,编码时两边从没"见过面"------给文档编码时并不知道未来用什么 Query 来查,各自被压缩成一个固定长度向量(如 768 维),大量细节在压缩中丢失。用两个"各自压缩过的向量"算相似度,只能得到粗略的相关性估计,所以 Top-K 里常混进"向量看着像、其实不相关"的文档。

而 Reranker 用的是 Cross-Encoder(交叉编码器) :把 [Query + Document] 拼成一个序列送进模型,让两段文本在模型内部逐词交互、直接判断相关性 ,准得多------但代价是极慢 (每个 [Query+Doc] 组合都要完整跑一遍模型,无法对百万文档全跑)。于是把两者串成两阶段检索,各取所长:

  • 第一阶段(召回 / Recall) :Bi-Encoder 向量检索从百万文档 里快速捞出 Top-50~100 候选,目标是"别把相关的漏掉"(高召回),允许有噪声。
  • 第二阶段(精排 / Rerank) :Reranker(Cross-Encoder)只对这几十个候选逐一精细打分、重新排序,选出真正最相关的 Top-5 交给 LLM。因为只算几十次,慢也能接受。

一个类比:Bi-Encoder 像用关键词从图书馆几百万本书里快速筛出 100 本"可能相关"的 (只看了书名标签,快但粗);Reranker 像馆员把这 100 本真的翻开、对着你的问题逐本判断,挑出最对口的 5 本(慢但准)------你不会让馆员翻遍全馆,但翻 100 本可行,这就是两阶段的价值。

Reranker 通常是一个 Cross-Encoder 模型:

python 复制代码
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-base")

def rerank(query, documents, top_k=5):
    """对检索结果重新排序"""
    pairs = [[query, doc] for doc in documents]
    scores = reranker.predict(pairs)
    ranked = sorted(zip(scores, documents), reverse=True)
    return [doc for _, doc in ranked[:top_k]]
方法 速度 精度
向量检索(Bi-Encoder) 快 中
Reranker(Cross-Encoder) 慢 高
两阶段(先召回再重排) 中 高

Cross-Encoder 到底怎么"判断相关不相关"? 一句话概括:它把 [Query + Document] 拼成一个序列送进模型,让两段文本在内部逐词交互、充分交融 ,最后输出一个相关性分数 ;再按分数从高到低重排。它的判断能力是用带标签的数据训练出来的------(Query, 相关文档) → 高分、(Query, 不相关文档) → 低分。这正是 Bi-Encoder(Query 与 Document 分开独立编码、词与词从没跨段交互)做不到的细粒度匹配。

这里的"拼接输入、Self-Attention 逐词交互、取 [CLS] 表示接打分头、句对分类训练"等内部机制,属于 BERT / 句对模型的细节,本书不再展开。想深入理解 Cross-Encoder 为什么能这样判断相关性,可参阅笔者的《BERT》一书(Self-Attention、CLS 表示、句对分类等章节)。

顺带解释它为什么慢:每个 [Query+Doc] 组合都要完整跑一遍模型,而 Bi-Encoder 只需查一次预存向量------因此 Cross-Encoder 只能用在"精排少量候选"这一步。


19.8 Prompt 设计

python 复制代码
def build_prompt(query, retrieved_docs):
    context = "\n\n".join([f"[文档{i+1}]\n{doc}" for i, doc in enumerate(retrieved_docs)])
    prompt = f"""请根据以下参考文档回答问题。如果文档中没有相关信息,请说"根据提供的文档,无法回答此问题"。

参考文档:
{context}

问题:{query}

回答:"""
    return prompt

19.9 完整 RAG 系统

python 复制代码
import requests

def rag_answer(query, n_retrieve=20, n_rerank=5):
    # Step 1: 检索
    docs, _ = retrieve(query, n_results=n_retrieve)

    # Step 2: 重排序
    reranked_docs = rerank(query, docs, top_k=n_rerank)

    # Step 3: 构建 Prompt
    prompt = build_prompt(query, reranked_docs)

    # Step 4: 调用 LLM(以 Ollama 为例)
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "qwen2:7b", "prompt": prompt, "stream": False}
    )
    return response.json()["response"]

# 使用
answer = rag_answer("Transformer 的 Self-Attention 是如何计算的?")
print(answer)

19.10 RAG 的评估

前面讲了很多 chunking、检索、Rerank 的方法。但一个关键问题是:换了一种切分方案(或改了 Embedding、Prompt),怎么知道到底是变好了还是变差了? 不能靠感觉,要靠指标。

19.10.1 核心思想:评估的是"下游效果",不是切分本身

Chunking 本身没有独立的"对错"------它的好坏最终体现在检索准不准、回答对不对。所以评估要分层进行:
#mermaid-svg-0rNLp5noqFPQhCxT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0rNLp5noqFPQhCxT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0rNLp5noqFPQhCxT .error-icon{fill:#552222;}#mermaid-svg-0rNLp5noqFPQhCxT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0rNLp5noqFPQhCxT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0rNLp5noqFPQhCxT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0rNLp5noqFPQhCxT .marker.cross{stroke:#333333;}#mermaid-svg-0rNLp5noqFPQhCxT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0rNLp5noqFPQhCxT p{margin:0;}#mermaid-svg-0rNLp5noqFPQhCxT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0rNLp5noqFPQhCxT .cluster-label text{fill:#333;}#mermaid-svg-0rNLp5noqFPQhCxT .cluster-label span{color:#333;}#mermaid-svg-0rNLp5noqFPQhCxT .cluster-label span p{background-color:transparent;}#mermaid-svg-0rNLp5noqFPQhCxT .label text,#mermaid-svg-0rNLp5noqFPQhCxT span{fill:#333;color:#333;}#mermaid-svg-0rNLp5noqFPQhCxT .node rect,#mermaid-svg-0rNLp5noqFPQhCxT .node circle,#mermaid-svg-0rNLp5noqFPQhCxT .node ellipse,#mermaid-svg-0rNLp5noqFPQhCxT .node polygon,#mermaid-svg-0rNLp5noqFPQhCxT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0rNLp5noqFPQhCxT .rough-node .label text,#mermaid-svg-0rNLp5noqFPQhCxT .node .label text,#mermaid-svg-0rNLp5noqFPQhCxT .image-shape .label,#mermaid-svg-0rNLp5noqFPQhCxT .icon-shape .label{text-anchor:middle;}#mermaid-svg-0rNLp5noqFPQhCxT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0rNLp5noqFPQhCxT .rough-node .label,#mermaid-svg-0rNLp5noqFPQhCxT .node .label,#mermaid-svg-0rNLp5noqFPQhCxT .image-shape .label,#mermaid-svg-0rNLp5noqFPQhCxT .icon-shape .label{text-align:center;}#mermaid-svg-0rNLp5noqFPQhCxT .node.clickable{cursor:pointer;}#mermaid-svg-0rNLp5noqFPQhCxT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0rNLp5noqFPQhCxT .arrowheadPath{fill:#333333;}#mermaid-svg-0rNLp5noqFPQhCxT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0rNLp5noqFPQhCxT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0rNLp5noqFPQhCxT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0rNLp5noqFPQhCxT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0rNLp5noqFPQhCxT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0rNLp5noqFPQhCxT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0rNLp5noqFPQhCxT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0rNLp5noqFPQhCxT .cluster text{fill:#333;}#mermaid-svg-0rNLp5noqFPQhCxT .cluster span{color:#333;}#mermaid-svg-0rNLp5noqFPQhCxT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0rNLp5noqFPQhCxT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0rNLp5noqFPQhCxT rect.text{fill:none;stroke-width:0;}#mermaid-svg-0rNLp5noqFPQhCxT .icon-shape,#mermaid-svg-0rNLp5noqFPQhCxT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0rNLp5noqFPQhCxT .icon-shape p,#mermaid-svg-0rNLp5noqFPQhCxT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0rNLp5noqFPQhCxT .icon-shape .label rect,#mermaid-svg-0rNLp5noqFPQhCxT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0rNLp5noqFPQhCxT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0rNLp5noqFPQhCxT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0rNLp5noqFPQhCxT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 某种切分/配置方案
① 检索层评估

检索得准不准
② 回答层评估

最终答案对不对
③ 线上评估

真实用户反馈

19.10.2 第一层:检索层评估(最直接、性价比最高)

先建一个测试集:一批"问题 → 正确答案应该来自哪个原文片段"的标注对:

text 复制代码
Q1: "Transformer 为什么要除以 √dk?" → 正确来源: 第6章 "Scaled Dot-Product" 那段
Q2: "BERT 用什么预训练任务?"        → 正确来源: 第12章 "MLM 和 NSP" 那段
...(通常几十到几百条)

然后对同一测试集,分别用"方案 A"和"方案 B"建库、检索,对比这几个指标:

指标 含义 关注点
Recall@K Top-K 里有没有召回到正确来源 最重要------漏召回是致命的
Precision@K Top-K 里有多少是真正相关的 噪声多不多
MRR 正确结果排在第几位(越靠前越好) 排序质量
NDCG 综合考虑相关性和排名位置 更精细的排序质量

方案 B 更好  ⟺  在同一测试集上 Recall@K / MRR / NDCG 更高\text{方案 B 更好} \iff \text{在同一测试集上 Recall@K / MRR / NDCG 更高}方案 B 更好⟺在同一测试集上 Recall@K / MRR / NDCG 更高

这是验证两次切分优劣最核心的方法------同样的问题、同样的 Embedding 模型,只有切分不同,谁的检索指标高谁就更好。

19.10.3 第二层:回答层评估(端到端)

检索准不代表最终答案就好(还受 Prompt、LLM 影响),所以再看完整 RAG 输出的质量:

指标 含义 工具
Faithfulness(忠实度) 答案是否基于检索内容,有没有幻觉 RAGAS
Answer Relevance 答案是否切题 RAGAS
Context Precision 检索到的上下文是否都有用 RAGAS
Context Recall 检索到的上下文是否足够回答 RAGAS

现在有现成工具做这类评估,如 RAGAS 、TruLens 、LlamaIndex Evaluation------把两套方案的 RAG 输出丢进去,它自动打分对比。

19.10.4 第三层:线上评估(最真实,成本最高)

  • A/B 测试:一部分用户用方案 A、一部分用方案 B,比点击率、满意度、"有帮助"点赞率。
  • 人工盲评:让人对两套方案的答案盲评打分。

19.10.5 关键:控制变量

验证"这次切分比上次好"时,必须只改切分,其他全部固定,否则分不清效果变化到底是谁的功劳:
#mermaid-svg-4AFcUXfRjUogOMjU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4AFcUXfRjUogOMjU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4AFcUXfRjUogOMjU .error-icon{fill:#552222;}#mermaid-svg-4AFcUXfRjUogOMjU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4AFcUXfRjUogOMjU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4AFcUXfRjUogOMjU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4AFcUXfRjUogOMjU .marker.cross{stroke:#333333;}#mermaid-svg-4AFcUXfRjUogOMjU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4AFcUXfRjUogOMjU p{margin:0;}#mermaid-svg-4AFcUXfRjUogOMjU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4AFcUXfRjUogOMjU .cluster-label text{fill:#333;}#mermaid-svg-4AFcUXfRjUogOMjU .cluster-label span{color:#333;}#mermaid-svg-4AFcUXfRjUogOMjU .cluster-label span p{background-color:transparent;}#mermaid-svg-4AFcUXfRjUogOMjU .label text,#mermaid-svg-4AFcUXfRjUogOMjU span{fill:#333;color:#333;}#mermaid-svg-4AFcUXfRjUogOMjU .node rect,#mermaid-svg-4AFcUXfRjUogOMjU .node circle,#mermaid-svg-4AFcUXfRjUogOMjU .node ellipse,#mermaid-svg-4AFcUXfRjUogOMjU .node polygon,#mermaid-svg-4AFcUXfRjUogOMjU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4AFcUXfRjUogOMjU .rough-node .label text,#mermaid-svg-4AFcUXfRjUogOMjU .node .label text,#mermaid-svg-4AFcUXfRjUogOMjU .image-shape .label,#mermaid-svg-4AFcUXfRjUogOMjU .icon-shape .label{text-anchor:middle;}#mermaid-svg-4AFcUXfRjUogOMjU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4AFcUXfRjUogOMjU .rough-node .label,#mermaid-svg-4AFcUXfRjUogOMjU .node .label,#mermaid-svg-4AFcUXfRjUogOMjU .image-shape .label,#mermaid-svg-4AFcUXfRjUogOMjU .icon-shape .label{text-align:center;}#mermaid-svg-4AFcUXfRjUogOMjU .node.clickable{cursor:pointer;}#mermaid-svg-4AFcUXfRjUogOMjU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4AFcUXfRjUogOMjU .arrowheadPath{fill:#333333;}#mermaid-svg-4AFcUXfRjUogOMjU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4AFcUXfRjUogOMjU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4AFcUXfRjUogOMjU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4AFcUXfRjUogOMjU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4AFcUXfRjUogOMjU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4AFcUXfRjUogOMjU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4AFcUXfRjUogOMjU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4AFcUXfRjUogOMjU .cluster text{fill:#333;}#mermaid-svg-4AFcUXfRjUogOMjU .cluster span{color:#333;}#mermaid-svg-4AFcUXfRjUogOMjU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4AFcUXfRjUogOMjU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4AFcUXfRjUogOMjU rect.text{fill:none;stroke-width:0;}#mermaid-svg-4AFcUXfRjUogOMjU .icon-shape,#mermaid-svg-4AFcUXfRjUogOMjU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4AFcUXfRjUogOMjU .icon-shape p,#mermaid-svg-4AFcUXfRjUogOMjU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4AFcUXfRjUogOMjU .icon-shape .label rect,#mermaid-svg-4AFcUXfRjUogOMjU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4AFcUXfRjUogOMjU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4AFcUXfRjUogOMjU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4AFcUXfRjUogOMjU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 唯一变量
切分方案 A vs B
保持不变
同一 Embedding 模型
同一测试问题集
同样的 Top-K
同样的 Prompt
同样的 LLM
对比检索/回答指标

19.10.6 最小可行流程

如果只是想快速判断"这次调整有没有用",最省事的流程:
#mermaid-svg-CyXQyo1F0DfOhChX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CyXQyo1F0DfOhChX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CyXQyo1F0DfOhChX .error-icon{fill:#552222;}#mermaid-svg-CyXQyo1F0DfOhChX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CyXQyo1F0DfOhChX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CyXQyo1F0DfOhChX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CyXQyo1F0DfOhChX .marker.cross{stroke:#333333;}#mermaid-svg-CyXQyo1F0DfOhChX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CyXQyo1F0DfOhChX p{margin:0;}#mermaid-svg-CyXQyo1F0DfOhChX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CyXQyo1F0DfOhChX .cluster-label text{fill:#333;}#mermaid-svg-CyXQyo1F0DfOhChX .cluster-label span{color:#333;}#mermaid-svg-CyXQyo1F0DfOhChX .cluster-label span p{background-color:transparent;}#mermaid-svg-CyXQyo1F0DfOhChX .label text,#mermaid-svg-CyXQyo1F0DfOhChX span{fill:#333;color:#333;}#mermaid-svg-CyXQyo1F0DfOhChX .node rect,#mermaid-svg-CyXQyo1F0DfOhChX .node circle,#mermaid-svg-CyXQyo1F0DfOhChX .node ellipse,#mermaid-svg-CyXQyo1F0DfOhChX .node polygon,#mermaid-svg-CyXQyo1F0DfOhChX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CyXQyo1F0DfOhChX .rough-node .label text,#mermaid-svg-CyXQyo1F0DfOhChX .node .label text,#mermaid-svg-CyXQyo1F0DfOhChX .image-shape .label,#mermaid-svg-CyXQyo1F0DfOhChX .icon-shape .label{text-anchor:middle;}#mermaid-svg-CyXQyo1F0DfOhChX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CyXQyo1F0DfOhChX .rough-node .label,#mermaid-svg-CyXQyo1F0DfOhChX .node .label,#mermaid-svg-CyXQyo1F0DfOhChX .image-shape .label,#mermaid-svg-CyXQyo1F0DfOhChX .icon-shape .label{text-align:center;}#mermaid-svg-CyXQyo1F0DfOhChX .node.clickable{cursor:pointer;}#mermaid-svg-CyXQyo1F0DfOhChX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CyXQyo1F0DfOhChX .arrowheadPath{fill:#333333;}#mermaid-svg-CyXQyo1F0DfOhChX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CyXQyo1F0DfOhChX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CyXQyo1F0DfOhChX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CyXQyo1F0DfOhChX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CyXQyo1F0DfOhChX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CyXQyo1F0DfOhChX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CyXQyo1F0DfOhChX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CyXQyo1F0DfOhChX .cluster text{fill:#333;}#mermaid-svg-CyXQyo1F0DfOhChX .cluster span{color:#333;}#mermaid-svg-CyXQyo1F0DfOhChX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CyXQyo1F0DfOhChX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CyXQyo1F0DfOhChX rect.text{fill:none;stroke-width:0;}#mermaid-svg-CyXQyo1F0DfOhChX .icon-shape,#mermaid-svg-CyXQyo1F0DfOhChX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CyXQyo1F0DfOhChX .icon-shape p,#mermaid-svg-CyXQyo1F0DfOhChX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CyXQyo1F0DfOhChX .icon-shape .label rect,#mermaid-svg-CyXQyo1F0DfOhChX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CyXQyo1F0DfOhChX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CyXQyo1F0DfOhChX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CyXQyo1F0DfOhChX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
准备 30-50 个测试问题

  • 标注正确来源
    方案A: 建库→检索
    方案B: 建库→检索
    算 Recall@5 / MRR
    B 的指标 更高?
    ✅ 这次切分有改进
    ❌ 没改进甚至退步

一个测试集 + Recall@K + MRR,就能让"切分好不好"从"凭感觉"变成"有数字"。 这是最低成本、最值得先做的一步。

19.10.7 测试集是评估的地基

上面所有评估都依赖一个"问题 → 正确来源"的测试集,它的构建方式:

  • 人工标注:最准,但费时。
  • 从历史 QA 日志反推:如果有线上问答记录。
  • 用强 LLM 辅助生成:"问题 + 对应原文段落",再人工抽检。

测试集一旦建好就能反复复用------以后每次调切分、换 Embedding、改 Prompt,都用它量化对比。这是 RAG 工程化的基础设施。

一句话总结 :切分好不好,不看切分本身,看它带来的下游效果。做法是建一个"问题→正确来源"的测试集,固定其他所有变量、只换切分方案,对比 Recall@K / MRR(检索层)和 Faithfulness / Answer Relevance(回答层)。指标高的那个方案就是更好的。


19.11 RAG 的常见问题与解决方案

问题 原因 解决方案
检索不到相关文档 Chunk 太大/太小 调整 Chunk Size
答案不准确 检索文档不相关 加 Reranker
答案不完整 信息分散在多个 Chunk 增加 n_results
幻觉 LLM 忽略了文档 改进 Prompt
速度慢 检索+重排+生成 缓存、异步

本章总结

#mermaid-svg-jf882JCg3VHP3IRE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jf882JCg3VHP3IRE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jf882JCg3VHP3IRE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jf882JCg3VHP3IRE .error-icon{fill:#552222;}#mermaid-svg-jf882JCg3VHP3IRE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jf882JCg3VHP3IRE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jf882JCg3VHP3IRE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jf882JCg3VHP3IRE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jf882JCg3VHP3IRE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jf882JCg3VHP3IRE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jf882JCg3VHP3IRE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jf882JCg3VHP3IRE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jf882JCg3VHP3IRE .marker.cross{stroke:#333333;}#mermaid-svg-jf882JCg3VHP3IRE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jf882JCg3VHP3IRE p{margin:0;}#mermaid-svg-jf882JCg3VHP3IRE .edge{stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .section--1 rect,#mermaid-svg-jf882JCg3VHP3IRE .section--1 path,#mermaid-svg-jf882JCg3VHP3IRE .section--1 circle,#mermaid-svg-jf882JCg3VHP3IRE .section--1 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section--1 text{fill:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth--1{stroke-width:17;}#mermaid-svg-jf882JCg3VHP3IRE .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-0 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-0 path,#mermaid-svg-jf882JCg3VHP3IRE .section-0 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-0 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-jf882JCg3VHP3IRE .section-0 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-0{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-0{stroke-width:14;}#mermaid-svg-jf882JCg3VHP3IRE .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-1 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-1 path,#mermaid-svg-jf882JCg3VHP3IRE .section-1 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-1 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-1 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-1{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-1{stroke-width:11;}#mermaid-svg-jf882JCg3VHP3IRE .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-2 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-2 path,#mermaid-svg-jf882JCg3VHP3IRE .section-2 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-2 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-2 text{fill:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-2{stroke-width:8;}#mermaid-svg-jf882JCg3VHP3IRE .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-3 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-3 path,#mermaid-svg-jf882JCg3VHP3IRE .section-3 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-3 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-3 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-3{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-3{stroke-width:5;}#mermaid-svg-jf882JCg3VHP3IRE .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-4 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-4 path,#mermaid-svg-jf882JCg3VHP3IRE .section-4 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-4 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-4 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-4{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-4{stroke-width:2;}#mermaid-svg-jf882JCg3VHP3IRE .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-5 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-5 path,#mermaid-svg-jf882JCg3VHP3IRE .section-5 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-5 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-5 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-5{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-5{stroke-width:-1;}#mermaid-svg-jf882JCg3VHP3IRE .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-6 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-6 path,#mermaid-svg-jf882JCg3VHP3IRE .section-6 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-6 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-6 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-6{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-6{stroke-width:-4;}#mermaid-svg-jf882JCg3VHP3IRE .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-7 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-7 path,#mermaid-svg-jf882JCg3VHP3IRE .section-7 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-7 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-7 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-7{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-7{stroke-width:-7;}#mermaid-svg-jf882JCg3VHP3IRE .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-8 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-8 path,#mermaid-svg-jf882JCg3VHP3IRE .section-8 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-8 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-8 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-8{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-8{stroke-width:-10;}#mermaid-svg-jf882JCg3VHP3IRE .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-9 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-9 path,#mermaid-svg-jf882JCg3VHP3IRE .section-9 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-9 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-9 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-9{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-9{stroke-width:-13;}#mermaid-svg-jf882JCg3VHP3IRE .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-10 rect,#mermaid-svg-jf882JCg3VHP3IRE .section-10 path,#mermaid-svg-jf882JCg3VHP3IRE .section-10 circle,#mermaid-svg-jf882JCg3VHP3IRE .section-10 polygon,#mermaid-svg-jf882JCg3VHP3IRE .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-10 text{fill:black;}#mermaid-svg-jf882JCg3VHP3IRE .node-icon-10{font-size:40px;color:black;}#mermaid-svg-jf882JCg3VHP3IRE .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .edge-depth-10{stroke-width:-16;}#mermaid-svg-jf882JCg3VHP3IRE .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-jf882JCg3VHP3IRE .disabled,#mermaid-svg-jf882JCg3VHP3IRE .disabled circle,#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:lightgray;}#mermaid-svg-jf882JCg3VHP3IRE .disabled text{fill:#efefef;}#mermaid-svg-jf882JCg3VHP3IRE .section-root rect,#mermaid-svg-jf882JCg3VHP3IRE .section-root path,#mermaid-svg-jf882JCg3VHP3IRE .section-root circle,#mermaid-svg-jf882JCg3VHP3IRE .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-jf882JCg3VHP3IRE .section-root text{fill:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .section-root span{color:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .section-2 span{color:#ffffff;}#mermaid-svg-jf882JCg3VHP3IRE .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-jf882JCg3VHP3IRE .edge{fill:none;}#mermaid-svg-jf882JCg3VHP3IRE .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-jf882JCg3VHP3IRE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RAG
离线建库
文档解析
Chunking分块
Embedding向量化
存入向量数据库
在线检索
Query Embedding
向量检索Top-K
Reranker重排序
生成
构建Prompt
LLM生成
基于文档回答

RAG 的核心价值:

让 LLM 基于可信的外部知识回答问题,减少幻觉,支持知识更新。


本章思考题

  1. Chunk Size 太小和太大分别会导致什么问题?
  2. 为什么两阶段检索(向量召回 + Reranker 重排)比单阶段效果好?
  3. 如果用户的问题需要综合多个文档的信息,RAG 应该如何处理?
  4. RAG 和 Fine-tuning 各有什么优缺点?什么时候用哪个?

下一章预告

下一章我们进入 第六篇:实战。

我们将从零开始:

  • 用 TensorFlow 实现一个完整的 Transformer
  • 训练一个简单的 GPT
  • 实现一个完整的 RAG 系统
相关推荐
2301_801821711 小时前
推进语义文本相似性建模:一个具有平移ReLU和平滑 K2损失的回归框架
人工智能
IT_陈寒1 小时前
我花3小时debug,就因为JavaScript这个隐式转换坑
前端·人工智能·后端
我是小白呀1 小时前
23-AI说可以开通以后呢:权限、审批、审计与执行门禁
人工智能·workflow
2401_890095611 小时前
武汉企业AI私有化部署验收需核对哪些日志字段?
人工智能·验收标准·武汉自动意志科技有限公司·智钳ai智能体聚合平台·企业ai私有化部署·日志字段
北京中科新远科技1 小时前
AI网卡五层检查法:协议、PCIe、NUMA、端口与验收
服务器·网络·人工智能
小苑同学1 小时前
Introduction怎么写
人工智能
径硕科技JINGdigital1 小时前
企业希望使用OpenAI ChatGPT系列模型构建业务应用,推荐通过哪些云平台接入和部署?
人工智能·其他
wp123_11 小时前
TLVR 电感在 AI 服务器电源中的应用与市场前景分析
服务器·人工智能·科技·ai·硬件工程
鲸能云1 小时前
【AI Agent】光储运维从 “展示数据“ 到 “自主决策“:运维 AI Agent 落地实践拆解
大数据·人工智能·ai agent·智能运维·光伏储能