Day 013|Chunking 策略:为什么知识库效果差,锅经常在切分
系列:100 天系统学习 AI Agent 开发
当前阶段:RAG、知识库与工具边界
今日目标:切分大小、重叠长度、标题保留和层级结构都会影响 RAG 的召回质量。
有时不是没搜到,而是答案被切成了两半
一份部署文档里,“执行命令”在上一段,“环境变量说明”在下一段。如果按固定字数正好从中间切开,检索可能只拿到命令,却漏掉执行前提。片段再相似,也无法补回被边界割断的关系。
Chunking 看起来像预处理细节,实际上决定检索系统最小能找到什么。块太小,语义不完整;块太大,相关句子被大量噪声包围,还会挤占上下文。没有一个适合所有资料的神奇数字。
四个互相牵制的变量
| 变量 | 太小/缺失的后果 | 太大/过多的后果 |
|---|---|---|
| chunk 大小 | 语义断裂、缺上下文 | 噪声多、定位不准、成本高 |
| overlap | 跨边界信息丢失 | 重复召回、索引膨胀 |
| 标题路径 | 代词和短段失去主题 | 每块重复过多导航文字 |
| 结构层级 | 表格、代码、步骤被拆散 | 整章作为一块难以命中细节 |
Overlap 不是越大越稳。相邻三块都包含同一段话时,Top 3 看似命中了三条,实际只有一份信息,模型得到的证据多样性反而下降。
三种策略,必须控制变量比较
今天的练习是把同一篇技术文档做三份索引:
- 固定约 300 字,保留少量重叠;
- 固定约 800 字,保留少量重叠;
- 按标题和语义结构切分,代码块与紧邻解释尽量不分开。
为了让比较有意义,Embedding 模型、查询集、Top K、metadata 过滤和生成 Prompt 都应保持一致。否则结果变化不能归因于切分。
| 查询 | 期望证据 | 300 字 | 800 字 | 标题层级 | 观察项 |
|---|---|---|---|---|---|
| 安装前置依赖是什么 | “环境准备”列表 | 待运行 | 待运行 | 待运行 | 是否完整命中列表 |
| 超时后能否重试 | 错误策略 + 幂等说明 | 待运行 | 待运行 | 待运行 | 关系是否跨块 |
| 某函数参数含义 | 参数表对应行 | 待运行 | 待运行 | 待运行 | 表格有没有被破坏 |
这里没有伪造优胜策略。我的预期是结构化切分通常更自然,但遇到标题很差、正文结构混乱的文档,它也可能不如固定窗口稳定。
一个保守的标题切分草案
from dataclasses import dataclass
@dataclass
class Chunk:
chunk_id: str
heading_path: list[str]
text: str
source: str
def enrich_text(chunk: Chunk) -> str:
heading = " > ".join(chunk.heading_path)
return f"标题路径:{heading}\n正文:{chunk.text.strip()}"
这段代码只演示“标题路径与正文一起进入检索文本”。真正的解析器还要处理 Markdown 表格、围栏代码、列表、图片说明和超长章节。尤其不应在代码块中间按字符硬切,那会留下无法理解、也无法运行的残片。
如果不得不用固定窗口,也应先按句子或段落寻找安全边界:
优先边界:标题 > 段落 > 句子 > 字符兜底
禁止边界:代码围栏内部、表格行中间、步骤标题与其内容之间
常见失败模式
- 只看平均块长。 平均 500 字可能掩盖少数 5000 字的超长块。
- 用同一策略处理所有格式。 FAQ、API 参考、叙述文章、表格需要不同规则。
- 只评最终回答。 模型可能用常识碰巧答对,掩盖切分没命中。
- chunk_id 不稳定。 每次重建都随机编号,历史评测和引用无法对齐。
- 先切再丢标题。 “它支持三种方式”被检索出来,却不知道“它”指什么。
我现在的取舍
切分不是越精细越专业,而是要让一个片段足够独立地支持一条结论,同时还能准确被问题召回。这个尺度只能用自己的文档和问题集校准。下一篇做 metadata 后,还能把版本、权限和主题作为硬条件,减少仅靠语义相似承担的压力。
面试官会追问:Chunk 设成 512 还是 1024?
这不是常数题。Chunk 应围绕“一个检索结果能否独立支撑答案”设计。FAQ 可以一问一答一块,API 文档要保留标题、参数表与示例,合同则不能把定义和适用条款切开。
我会做一个小实验:固定 30 个问题,分别测试固定长度、按标题层级、语义切分三种方案,记录 Recall@5、平均 chunk 长度、上下文 Token 与引用完整率。若召回正确但引用缺前提,说明切得太碎;若每次都召回整页却答案漂移,说明切得太粗。
加分点不是报出一个“最佳长度”,而是讲清楚标题继承、父子块检索、邻块扩展和版本元数据怎样共同减少语义断裂。
今日检查清单
- 三种切分策略使用同一问题集和检索参数
- 标题、代码、表格和列表没有被无意义切断
- 同时记录命中、证据完整度和重复召回
- chunk_id 可稳定追溯到源文档位置
- 结论写成“本数据集上的观察”,不包装成通用定律
更多推荐

所有评论(0)