外观
RAG 基础链路:数据清洗、切片与版本治理
面试结论| RAG 的上限往往先由数据工程决定:清洗负责让内容可信且可解析,切片负责让证据既能被找到又保留足够语境,元数据与版本负责让系统只召回“有权限、在有效期、与当前模型兼容”的证据。三者不是离线杂务,而是线上检索质量、安全和可回滚性的共同前提。
目录
- 1. 为什么先补数据层
- 2. 小白先这样理解
- 3. 数据清洗不是删空格
- 4. 切片如何兼顾可检索与可理解
- 5. 元数据、权限与版本区分
- 6. 数据样例与最小实现
- 7. 技术点清单与横向选型
- 8. 架构与调用流程
- 9. 生产风险、监控与验证
- 10. 面试追问与总结
1. 为什么先补数据层
很多团队看到回答不准,第一反应是换 Embedding、增大 TopK 或改 Prompt。但如果原始 PDF 表格错位、页眉重复进入正文、旧版本和新版本混在一起、一个 Chunk 把“适用条件”与“结论”切开,那么后面的检索与生成只能更快地消费脏数据。
数据层要回答四个问题:
- 这段内容是否值得进入知识库? 来源是否可信、正文是否完整、重复与乱码是否处理;
- 它以什么粒度进入索引? Chunk 是否有完整语义、稳定 ID、父子关系和定位信息;
- 谁在什么条件下可以看到? 租户、ACL、部门、地区、产品、语言和有效期如何表达;
- 它属于哪个版本世界? 原文、解析器、切片策略、Embedding、索引和业务规则版本能否追溯。
2. 小白先这样理解
小白先这样理解:给城市急救中心整理手册
凌晨两点,急救中心接到电话:“孩子误服了清洁剂怎么办?”值班员面前有三箱资料:一本最新版急救手册、一本五年前旧版、还有一沓扫描歪斜且页码混乱的培训讲义。如果他只按“意思相近”翻资料,很可能先找到旧版;如果把一整本书摊在桌上,又来不及定位关键步骤。
资料管理员先做四件事:去掉重复页和广告页,校正扫描文字;按“危险判断—禁止动作—处置步骤—送医条件”切成可以独立阅读的卡片;在卡片上贴“儿童、误服、2026 版、仅急救人员可见”的标签;最后记录卡片来自哪一页、哪次修订。
技术映射如下:
| 生活元素 | RAG 对象 | 作用 |
|---|---|---|
| 歪斜扫描、重复页 | 原始 PDF/OCR 噪声 | 数据清洗与解析质量问题 |
| 可独立阅读的急救卡片 | Chunk | 检索和上下文构造的基本证据单元 |
| 儿童、2026 版、权限标签 | Metadata/ACL | 检索前过滤与版本约束 |
| 原书页码和修订记录 | Lineage/Version | 引用、审计、回滚与重建 |
| 值班员的问题 | Query | 在线检索输入 |
类比边界: 人能凭常识发现旧手册不可靠,系统不会自动拥有这种判断;标签写错、OCR 漏字或切片断裂时,向量相似度可能仍然很高。因此必须用数据校验、评测集和 Trace 验证,而不能只相信“看起来相似”。
3. 数据清洗不是删空格
3.1 清洗的五层职责
| 层次 | 典型问题 | 处理动作 | 必留证据 |
|---|---|---|---|
| 文件层 | 损坏、加密、重复附件、格式不支持 | 校验哈希、格式嗅探、去重、隔离失败文件 | source_hash、MIME、失败原因 |
| 解析层 | OCR 乱码、表格错列、阅读顺序错误 | 版面解析、OCR 置信度、表格/图片保留 | 页码、块坐标、解析器版本 |
| 文本层 | 页眉页脚、断词、不可见字符、模板噪声 | 规范化、重复检测、语言识别 | 清洗规则版本、前后差异 |
| 语义层 | 标题丢失、条件与结论分离、跨页表格 | 结构恢复、章节树、父子关系 | 标题路径、父块 ID |
| 治理层 | 旧版本、敏感信息、越权内容、来源不可信 | ACL、脱敏、有效期、审批与下线 | 权限策略、状态、责任人 |
3.2 清洗的正确顺序
先保留原件和哈希,再解析;先恢复结构,再做文本规范化;先判断内容是否可发布,再切片和 Embedding。不要直接覆盖原文,因为后续需要对照 OCR 错误、重新解析或审计引用。
一个最小数据质量报告至少包含:
json
{
"document_id": "policy-2026-017",
"source_hash": "sha256:...",
"parser_version": "layout-parser-3.2",
"page_count": 18,
"parsed_block_count": 146,
"ocr_low_confidence_ratio": 0.031,
"duplicate_block_ratio": 0.082,
"empty_page_count": 0,
"quarantine_reasons": []
}这些数字是示例 Schema,不是本仓库实测值。生产阈值应从人工标注样本、来源类型和错误成本中确定。
3.3 清洗常见误区
- 把所有空白合并,导致代码缩进、表格列或公式结构丢失;
- 只按文本哈希去重,忽略“同内容不同权限/版本”的治理差异;
- OCR 低置信内容照常发布,却没有降权、隔离或人工复核;
- 清洗后不保留
source_hash与parser_version,出错时无法重放; - 把个人信息脱敏放在生成后,导致敏感内容已经进入索引和 Trace。
4. 切片如何兼顾可检索与可理解
4.1 Chunk 的三重目标
一个好 Chunk 要同时满足:
- 可召回: 问题中的关键实体、术语或语义能在块中形成明确检索信号;
- 可判别: 粗排和精排模型能看懂它是否回答问题;
- 可生成: 放入上下文后,条件、结论、例外和来源足够完整。
Chunk 越小,定位通常越精确,但更容易丢上下文;Chunk 越大,语境更完整,却可能稀释关键词和向量主题,并消耗更多 Token。不存在通用的“512 Token 最优”。
4.2 常见切片策略横向比较
| 策略 | 如何切 | 优点 | 代价与失败模式 | 适用场景 |
|---|---|---|---|---|
| 固定字符/Token | 每 N 个单位切,保留 overlap | 简单、稳定、易并行 | 可能切断句子、表格和条件 | 结构弱、快速基线 |
| 递归分隔 | 标题→段落→句子→Token | 尽量保留自然边界 | 规则与语言/格式相关 | 通用文档知识库 |
| 结构感知 | 按标题、表格、代码块、页面区域 | 语义和引用位置清晰 | 依赖解析质量和格式适配 | 制度、API、论文、合同 |
| 语义切片 | 依据相邻句向量变化切分 | 可发现主题转折 | 计算更贵、阈值不稳定 | 长叙述、结构缺失文本 |
| 父子切片 | 小块召回,返回或扩展父块 | 兼顾命中粒度与上下文 | 存储、去重和 Token 控制更复杂 | 手册、章节化文档 |
| 句窗检索 | 命中句后带前后窗口 | 定位精细,扩展直观 | 窗口可能跨越无关小节 | FAQ、规章条款、日志说明 |
4.3 overlap 不是越大越好
overlap 的直接目的,是让前一个 Chunk 的尾部在后一个 Chunk 的开头重复出现,降低切点恰好截断完整证据的风险。它主要保护条件与结论、实体与解释、代词与指代对象、表头与数据行、函数签名与关键代码等真实跨边界关系,而不是笼统地让所有文本“更连贯”。
例如,假设按 100 Token 切片,并把第 81~100 个 Token 同时放入下一个 Chunk;原本横跨第 90~110 个 Token 的证据,就有机会完整出现在后一个 Chunk 中。这里的数值只是说明机制,不是推荐参数:生产配置应先尊重标题、段落、句子、表格和代码块等结构边界,再用最小必要 overlap 补偿仍无法避免的跨边界关系。
overlap 与 parent_chunk_id 解决的阶段不同:overlap 在候选召回前保护相邻子块切点附近的局部证据;parent_chunk_id 在子块命中后扩展回完整父块。若子块因边界截断而根本没有被召回,父块扩展也不会触发;反过来,父子切片已经能稳定补回上下文时,通常也没有必要用很大的 overlap。
overlap 过大会制造近重复 Chunk:同一证据占据多个 TopK 位置,Recall@K 看似变好,真正的信息覆盖却下降,还会增加索引、Embedding 和上下文 Token 成本。应同时监控:
text
unique_evidence_ratio@K = TopK 中不同证据簇数量 / K
duplicate_token_ratio = 重复上下文 Token / final_context 总 Token4.4 父子切片与 overlap 如何组合
需要先纠正一个常见表述:parent_chunk_id 本身不提高检索准确率,真正降低关键词或向量主题稀释的是“用较小 Child Chunk 建索引和召回”。parent_chunk_id 只是把命中的 Child 映射回较完整 Parent 的关联键,从而把检索粒度与生成上下文粒度解耦;如果直接索引和召回 Parent,或者 Child 本身切得不合理,这个字段不会自动提高准确率。
| 维度 | 小块召回 + parent_chunk_id | overlap |
|---|---|---|
| 主要问题 | 小块容易命中,但单块语境不足 | 固定或递归切点可能截断局部证据 |
| 生效阶段 | Child 命中、重排后,再回填 Parent | 建索引前,在相邻 Chunk 中复制边界文本 |
| 主要收益 | 检索信号集中,同时补回条件、例外和章节语境 | 让跨切点的短关系至少完整出现在一个候选中 |
| 主要代价 | Parent 回填过大可能重新引入噪声和上下文稀释 | 近重复候选、索引与 Embedding 成本、TopK 挤占 |
长手册、制度和章节化文档可以采用以下组合链路:
text
结构化 Parent
→ 切成可判别的 Child,并只为真实跨边界关系保留小 overlap
→ 对 Child 建索引、召回和重排
→ 按 parent_chunk_id 聚合去重
→ 只为高分 Child 回填 Parent 或句窗
→ 按 Token 预算构造 final_context选择时不要机械地“两者都开”:短 FAQ 本身已是完整事实时,通常都不需要;结构清晰的长文优先父子切片,并把 overlap 控制在最小必要范围;结构弱、切点不稳定的长叙述可以先用递归或语义切片配合适度 overlap,只有答案经常跨多个子块时再增加 Parent 回填;表格和代码应优先保持表头与数据行、函数签名与实现体等原子结构,overlap 只能作为补偿,不能替代专用解析。
最终应在同一问题集上对比“都不用、只用 overlap、只用父子回填、两者组合”四组实验,同时观察 Child Recall@K、完整证据召回率、答案正确性、引用支持率、unique_evidence_ratio@K、duplicate_token_ratio、延迟和 Token 成本。只有组合方案在完整证据与最终答案上带来的收益超过重复和回填成本,才值得同时使用。
4.5 按文档类型选择切片策略
不同格式不应先统一转成纯文本再按固定 Token 切。正确顺序是:格式识别 → 专用解析 → 结构恢复 → 原子元素保护 → 超长元素二次切分 → 父子关系与定位元数据。标题、段落、列表、表格、代码块和页面区域先作为语义元素;只有单个元素超过 Embedding 或 Reranker 的输入限制时,才按句子、行或 Token 继续拆分。
下表中的数字只适合作为首轮实验起点,不是生产默认值。最终参数必须按真实问题、Embedding 输入限制、Reranker 截断、k_recall 和上下文 Token 预算共同评测。
| 文档类型 | 解析与清洗重点 | 推荐 Child Chunk | Parent/回填方式 | overlap 与特殊规则 | 必留元数据 |
|---|---|---|---|---|---|
| HTML / 网页 | 用 DOM/语义标签恢复正文,去导航、广告、Cookie、页脚和重复模板;保留标题、列表、表格、pre/code | 按 article/section、h1-h6 标题路径和段落组切;长小节再递归到句子/Token | 页面 → 章节 → 子段落;命中子段后回填同章节必要段落 | 结构边界清晰时少用 overlap;表格和代码独立;动态页面保存最终正文快照 | URL、canonical URL、标题路径、DOM 路径、抓取时间、语言、发布日期、内容哈希 |
| Markdown | 先解析 AST,不直接按换行;识别标题、列表、引用、代码围栏、表格和 Frontmatter | 按标题层级切;同一标题下合并相邻短段;代码围栏和表格尽量保持原子 | 文件 → 标题 Section → 段落/代码块 | 普通正文只在超长 Section 内适度 overlap;不能从代码围栏或表格中间机械切 | 文件路径、仓库/分支/Commit、标题路径、行号范围、语言、代码语言 |
| Word / DOCX | 读取 Heading Style、Section、段落、编号列表、表格、批注/脚注和图片说明;过滤页眉页脚 | 按 Heading 层级和连续段落切;条款、列表项、表格分别成块;长章节再按句切 | 文档 → Section/Heading → 段落或条款 | 页码不是主要语义边界;列表编号与正文绑定;表格跨块重复表头 | 文件版本、Heading 路径、Section、段落序号、表格/图片 ID、修订状态 |
| 原生 PDF | 先恢复阅读顺序、双栏、文本块、页眉页脚、表格、图片 Caption 和跨页关系 | 按恢复后的逻辑标题/段落/页面区域切,而不是默认一页一块;表格与正文分开索引并关联 | 文档 → 章节/跨页 Section → 页面区域/段落;检索块回填邻接区域或父章节 | overlap 只补跨页断句;表格按行组切并重复表头;公式、Caption 与解释段关联 | 页码、Bounding Box、阅读顺序、章节路径、表格/图片 ID、解析器版本 |
| 扫描 PDF / 图片文档 | OCR、版面检测、旋转校正、表格识别、置信度与人工复核是发布门禁 | OCR 后仍按版面元素和逻辑章节切;低置信区域单独隔离或降级 | 页面图像 → 区域 → OCR 文本;必要时回填原页截图 | 不用 overlap 掩盖 OCR 错字;跨栏、印章和手写区需要专用处理 | 页码、坐标、OCR 置信度、OCR 模型/语言、原图引用、复核状态 |
| Excel / XLSX / CSV | 识别 Workbook、Sheet、连续表格区域、表头、主键、合并单元格、公式和值;过滤空行列和装饰区 | 不按自然语言 Token 直接切:小型查找表整表;明细表按连续行批次;时间序列按实体 + 时间窗口;宽表按业务列组切 | Workbook → Sheet → Table Region → Row Group;查询命中行后回填表头、键列和必要邻行 | 通常不用文本 overlap;每块重复表头和主键列;宽表拆列时每组都重复业务键;公式与计算值同时保留 | Workbook/Sheet、单元格范围、表名、表头、主键、公式、计算值、日期/币种/单位、数据版本 |
| PowerPoint / PPTX | 读取 Slide Title、正文、图表、图片 Caption、Speaker Notes 和 Section | 默认以单页为原子;同一章节可合并 1~3 个短 Slide;复杂图表单独形成带说明的块 | Deck → Section → Slide → 图表/备注 | 不跨无关 Slide overlap;标题和章节名作为每块前缀;图表需保留数据或可定位说明 | Deck/Section、Slide 编号、标题、Notes、图表/图片 ID、版本 |
| TXT / 长纯文本 | 识别段落、句子、对话角色或日志行;去重复空白但保留结构字符 | 递归使用段落 → 句子 → Token;结构极弱时才考虑语义切片 | 文件 → 主题段 → 句窗 | 可使用最小必要 overlap 保护跨句关系;日志按事件/Trace 而非固定字符切 | 文件、字符/行号范围、时间、语言、编码、主题或事件 ID |
| 源代码 | 使用语言 Parser/AST,识别 Module、Class、Function、Signature、Docstring、Import 与调用关系 | 函数/方法/类作为主要 Chunk;超长函数按逻辑块切,并给每块重复签名和类路径 | 仓库 → 文件/模块 → 类/函数 → 逻辑块 | 不在语句或代码块中间按字符切;调用链通过 Metadata/图关系补充,不靠大 overlap | 仓库、Commit、文件、语言、Symbol、起止行、调用/被调用、测试关联 |
| Email / 工单 / Chat | 保留 Thread、发送者、时间、引用层级、附件和状态变化;删除重复引用正文 | Email 按消息或 Thread 阶段;工单按事件;Chat 按连续对话窗口和主题转折 | Thread/工单 → 消息阶段 → 单条消息/附件 | overlap 可重复少量上一轮用于指代,但应按消息 ID 去重;权限继承自会话 | Thread/Message ID、发送者、时间、参与者、状态、附件、ACL |
4.5.1 Excel 为什么必须单独设计
Excel 的意义主要存在于“行列关系”,不是连续文本。以下三种表格应采用不同方式:
text
小型字典表:整表索引,序列化为 表名 + 表头 + 全部行
大明细表:表头 + 主键列 + 连续 Row Group,每块记录 cell_range
时间序列表:业务实体 + 连续时间窗口,禁止随机混合不连续日期
宽表:按业务列组拆分,每组重复主键、时间和单位列如果表格是实时库存、价格或账户余额,通常不应把历史 Excel Chunk 当作当前真值;应把字段说明、计算口径和历史快照放入 RAG,把最新数值交给受控 SQL/API Tool 查询。
4.5.2 一个可落地的格式路由器
首轮实现可以把格式路由和策略写成显式配置,而不是在一个通用 Splitter 中堆条件:
yaml
html: {parser: dom, chunker: heading_parent_child, atomic: [table, code]}
md: {parser: md_ast, chunker: heading_parent_child, atomic: [table, code_fence]}
docx: {parser: ooxml, chunker: heading_parent_child, atomic: [table, list]}
pdf: {parser: layout, chunker: section_region, atomic: [table, figure]}
xlsx: {parser: sheets, chunker: table_row_group, repeat: [header, key_columns]}
pptx: {parser: slides, chunker: section_slide, include: [notes, captions]}
txt: {parser: text, chunker: recursive_sentence, overlap: minimal}
code: {parser: ast, chunker: symbol, repeat: [signature, class_path]}结构化正文可以从 Child 250~500 Token、Parent 800~1500 Token 建立实验基线;这不是推荐常量。表格优先按完整行和 Token 上限决定批次,可从几十行一个 Row Group 起测;Slide 优先一页一块;代码优先一个 Symbol 一块。若正确证据频繁跨块,再增加父块回填或最小 overlap,而不是直接把所有格式统一扩大。
4.5.3 如何验证格式策略选对了
按文件类型建立分桶评测,不只看平均 Recall:
- HTML/Markdown/DOCX:标题路径、条件与例外是否完整,模板噪声是否进入 TopK;
- PDF:阅读顺序、跨页句、双栏和引用页码是否正确;
- Excel:表头—行—单位—公式关系是否完整,单元格引用能否定位;
- PPT:Slide 标题、图表和 Notes 是否共同支撑答案;
- 代码:Symbol 是否完整,签名、实现和调用关系是否可定位;
- 全部格式共同检查 Child Recall@K、完整证据召回率、引用支持率、重复率、上下文 Token、解析失败率和人工可定位性。
4.6 用真实问题反推切片
假设原文是:
Pro 版用户可在订单创建后 30 分钟内撤销。企业版若已进入人工审核,不允许自助撤销,需联系管理员。
如果把“企业版”与“不允许自助撤销”切到两个块,用户问“企业版为什么撤销不了”时可能只召回第一句,最终生成错误结论。切片评测不能只看长度分布,还要用包含条件、否定、跨句指代和表格行列的问题验证。
4.7 TopK 与切片是联动参数
相同 Token 预算下,小 Chunk 可能需要更大的 k_recall 才能拼全事实,大 Chunk 则可能用较小 K,但单块噪声更高。实验时至少联合扫描:
text
chunk_size × overlap × k_recall × k_rerank × k_context并同时报告 Recall、前排排序、答案正确性、引用支持率、重复率、延迟和 Token 成本。
5. 元数据、权限与版本区分
5.1 元数据是什么
元数据(Metadata)是描述 Chunk 的结构化字段,它不是正文的替代品。典型字段包括:
json
{
"tenant_id": "t-17",
"acl_groups": ["support", "risk"],
"document_id": "policy-2026-017",
"chunk_id": "policy-2026-017#sec-4#c-02",
"parent_id": "policy-2026-017#sec-4",
"title_path": ["退款规则", "企业版"],
"product": "enterprise",
"region": "CN",
"language": "zh-CN",
"valid_from": "2026-07-01T00:00:00+08:00",
"valid_to": null,
"source_version": "v7",
"parser_version": "layout-parser-3.2",
"chunker_version": "section-parent-child-2",
"embedding_model": "example-embedding-id",
"embedding_dimension": 1024,
"index_version": "kb-cn-20260713-02"
}模型 ID 和维度仅为字段示例,必须替换为真实部署值。
5.2 硬过滤与软加权
- 硬过滤: 租户、ACL、法律区域、有效期、产品版本等不满足就不能进入候选;
- 软加权: 新鲜度、权威等级、热度、人工精选等可以影响排序,但不能突破硬边界;
- 正文信号: 标题、术语、完整语义仍参与 BM25/Dense/Cross-Encoder 相关性判断。
把 ACL 做成“排序扣分”是严重错误:低分的越权文档仍可能在候选不足时进入结果。
5.3 版本不是一个字段
RAG 至少有六类相互关联但不能混为一谈的版本:
| 版本 | 回答的问题 | 变化后通常需要什么 |
|---|---|---|
source_version | 原始知识内容是哪一版 | 重新审批、增量解析 |
parser_version | 页面如何被解析 | 对受影响文档重解析 |
chunker_version | 内容如何切片 | 重切片与评测 |
embedding_model | 向量由什么模型/维度生成 | 新索引或双写迁移 |
index_version | 查询实际命中哪个物理/逻辑索引 | 原子切别名与回滚 |
retrieval_config_version | TopK、融合、过滤和重排如何配置 | 灰度、影子流量、回放 |
不同 Embedding 模型或维度生成的向量通常不能直接放进同一相似度空间比较。迁移应采用新索引回填、双写、影子查询、评测门禁、别名切换和旧索引保留窗口,而不是原地覆盖。
6. 数据样例与最小实现
下面伪代码强调可追溯数据契约:
python
def build_chunks(document, policy):
raw_hash = sha256(document.bytes)
blocks = parse_layout(document, version=policy.parser_version)
cleaned, report = clean_blocks(blocks, rules=policy.cleaning_version)
assert report.quarantine_reasons == []
chunks = chunk_by_sections(
cleaned,
max_tokens=policy.max_tokens,
overlap=policy.overlap,
keep_tables=True,
)
return [
{
"chunk_id": stable_chunk_id(document.id, c.section_path, c.ordinal),
"text": c.text,
"metadata": {
"source_hash": raw_hash,
"title_path": c.section_path,
"tenant_id": document.tenant_id,
"acl_groups": document.acl_groups,
"source_version": document.version,
"parser_version": policy.parser_version,
"chunker_version": policy.chunker_version,
},
}
for c in chunks
]stable_chunk_id 应尽量基于文档身份与结构位置,而不是仅用数组下标;否则前面插入一段内容就会让后续所有 ID 漂移,失败样本、引用与增量更新难以对齐。
7. 技术点清单与横向选型
边界| 数据清洗、切片和版本治理是框架无关的工程机制;下表的工具类别是参考实现,不构成唯一方案。
| 技术点 ID | 技术点/环节 | 类型 | 采用方案 | 链路职责 | 版本/证据边界 |
|---|---|---|---|---|---|
| TP-D01 | 文档解析与清洗 | 数据管道 | 格式路由 + 版面感知解析 + 质量报告 + 隔离队列 | 从 HTML、PDF、Office、表格和代码等原文件产出可审计结构块 | 需按来源格式、原生/扫描和结构复杂度分桶实测 |
| TP-D02 | 切片 | 算法/数据结构 | 格式原子单元 + 结构感知 + 父子 Chunk | 小块检索、父块补上下文,并保护表格行列、代码 Symbol 等关系 | Chunk 参数无通用最优值;解析失败时结构策略也会失败 |
| TP-D03 | 元数据与 ACL | Schema/安全 | 服务端可信字段 + 检索前硬过滤 | 限定可见范围和有效版本 | 必须以越权测试验证 |
| TP-D04 | 版本与血缘 | 数据治理 | 多维版本矩阵 + 稳定 ID + 索引别名 | 重放、灰度、迁移与回滚 | 示例 Schema,非真实部署证据 |
| 技术点 ID | 候选方案 | 优点 | 缺点/代价 | 适用场景 | 不适用场景 | 选择结论与依据 |
|---|---|---|---|---|---|---|
| TP-D01 | 纯文本抽取 | 成本低、吞吐高 | 丢布局、表格和图文关系 | 简单 HTML/TXT | 扫描 PDF、复杂表格 | 作为简单来源基线 |
| TP-D01 | 版面/OCR 解析 | 保留页面结构与坐标 | 计算和人工复核成本高 | PDF、扫描件、合同 | 纯文本小文档 | 按来源路由,不全量重型解析 |
| TP-D02 | 固定 Token | 易实现和复现 | 容易切断语义 | 快速基线、弱结构文本 | 条款、表格、代码 | 先建立基线,再用失败集决定升级 |
| TP-D02 | 结构感知父子切片 | 兼顾召回粒度和语境 | 实现、存储、去重更复杂 | 长文、手册、制度 | 极短 FAQ | 条件/例外跨句时优先 |
| TP-D03 | 检索后过滤 | 接入简单 | 可能漏光候选并暴露越权面 | 仅非敏感软属性实验 | 多租户、敏感数据 | 不用于 ACL |
| TP-D03 | 检索前硬过滤 | 安全边界明确,候选即受权 | 索引和过滤设计更复杂 | 多租户、版本化知识 | 无可信过滤字段 | 生产默认方案 |
| TP-D04 | 原地覆盖索引 | 操作看似简单 | 难回滚、混版本、不可审计 | 一次性实验 | 生产迁移 | 不推荐 |
| TP-D04 | 新索引双写与别名切换 | 可影子验证和快速回滚 | 双份存储与迁移成本 | 模型/维度/切片升级 | 资源极紧且无生产要求 | 生产优先 |
8. 架构与调用流程
图:架构|RAG 数据接入、治理与版本化索引
替代文本: 原始文件进入不可变对象存储,经格式路由、解析清洗、质量门禁、结构切片和元数据权限装配后生成 Embedding,并写入带版本别名的索引;血缘仓保存每个产物与版本关系,隔离队列承接失败文档。
图表加载中…
读图结论: 可上线的数据链路必须同时产出“可检索内容”和“可审计证据”;质量失败应隔离,版本变化应形成新产物而不是静默覆盖。
图:技术调用流程|一次文档发布的成功、隔离与回滚分支
替代文本: 发布服务登记原件后调用解析、清洗和切片;低质量内容进入隔离队列,通过内容生成向量并双写候选索引,离线评测通过才切换别名,失败则保留旧索引并记录版本证据。
图表加载中…
读图结论: 文档写入成功不等于发布成功;只有数据质量、检索评测和权限回归都通过,候选索引才能成为线上版本。
9. 生产风险、监控与验证
| 现象 | 首查证据 | 可能根因 | 止损 | 长期修复与防复发 |
|---|---|---|---|---|
| 新文档搜不到 | source_hash、发布状态、索引版本、写入时间 | 隔离未处理、增量任务失败、查询仍指旧别名 | 回退明确状态,必要时查旧版 | 新鲜度 SLO、写入对账、别名切换告警 |
| 回答引用旧制度 | source_version、有效期过滤、候选快照 | 新旧版本并存且无硬过滤 | 强制指定有效版本 | 版本互斥校验、时间旅行用例 |
| TopK 全是重复段 | parent_id、内容指纹、重复 Token 比 | overlap 过大、页眉未清洗 | final_context 去重 | 数据侧去重、Chunk 策略回归 |
| 表格金额答错 | 页面坐标、表格行列、OCR 置信度 | 解析错列或表头与数据分离 | 返回原页或人工确认 | 表格专用解析、行列一致性测试 |
| 撤权后仍命中 | ACL 版本、缓存键、过滤表达式 | 缓存未绑定权限或索引未更新 | 禁用相关缓存、强制二次授权 | 撤权传播 SLO、越权自动测试 |
数据层至少监控:接入成功率、隔离率、解析耗时、OCR 低置信比、重复块率、Chunk Token 分布、元数据缺失率、Embedding 失败率、索引新鲜度、版本混用率、撤权传播延迟和孤儿 Chunk 数。
10. 面试追问与总结
10.1 递进追问
- 为什么 Chunk 不是越小越好,overlap 不是越大越好?
- 表格、代码、FAQ 和长制度文档应采用相同切片策略吗?
- 为什么 ACL 必须在候选召回前生效?
- Embedding 模型升级时为什么通常要建新索引?
- 如何证明回答问题是切片问题,而不是 Reranker 或 Prompt 问题?
10.2 一分钟面试复述版
我会把 RAG 数据层拆成清洗、切片、元数据权限和版本血缘四部分。清洗不是删空格,而是保留原件、恢复布局、隔离低质量内容并产出质量报告;切片先按格式路由:HTML/Markdown/Word 保留标题层级,PDF 恢复版面与阅读顺序,Excel 按表格区域和行组并重复表头,代码按 AST Symbol,再用 Token 上限处理超长元素。切片策略要联合真实问题、父子结构、重复率和 Token 预算评测;租户、ACL、有效期和版本属于硬过滤。模型或切片策略升级时,我会新建索引、双写和影子评测,通过后切别名,并保留旧版回滚。线上如果答错,我先用
source_hash、chunk_id和版本矩阵证明正确证据在哪一层丢失,而不是直接调 TopK。
10.3 参考资料
以下官方资料访问日期为 2026-08-20;它们证明结构元素、标题边界、表格表头重复和 PDF 坐标提取等实现能力,具体产品选择仍需按本项目文件分布、解析质量、成本和合规实测:
- Unstructured, Chunking:先 Partition 为语义元素,仅对超长元素做文本拆分;
by_title保留章节边界,并说明全局 overlap 可能污染正常结构块; - Docling, Chunking:层级 Chunk 上叠加 Token 上限、合并同标题短块,支持跨块重复表头和保留完整行;
- PyMuPDF, Text extraction recipes:PDF 可按带坐标的 Block/Word 提取,用于恢复阅读顺序、页面区域和引用位置。
简明总结
一句话记忆: RAG 的第一场排序发生在数据进入索引之前——先决定什么可信、怎样切、谁能看、属于哪个版本。
- 数据清洗必须保留原件、差异、质量报告与失败隔离;
- 切片要先按格式恢复结构:正文按标题,PDF 按版面,Excel 按表格行列,代码按 Symbol;overlap 只补真实跨边界关系,并联合检索、排序、生成、重复率和 Token 成本验证;
- 元数据承载结构化过滤,ACL、租户和有效期必须是硬边界;
- 版本要拆成来源、解析、切片、Embedding、索引和检索配置;
- 新索引双写、固定集回放、别名切换和回滚共同构成发布闭环。