文档切分策略
1. 定义与边界
文档切分(Chunking)是把原始文档解析、清洗并拆成适合检索和生成的片段。切分质量直接决定 RAG 的召回、引用和忠实度。
切分不是按固定 token 数机械截断。生产系统要保留文档结构、标题层级、表格、代码块、页码、权限和版本信息。
2. 为什么重要
切分错误会导致:
- 答案证据跨 chunk,检索不到完整上下文。
- chunk 太大,召回粗糙且成本高。
- chunk 太小,丢失标题和约束。
- 表格、脚注、代码被破坏。
- 引用无法定位原文。
3. 核心机制
4. 切分策略
| 策略 | 适用场景 | 注意事项 |
|---|---|---|
| 固定长度 + overlap | 简单文本、第一版原型 | 容易切断语义 |
| 递归字符切分 | 普通 Markdown/HTML | 保留段落边界 |
| 标题层级切分 | 手册、规范、长文档 | metadata 要带父标题 |
| 语义切分 | 主题变化明显的文档 | 成本较高,需评测 |
| 表格/代码专用切分 | 表格、代码、配置 | 不破坏行列和函数边界 |
| Parent-child chunk | 小 chunk 检索,大 chunk 注入 | 需要 fetch 原文窗口 |
5. 工程实现
{
"chunk_id": "doc123#section-4.2#p3",
"document_id": "doc123",
"text": "本段正文...",
"metadata": {
"title": "API 权限",
"section_path": ["安全", "API 权限"],
"page": 12,
"source_uri": "s3://kb/doc123.pdf",
"document_version": "2026-05-01",
"acl": ["engineering"],
"content_hash": "sha256:..."
}
}
切分流程:
def chunk_document(file):
parsed = parse_with_layout(file)
blocks = normalize_blocks(parsed)
chunks = structure_aware_split(blocks, max_tokens=500, overlap=80)
for chunk in chunks:
chunk.metadata.update(source_metadata(file, parsed))
return chunks
6. 生产实践
- Markdown/HTML 优先按标题、段落、列表切分。
- PDF 要保留页码和布局,表格单独解析。
- 代码按文件、类、函数、注释块切分,并保留行号。
- 用 overlap 解决边界问题,但不要用过大 overlap 制造重复。
- 保存 parent 文档和 child chunk 的关系,便于 Search-Fetch。
- 对每次索引记录 parser version 和 chunker version。
7. 常见反模式
- 所有文档统一 500 token 截断。
- 丢弃标题、页码、URL、版本和权限 metadata。
- 表格转纯文本后行列错位。
- overlap 太大导致重复 chunk 占满 top-k。
- 文档更新后 chunk ID 改变,引用和评测集失效。
8. 评测方法
- gold answer 所需证据是否落在可检索 chunk 中。
- chunk 完整性:是否保留标题、否定条件、表格行列。
- 重复率。
- 平均 chunk token 和 p95 token。
- chunk 边界 bad case 人工抽检。
- 切分策略 A/B 对 recall@k 和回答忠实度的影响。
9. 安全与治理
- 权限 metadata 必须来自源系统,不靠模型推断。
- 文档隐藏文本、注释、修订记录要按业务策略处理。
- 切分后每个 chunk 继承源文档敏感等级。
- 删除文档时按
document_id删除全部 chunk 和索引。
工程化补强:架构与实现细节
A. 与 Memory 的硬边界
文档切分策略处理的核心对象是把原始文档切成适合检索、重排、引用和上下文组装的 chunk。它的目标是把外部知识转化为可验证证据,而不是保存用户偏好或 Agent 经验。 Memory 可以影响“怎么服务这个用户、这个项目、这个流程”;RAG 只能回答“证据中是否支持这个事实”。
| 维度 | RAG | Memory |
|---|---|---|
| 数据来源 | 外部文档、网页、代码、数据库、知识库 | 对话、任务轨迹、用户偏好、历史经验 |
| 写入方式 | ingestion pipeline、同步任务、管理员上传 | 互动后抽取、用户确认、后台总结 |
| 核心约束 | 证据可追溯、权限过滤、引用准确 | 状态延续、偏好复用、隐私最小化 |
| 典型失败 | 召回错证据、引用不支持、上下文污染 | 错误记忆持久化、越权画像、投毒 |
| 评测指标 | chunk recall、boundary error rate、citation granularity、token waste | memory precision、task lift、staleness |
B. 端到端 Pipeline
本主题在总链路中的重点可以概括为:parse -> clean -> structure detect -> split -> overlap -> metadata -> quality check。
C. 索引数据结构
{
"chunk_id": "doc_2026_05_09#sec_04#chunk_003",
"document_id": "doc_2026_05_09",
"document_version": "v7",
"source_uri": "s3://kb/product/manual.pdf",
"source_type": "pdf|html|code|ticket|database",
"title": "支付失败排查手册",
"section_path": ["支付", "错误码", "超时"],
"text": "...可用于回答的原文片段...",
"span": {"page": 12, "start_char": 1840, "end_char": 2610},
"metadata": {
"tenant_id": "org_1",
"acl": ["support", "engineering"],
"created_at": "2026-05-01",
"updated_at": "2026-05-09",
"source_trust": "official_internal"
},
"retrieval": {
"dense_vector_id": "vec_abc",
"sparse_vector_id": "sparse_abc",
"graph_node_ids": ["entity:timeout", "claim:retry-policy"]
},
"splitter": "heading_aware_sentence",
"parent_chunk_id": "doc7#sec3",
"lineage": {
"parser_version": "parser-2.1",
"chunker_version": "heading-aware-1.4",
"embedding_version": "emb-2026-05-09",
"checksum": "sha256:..."
}
}
没有 document_version、span、acl 和 lineage 的 RAG 索引,很难做引用、回滚、权限审计和 bad case 修复。
D. Indexing Pipeline 设计要点
| 阶段 | 关键决策 | 常见坑 |
|---|---|---|
| 连接器 | 增量同步、删除同步、权限同步 | 只追加不删除,导致旧知识继续被召回 |
| 解析 | PDF 表格、代码块、标题层级、脚注 | 丢页码和结构,引用无法定位 |
| 切分 | chunk 大小、overlap、父子块、表格整体性 | 切断条款、代码函数或表格行 |
| 元数据 | tenant、ACL、时间、版本、来源可信度 | 检索后才做权限过滤,已经泄露给模型 |
| 向量化 | embedding 模型、维度、批量、缓存 | 模型切换后混用旧向量 |
| 索引 | vector、BM25/sparse、graph、rerank cache | 不记录索引版本,无法回归评测 |
| 回收 | 删除、过期、重建、压缩 | 向量残留和缓存残留 |
本文件建议的索引原则是:chunk_id 必须稳定,记录 section_path、page、span、parent_doc 和 splitter_version。
D.1 LlamaIndex RAG 阶段核对
LlamaIndex 官方 RAG 入门把 RAG 拆成数据加载、准备/索引、查询检索、上下文送入 LLM、生成响应等阶段;其 ingestion 文档也把加载、转换、索引/存储作为核心流程。这说明切分策略不是孤立函数,而是 indexing pipeline 的中间层。
| LlamaIndex 阶段 | 本文件对应设计 |
|---|---|
| Load data | 连接器要保留来源 URI、版本、权限和原始结构 |
| Transform data | 清洗、标题识别、表格/代码保护、chunking |
| Index and store | embedding、BM25/sparse、vector store、metadata |
| Query | 根据 query 类型选择小块、父块扩展或原文 fetch |
| Response synthesis | 引用粒度和上下文完整度决定生成质量 |
因此评测切分策略时,不能只看 chunk 平均长度;要看 gold span 是否能被召回、引用是否能定位、答案是否因为边界错误而缺证据。
E. 查询期策略
不同任务选择不同粒度:事实问答用小块,综述和表格用 parent expansion。查询期不要把“召回更多”当成唯一目标,而要控制证据质量、权限、时效和上下文预算。
def rag_query(user_query, user_ctx):
plan = plan_retrieval(user_query, user_ctx)
filters = enforce_acl(user_ctx, plan.filters)
rewritten = rewrite_query(user_query, plan, metadata_schema=INDEX_SCHEMA)
candidates = []
for source in plan.sources:
candidates.extend(source.search(rewritten, filters=filters, k=plan.candidate_k))
ranked = rerank(user_query, candidates, features=["text", "metadata", "trust", "freshness"])
evidence = pack_context(ranked, budget=plan.context_budget, diversity=True)
answer = generate_with_evidence(user_query, evidence)
return verify_citations(answer, evidence)
F. 引用与证据策略
引用粒度通常以 chunk/span 为准,必要时 fetch 上下文窗口。引用不是格式问题,而是 evidence contract:模型只能用传入证据支持关键断言。
| 断言类型 | 证据要求 | 不满足时动作 |
|---|---|---|
| 简单事实 | 至少一个直接 chunk 支持 | 给出不确定或拒答 |
| 跨文档综合 | 多个 chunk 覆盖关键维度 | 明确证据范围和缺口 |
| 高风险建议 | 官方/内部可信来源优先 | 要求人审或给出保守答案 |
| 时间敏感信息 | 来源版本和更新时间足够新 | 触发刷新或说明可能过期 |
| 权限受限内容 | 用户有权查看原文 | 不引用、不泄露摘要 |
G. 失败模式与修复
| 失败模式 | 早期信号 | 修复动作 |
|---|---|---|
| 切断表格/代码/法规条款上下文,或 chunk 过大导致召回不准 | 答案流畅但找不到支持片段 | 加 citation verifier 和无证据拒答 |
| chunk 边界错误 | 命中片段缺上文或表格列 | 调整切分器、加入 parent expansion |
| 召回偏科 | 概念问答好,错误码/ID 查询差 | 增加 hybrid search 和字段 boost |
| top-k 污染 | 上下文里半数以上无关 | rerank、diversity filter、query rewrite |
| 权限绕过 | 无权限文档出现在 trace | 服务端 ACL 前置过滤,索引按租户隔离 |
| 索引陈旧 | 用户指出文档已更新 | 增量同步、版本水位、freshness 监控 |
| 引用漂移 | 引用存在但不支持断言 | claim-level citation check 和回源校验 |
H. 评测指标
| 层级 | 指标 | 说明 |
|---|---|---|
| 检索 | recall@k、precision@k、nDCG、MRR | gold span/doc 是否进入候选和前排 |
| 重排 | rerank lift、first relevant rank | 观察 reranker 是否真正改善上下文 |
| 上下文 | evidence coverage、token waste、duplication rate | 是否既覆盖证据又不浪费窗口 |
| 生成 | answer correctness、faithfulness、abstention accuracy | 答案是否正确且不编造 |
| 引用 | citation precision、claim support rate、broken link rate | 引用是否可打开且支持断言 |
| 安全 | prompt injection success、unauthorized recall、sensitive leakage | 外部内容和权限场景的红线 |
| 运维 | p95 latency、index freshness、cost/query、cache hit rate | 生产可用性和成本 |
I. 安全治理清单
- 检索内容是数据,不是指令;提示词中明确外部证据不能覆盖系统和开发者约束。
- 权限过滤必须在检索前或索引层完成,不能依赖模型“不要使用”。
- 对网页、用户上传文件和第三方文档做 prompt injection 扫描和来源可信度标记。
- 高风险领域使用白名单来源、版本锁定、引用校验和无法支持时拒答。
- 记录 query、filters、命中文档、分数、rerank 理由、上下文包和最终引用,支持审计。
- 建立 bad case 回流:每个失败样本标注失败层级,并绑定索引版本、prompt 版本和模型版本。
10. 权威资料
- LangChain text splitters: https://docs.langchain.com/oss/python/integrations/splitters (核对日期:2026-05-09)
- LlamaIndex node parsers: https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/ (核对日期:2026-05-09)
- OpenAI File Search tool: https://platform.openai.com/docs/guides/tools-file-search (核对日期:2026-05-09)
- Azure AI Search indexing: https://learn.microsoft.com/en-us/azure/search/search-what-is-an-index (核对日期:2026-05-09)