AI Agent 开发 09|先把资料读对,再讨论每块切多大
PDF 里一张价格表被读成连续文字,版本名与价格之间的关系就可能丢掉。后面即使检索到这一段,也很难可靠判断某个价格属于哪个版本。
做知识库时,先打开 Loader 的实际输出。确认资料读得完整,再往下编码,能更早发现问题。
统一文档要保留哪些东西
原教程用 Document 组织正文和元数据。正文参与后续文本处理,元数据帮助定位来源、过滤和引用。
// 自定义文档示意
const document = {
pageContent: "项目使用 pnpm 管理依赖。",
metadata: {
docId: "development-guide",
source: "docs/development.md",
section: "开发环境",
version: "v3",
},
};标题放进 metadata,不代表它会自动参与 embedding。如果希望标题影响语义检索,需要明确把标题加入编码文本,同时保留来源字段。
逻辑文档 ID 用来更新和删除,片段 ID 用来去重和引用。权限字段则应来自服务端可信记录。上传文件可以带自定义 frontmatter,却不应该自行决定所属租户。
不同格式会丢掉不同的信息
Markdown 可以分开 frontmatter 和正文,再选择需要的字段写入 metadata。字段要校验,避免任意内容覆盖可信来源。
FAQ 最好把问题和答案放在一起。答案只有“最多十人”,离开问题以后很难知道限制对象。加入原问题,可以同时保留检索措辞和回答条件。
PDF 要检查多栏顺序和表格关系。扫描件没有可提取文本层时,需要 OCR。表格可以保留为 Markdown,或者逐行整理成包含列名的句子。只看解析器有没有抛错,还无法知道这些关系是否留下。
网页则需要检查正文区域。只取段落的选择器可能漏掉标题、代码、列表和表格。动态生成的内容还要确认是否存在于取得的 HTML 中。SaaS 文档同步需要继续处理分页、权限、更新和删除。
每种来源先抽一份人工比较。原文中的关键字段、条件和章节都能在输出中找到,再继续下一步。
分块要让一段内容能够被理解
块太大,一个向量混进许多主题,检索粒度变粗。块太小,条件和结论容易散开。合适大小与资料类型和真实问题有关。
中文资料可以从段落和句末标点开始尝试递归切分。递归分块器先按较粗边界拆开,对过长内容继续细分,再把能放在一起的片段合并。
因此 chunkSize 通常表示长度目标或限制,具体输出未必每块等长。容量为一百时,两段合起来七十五,下一段放不下,就可能停在七十五。
只有一个分隔符的切法,遇到没有该分隔符的长文本时还可能产生超长块。要打印最终结果,检查边界与长度,不能只看配置名称。
overlap 要看最终留下了什么
chunkOverlap 希望让相邻块共享部分内容。某些合并实现会保留完整尾部片段。如果最小尾部片段已经大于重叠目标,它就可能无法留下。
这解释了为什么设了非零 overlap,实际两块仍可能没有重复文字。原教程专门分析了这种合并行为。最终效果取决于分隔符、片段长度与实现版本。
重复太多也有成本。同一段内容被多个块召回,会占用上下文,还可能让结果看起来很多、独立证据却很少。调参时应该同时观察重复率。
长度单位别混在一起
字符长度与 token 数量没有固定换算关系。中文、英文、代码和数字在不同 tokenizer 下会有不同切法。
按 token 切分更便于控制模型容量,边界仍可能落在句子中间。也可以给递归切分器使用合适的 token 计数函数,再复核最终片段。
完整请求还要装系统规则、问题、消息历史、工具定义,并为输出留空间。片段没有超限,不能证明整次请求一定装得下。
Markdown 可以保留章节路径,代码可以在函数附近分开,表格则要重复必要列名。用小片段检索后返回较大的父章节,也是一种选择,但需要维护映射、去重和总长度。
先拿三组候选块大小在同一批问题上比较。查看正确证据是否被召回,条件是否完整,再看回答质量与输入量。只有发现切分边界确实影响结果时,再增加更复杂的策略。
延伸阅读
本篇依据冴羽《AI Agent 开发实战》学习整理稿中的 Document、加载与递归分块分析重写。原教程见 Loader 与 Splitter 入门、文档加载的影响 和 分块器详解。