乐于分享
好东西不私藏

RAG 工程实践(一):一份文档,如何变成可检索的知识

RAG 工程实践(一):一份文档,如何变成可检索的知识

开篇:答案在文档里,为什么仍然检索不到

设想一个常见场景:集团把《差旅费用管理办法》的 PDF(便携式文档格式)接入知识库后,员工问:“跨城培训住宿超过标准能否报销?”答案其实写在制度里,却没有被找出来,系统反而给出了错误的报销上限。

问题往往并不神秘,常见失败包括:

每页重复的页眉、页脚挤进正文。
双栏页面被按错误顺序读成一段话。
“经区域负责人书面批准”这一条件与后面的结论被拆开。
表格只留下金额,丢了“元/晚”这样的单位。
新旧版本一起进入知识库。
即使命中一句话,也没有页码和标题路径让审核人核对出处。

此时再调整检索排序,得到的仍是失真的输入。对读者而言,这像一次 Retrieval-Augmented Generation(检索增强生成,RAG)失败;对工程团队而言,许多失败其实更早发生在 Data Indexing(数据索引)——知识还没有被准备成可靠使用的证据。

完整 RAG 流程与本文边界

一套完整的 RAG 流程可以分为三个边界:

1.
Data Indexing(数据索引): 把原始文档整理为能够查找、核验和引用的知识。
2.
Retrieval(检索): 面对用户问题,从已经发布的知识中找出候选证据。
3.
Generation(生成): 依据这些证据组织回答。

三个阶段彼此相连,但各自解决不同问题。

下面的流程图给出本文坐标:原始文件先经过解析、清洗、切分和治理,再完成嵌入并形成混合索引。本文只讲第一步,止于 Published Hybrid Index(已发布混合索引);后续的在线检索与回答生成只用于说明位置,将在后续文章展开。

图 1 RAG 全流程与本文边界

处理到这一步,文件本身还不是“可用知识”。接下来的 Parsing(解析)与 Cleaning(清洗),要把它恢复成既忠于原文、又方便后续处理的形态。

Parsing & Cleaning:恢复可用的文档结构

Parsing 负责识别文档中有什么,Cleaning 负责去掉干扰而不改变原意。它们的交付物不是一长串抽出的文字,而是 Normalized Document Tree(标准化文档树):一种统一的中间表示,能够同时保留正文、标题层级、列表、表格、图片之间的关系,以及回到原文的位置。

这一区别决定了后续质量。PDF 的文字流未必保存表格单元格和行边界;扫描件即使识别出了文字,也可能把阅读顺序弄错。因此,Parsing 是否成功不能只看“是否抽到了文本”,还要逐项检查:[1][2][3]

条件与结论是否仍然相邻。
表格单位是否仍属于正确数值。
每段内容是否能回到原始页面。

处理路线应由“页面中的信息以什么形态存在”决定,而不是只看文件扩展名。常见能力各自解决不同问题:

Parser(解析器): 读取本就带有文字和基本结构的内容。
OCR(光学字符识别): 把扫描图像中的文字转换为机器可处理的文本。
Layout Analysis(版面分析): 判断双栏、标题、页眉页脚和图片区块的空间关系。
Structure Extraction(结构提取): 恢复章节、列表和表格等内容之间的层级。
Multimodal Extraction(多模态提取): 在图文共同表达含义时,保留图片与周围文字的关联。

一个 PDF 可能是可直接读取的正文,也可能是扫描件或复杂版面;同一个扩展名不能替代对页面形态的判断。

DOCX(文字处理文档)、XLSX/CSV(工作簿/逗号分隔值)、PPTX(演示文稿)和 HTML(网页文档)各自带有可利用的结构线索。其中 DOCX、XLSX 和 PPTX 属于 Office Open XML(开放式办公 XML)格式,其结构依据来自该格式标准;HTML 的文档结构和 CSV 的记录、字段结构分别有各自的标准依据。[4][5][6] 旧的 .doc、.xls、.ppt 不在 Office Open XML 的覆盖范围内,需要单独选择解析器并独立验收,不能沿用开放 XML 格式的结构假设。

下表按 Document Type(文档类型)列出常见内容的处理重点。它不是产品选型清单,而是验收时可以逐项判断的结构检查表。

Document Type 处理重点 必须保留的结构 常见失败
PDF 校正双栏等复杂页面的阅读顺序,并移除重复页眉和页脚。 页码、标题层级、表格边界、数值单位和原始阅读顺序。 左右两栏交错、页脚混入正文,或金额与单位分离。
DOCX 区分正文、批注和修订内容,并识别重复模板区域。 标题层级、列表层级、表格关系和有效版本的正文。 条款层级被压平,或修订稿被误当成现行制度。
HTML 提取主内容,排除导航、广告和重复推荐区域。 页面标题、正文顺序、列表、链接文字与其指向关系。 菜单或推荐内容进入知识库,正文失去链接上下文。
XLSX/CSV XLSX 识别工作表、合并单元格、表头、数据行和单位;CSV 识别分隔规则、表头、数据行和单位。 XLSX 保留工作表、合并关系及表头—数据行—单位关系;CSV 保留表头—数据行—单位关系。 XLSX 的合并关系或空行造成错段;CSV 分隔错误会使表头、数据行或单位错位。
PPTX 按每页的主题聚合文字、图表和备注,并识别重复版式。 幻灯片标题、内容组、备注,以及图表或图片与说明文字的对应关系。 模板文字淹没正文,或图表脱离其解释文字。
Image/Scan(图片/扫描件) 纠正方向并识别文字块和页面区域,再核对识别质量。 原始页面、文字块位置、阅读顺序和图像区域。 倾斜导致漏识,文字块顺序错误,且低质量内容无法复核。

下面的路由图展示了按内容形态选择处理路线的过程:不同分支最后都汇合为同一个 Normalized Document Tree。

图 2 不同文档的解析路由

要让这棵树真正可用,团队至少应守住三条原则。

Preserve Structure(保留结构): 标题、列表、表格、页码和阅读顺序应随内容一起保留。否则条件可能脱离结论,表格中的单位也可能脱离数值,后续即使找到了文字也无法正确解释。
Remove Boilerplate(清理模板噪声): 可以去掉反复出现的页眉、页脚、导航和通知,但不能为了“干净”而删掉版本、生效范围、密级或例外条件。过度清洗会把判断依据一并抹去。
Keep Traceability(保留可追溯性): 每段可引用内容都应能回到源文件、具体版本及该类型可用的结构位置。无法回源的命中无法审计、无法确认是否仍有效,也难以在制度更新时纠正或撤回。

不同文档的回源位置示例包括:

PDF 页码。
PPTX 幻灯片。
XLSX 工作表或数据行。
HTML 标题或链接。

Parsing 与 Cleaning 的目标不是抽取尽可能多的文字,而是恢复可被后续切片、检索和引用共同使用的文档结构。

Chunking:按语义单元切分

Chunking(切片)将文档组织为 Chunk(切片单元);一个可用的 Chunk 不是按固定字符数裁出的文本,而是能够独立召回的证据单元:它保留判断问题所需的最小完整上下文,同时能沿标题层级或父级关系回到原文。制度中的条件、结论与例外,表格中的表头、单位与数据行,都不应因为长度计数而失去联系。

Token(词元)适合度量模型输入,却不是语义边界。切分时需要同时权衡三类影响:[7][8]

Chunk Size 过小: 容易拆散跨句、跨段依赖。
Chunk Size 过大: 容易让命中的相关内容淹没在无关上下文中。
Overlap 增加: 可以缓解边界截断,但也会增加索引体量和重复候选。

这些参数都不能替代对内容结构的判断。

下表比较六类 Strategy(策略)。它的作用不是给出唯一答案,而是说明不同切分起点的适用条件、优势和风险。

Strategy 如何切分 适合内容 优势 主要风险
Fixed-size(固定长度切片) 按统一长度切开,必要时保留相邻边缘。 句子较短、分布均匀且跨段依赖少的文本。 实现简单,吞吐和成本容易估算。 条件与结论可能恰好落在边界两侧。
Recursive(递归切片) 先按段落等较大边界切分,超出容量再逐级下钻到句子或词。 段落边界稳定、但缺少严格层级的通用文档。 在满足容量限制的同时,尽量保留较大的语义单元。 分隔符与真实结构不一致时,仍会误切。[7][8]
Structure-aware(结构感知切片) 沿标题、章节、条款和版面块边界切分。 制度、手册、网页等结构明确的内容。 能保留标题路径和内容类型,便于回源。 上游结构识别错误会被继续放大。
Semantic(语义切片) 根据主题变化识别边界,将语义连续的句段合并。 访谈、纪要和连续叙事等弱结构文本。 不依赖固定分隔符,更容易保持主题连续。 边界受模型、语料分布和判断阈值影响,结果与成本更难预测。
Parent-Child(父子切片) 用较小的 Child 参与召回,命中后补充其所属 Parent。 条件、例外或解释分散在多个段落的长条款。 同时兼顾精细定位与较完整的判断上下文。 父子错配会带回错误原文,Parent 过大又会引入噪声。
Block-specific(块类型专用切片) 先识别表格、代码或列表,再按各自内部结构切分。 表头与数据行、函数签名与函数体、有引导语的列表。 可针对不同内容保护关键依赖,并与其他策略组合。 块类型识别错误,或跨块说明未被关联,都会造成上下文缺失。

图 3 Chunking 策略选择路径

图 3 给出的顺序可以作为策略选择的起点:

1.
判断文档是否有稳定结构。 标题、条款和段落可靠时,优先从 Structure-aware 或 Recursive 开始。
2.
检查答案是否依赖相邻段落。 条件、结论和例外分散时,可用 Parent-Child 保持联系。
3.
识别表格、代码和列表。 把这些特殊块交给 Block-specific 处理;这一步可以与前面的策略组合。
4.
处理弱结构连续叙事。 内容缺少可靠分隔符、主要靠连续叙事推进时,再考虑 Semantic。

Fixed-size 更适合作为结构弱且内容均匀时的基线,而不是默认答案。

这棵决策树不会自动产生最佳参数。同一种制度文档,不同问题也可能需要不同粒度。例如:

查询具体报销标准时,小块便于定位。
判断例外是否成立时,需要同时看到条件和结论。

最终选择必须回到真实语料与真实查询集,而不能只根据文档类型套规则。

切分失败往往在后续才暴露,常见表现包括:

条件与结论分离时,Retrieval 可能只召回结论,Generation 随后把有条件的规定说成无条件规则。
表格的表头或单位丢失时,即使命中金额,也无法判断它属于哪个项目、采用什么计量口径。
父子关系错配时,命中的 Child 会扩展到另一段 Parent,直接带回错误证据。
Parent 过大时,真正相关的句子会被大量无关条款包围,既降低定位精度,也增加 Generation 混淆证据的风险。

Chunk Size 与 Overlap 没有跨语料通用答案。验证时应按顺序执行:

1.
固定一套版本化的真实查询集。
2.
比较不同策略在召回类 Retrieval 指标上的表现。
3.
逐条复盘条件遗漏、表格错位和错误父级等失败样本。
4.
参数调整后保留查询集版本、切分版本和失败样本。

这样才能判断改善来自策略本身,还是来自样本变化。

Metadata:让 Chunk 可定位、可管理

Metadata(元数据)的价值,不是给 Chunk 贴上尽可能多的标签,而是让证据在进入索引后仍然知道自己从哪里来、位于哪里、谁可以使用,以及出现问题时如何追查。它连接的是检索命中与原始文档,也是发布、撤回和审计能够落地的基础。

Source(来源): 解决“这段内容来自什么原件”的问题。对于一条制度证据,应能确认它来自哪份正式文件、属于哪个发布版本,而不是来自临时副本或已失效稿件。这样在内容更新或争议发生时,团队才能确认权威来源,并准确撤回受影响的索引内容。
Location(位置): 解决“如何回到原文核对”的问题。PDF 中的页码与标题路径、演示文稿中的具体页面、电子表格中的工作表和数据位置,都应延续 Parsing 阶段已经恢复的结构。命中结果只有能跳回原始位置,才适合作为引用,也便于审核人检查上下文是否完整。
Governance(治理): 解决“这段内容现在是否允许被谁使用”的问题。同一知识库可能同时存在不同组织的数据、待生效制度和历史版本;访问边界、有效范围与发布状态必须随证据进入检索过滤。ACL(访问控制列表)缺失或版本状态不明时,系统不应把内容当作普通候选,否则一次召回就可能演变为越权泄露或过期规则被重新引用。
Observability(可观测性): 解决“错误经过哪条处理链路产生”的问题。当金额单位丢失或文本识别异常时,应能追溯到对应的采集批次、解析版本与质量记录,区分问题来自源文件、Parsing、Chunking 还是索引发布。保留这些处理依据,也让同类失败可以批量定位、修复并重新验证。

Metadata 不是越多越好,只保存能被检索过滤、引用回源、权限治理、版本管理或问题排查实际消费的信息。

Embedding:把文本转换为可比较的表示

Embedding(嵌入)把 Chunk 转换为可比较的向量表示,让写法不同但含义相近的内容有机会靠近。模型选型不应从榜单名次直接跳到采购决定:MTEB(大规模文本嵌入基准)表明,没有一个模型能在所有评测项目上始终占优;C-MTEB(中文大规模文本嵌入基准)补充了中文场景的评测覆盖。两者适合缩小候选范围,不能代替企业自己的数据验证。[9][10]

真正的选择过程,可以依次回答四个问题。

1.
语言与领域术语是否匹配? 先盘点文档和提问中实际出现的语言组合,再加入业务缩写、产品编号、政策名称和内部惯用表达。通用中文表现良好,不代表模型能区分企业里的近义术语;英文评测领先,也不代表中英混合提问不会漂移。候选模型应在这些真实表达上接受分层检验。
2.
Context(上下文容量)能否覆盖实际 Chunk? 这里看的不是宣传页上的上限,而是标题路径、正文、表格说明等共同进入模型后,关键条件是否仍被完整编码。容量不足时,模型可能拒绝输入,也可能按具体实现截断输入;如果采用尾部截断,位于末尾的例外条款尤其容易丢失。容量更大也不会自动修复上游已经切错的内容,因此要结合真实 Chunk 分布和失败样本判断。
3.
Query/Document(查询/文档)编码方式是否匹配? 有些候选模型会区分问题与知识文本的输入角色。团队需要确认索引文档和业务提问是否采用了模型预期的对应方式,并用成对样本检查语义能否正确靠近。只验证文档侧“能够生成向量”,无法发现两端编码失配。
4.
业务查询集上的质量、Latency(延迟)与 Cost(成本)能否同时接受? 使用固定的版本化查询集,覆盖高频问题、长尾表达、高风险意图和历史失败样本,同时评估分层质量、目标并发下的响应时间,以及首次构建、增量更新和模型升级成本。质量领先但无法按时返回或无法承担重建成本的模型,同样不适合生产环境。

选型完成也不是生命周期的终点,仍需关注三类并列风险:

模型升级会改变向量表示,新旧向量混在同一检索空间里,结果可能失去可比性。
公开评测集与企业查询分布不同,榜单提升也可能在真实业务里退化。
只看平均分,可能把权限制度、金额标准等少量关键查询的失败掩盖掉。

因此,模型、语料、查询集和评测结果应共同版本化。每次升级都应隔离生成候选结果,重新跑同一套业务评测,并复盘新增与既有失败样本后再决定是否发布。

Embedding 选型的终点不是“找到榜单第一”,而是证明候选模型在自己的语言、术语、上下文和成本边界内可靠。

Hybrid Index:让不同类型的问题都有入口

只依赖一种检索信号,会把它不擅长的问题变成系统盲区。混合索引的价值,是让语义、原文字面和治理属性各自有合适的入口。这里讨论的是三类互补的逻辑检索信号或能力,不是必须分别建设三个物理索引:它们可以共存于一个物理索引,也可以按搜索产品的能力拆分。

向量信号:承接语义相近的表达。 它利用 Embedding 的向量表示,适合处理同义词、口语化问题和不照搬原文的改写。承载这类信号的能力常被称为 Vector Index(向量索引),是现有搜索系统支持相似检索的一类实现。[11]
关键词信号:守住不可模糊的字面信息。 制度编号、产品代码、专有名词、精确金额和罕见缩写,往往差一个字符就代表另一件事。常被称为 Keyword Index(关键词索引)的能力保留这些字面信号,弥补向量表示可能把相似字符串或相近概念混在一起的问题。
元数据过滤能力:准备可执行的治理条件。 Data Indexing 只负责保存可过滤的权限、租户、版本、生效状态和时间范围等属性。Metadata Index(元数据索引)可以让这些属性便于过滤,却不知道当前请求者是谁,也不能替代在线授权判断。

以向量信号为例,下面两种写法没有复用原词,但语义接近:

用户问题:“培训住酒店超标怎么办?”
制度原文:“住宿费超出限额。”

在线 Retrieval 必须绑定当前请求者身份,根据这些属性执行 Fail-closed(默认拒绝)过滤:身份或权限条件缺失、无效或无法判定时,不让证据进入候选。本篇只说明 Data Indexing 应准备什么,不展开在线信号组合与授权实现。

Hybrid Index 的意义不是堆出三个物理索引,而是让三类逻辑检索能力各自承担擅长的问题。

Validation & Publishing:验证后再发布

Validation(验证)回答“候选结果是否合格”,Publishing(发布)回答“如何让线上稳定地使用合格版本”。两者必须连成一条质量链路,按四个动作执行。

1.
构建候选索引。 将本次解析、Chunking、Metadata 和 Embedding 的产物写入与线上版本隔离的候选空间,并记录各阶段使用的输入与版本。已有搜索系统对承载数据后的结构变更设有限制,也提供把数据重建到新索引的路径;这说明隔离候选版本具有现实工程依据,但不是要求所有产品照搬同一机制。[12][13]
2.
完成质量校验。 解析结果要抽查阅读顺序、表格单位与回源位置;Chunk 要检查条件、结论和例外是否完整;Metadata 要验证来源、权限、版本与时间信息;Embedding 要确认全部目标内容完成转换且版本一致;固定查询集还要比较当前版本与候选版本,逐条复盘关键失败。流水线执行成功,只能说明流程跑完,不等于新索引质量合格。
3.
切换稳定入口。 只有候选版本通过质量校验,才把面向线上检索的稳定入口切到新版本。调用方继续使用同一个入口,不应感知底层版本名称变化。已有产品文档展示了稳定逻辑名称在底层索引之间切换的能力;这里采用的是其背后的发布原则,不限定具体产品机制。[14]
4.
保留上一版用于回滚。 新版本发布后继续观察固定查询集、错误率、响应时间和高风险问题表现,并在回滚窗口内保留上一良好版本。一旦出现关键查询退化、权限边界异常或数据不完整,应先把稳定入口切回上一版,再隔离分析并重建候选版本。

这四个动作把“流水线跑完”与“可以发布”区分开来,并将发布变成可验证、可撤销的状态变化。候选版本未通过质量校验时不能进入线上;上一版尚未安全保留时,也不应贸然切换。

发布成功的标准不是处理流程没有报错,而是新索引通过质量校验、能够稳定切换,并且出现问题时可以回到上一良好版本。

结语与系列衔接

从原始文件到已发布混合索引,每一步都在决定后续检索究竟能看到什么:

1.
Parsing 与 Cleaning 恢复结构。
2.
Chunking 保住可独立判断的证据。
3.
Metadata 补上来源、位置、权限和版本。
4.
Embedding 建立语义表示。
5.
三类逻辑检索能力提供互补入口。
6.
验证与发布把质量合格的版本交给线上。

如果上游出现以下任一问题,后续排序和生成都无法凭空还原已经消失的信息:

把双栏页面读乱。
把条件与结论拆开。
丢失表格单位。
让过期版本进入候选范围。

反过来,Data Indexing 做得扎实,检索阶段才有机会在正确边界内找到完整、可核验的证据。

Data Indexing 决定后续检索能看到什么;没有被保存下来的结构、语义和治理信息,在本文所述的在线检索与生成链路中无法可靠补回,需要返回 Data Indexing 修复并重建。

第二篇将从在线 Retrieval 开始,依次认识:

1.
Query Processing(查询处理)。
2.
Query Rewrite(查询改写)。
3.
Similar Question Generation(相似问题生成)。
4.
HyDE(假设文档嵌入)。
5.
Semantic Search(语义检索)。
6.
Exact Search(精确检索)。
7.
Metadata Filter(元数据过滤)。

这里只先列出主题,具体实现留到下一篇展开。

参考资料

1.
Apache Tika, Apache Tika 3.3.2, 2026-07-16,访问日期 2026-08-09。
2.
Apache Tika, PDFParser,访问日期 2026-08-09。
3.
Apache Tika, PDFParserConfig,访问日期 2026-08-09。
4.
Ecma International, ECMA-376,第 5 版,2021-12,访问日期 2026-08-09。
5.
WHATWG, HTML Living Standard,持续更新,访问日期 2026-08-09。
6.
IETF, RFC 4180: Common Format and MIME Type for CSV Files,2005-10,访问日期 2026-08-09。
7.
LangChain, Text splitters,在线文档,访问日期 2026-08-09。
8.
LangChain, Splitting recursively,在线文档,访问日期 2026-08-09。
9.
Muennighoff et al., MTEB: Massive Text Embedding Benchmark, 2023-05,访问日期 2026-08-09。
10.
Xiao et al., C-Pack: Packed Resources For General Chinese Embeddings,首次提交 2023-09-14;arXiv v5 最新修订 2024-09-24,访问日期 2026-08-09。
11.
OpenSearch Project, k-NN vector,在线文档,访问日期 2026-08-09。
12.
OpenSearch Project, Create or Update Index Mappings API,在线文档,访问日期 2026-08-09。
13.
OpenSearch Project, Reindex data,在线文档,访问日期 2026-08-09。
14.
OpenSearch Project, Index aliases,在线文档,访问日期 2026-08-09。