我刚觉得自己把场子找回来一点,他就指着我刚才说的 Chunk 继续问:
我第一反应是,块越小,语义越集中,相似度当然更容易算准。
老周没反驳,只给我看了一段员工休假制度。第一块只有“适用对象”,第二块是申请条件,第三块才写“不适用于试用期员工”。
“员工问自己能不能休假,你只召回其中一块,准备怎么答?”
这一下我明白了:切片不是把文档切开就结束,而是要保证每一块仍然能够独立表达一个完整事实。
老周问我:“PDF 不是一段纯文本。标题、页眉、表格、跨页条款,你准备怎么切?”
我说,切片的输入不应该是粗暴抽出来的一长串字符,而应该是文档解析后的结构。扫描件先做 OCR,普通文档要识别标题层级、段落、列表和页码;表格不仅要保留单元格,还要把表头和数据行的关系带下来。
否则原文还没进入向量库,表头已经和数据分家,跨页条款已经断了。后面再换多强的 Embedding,也只是给错误的文本算出一个很精确的向量。
我以前也喜欢先定一个数字:每 500 字切一块,再重叠 50 字。简单、好实现,Demo 里通常也能跑。
但生产里没有万能长度。切得太小,条件、结论和例外会被拆散;切得太大,一个块塞进三个主题,检索噪音和上下文成本一起上升。Overlap 能缓解边界问题,却不能修复错误的文档结构。
更稳的做法,是先按标题、条款、段落和表格边界切出语义单元,再根据模型上下文和检索效果限制最大长度。制度文档保留“章—节—条”,FAQ 不拆散问题和答案,接口文档不把参数说明与示例分开。
老周又追问:“小块容易命中,大块上下文完整,这两个目标冲突怎么办?”
我会用父子块。索引里存更细的子块,让它负责精准召回;命中后根据 parent_id 回到所属章节,补上标题、前后条款或完整表格,再把扩展后的证据交给大模型。
每个块还要带上来源、章节路径、版本、生效时间、适用范围和权限。它们不是最后展示引用时才补的装饰,而是后面做过滤、冲突判断和追溯的基础。
所以真正的顺序应该是:先解析结构,再生成语义块,补齐父子关系与元数据,最后才做 Embedding 和入库。
“文档不是切得越细越准。切片前要先把 PDF、Word 和表格解析成正确结构,再按标题、条款、段落等语义边界切分。块太小会丢条件和例外,太大会引入噪音,不存在通用长度。生产中我会让子块负责召回、父块负责补上下文,并给每个块带上章节、版本、时效、适用范围和权限元数据。最后用跨边界、表格和长条款问题做评测,依据命中率和答案完整性调参数,而不是凭感觉写死 500 字。”
老周点了点头,又从文档里复制出一条编号很长的制度条款。
“好,文档总算没被你切坏。但用户直接问条款编号,向量相似度最高的却是另一份语义相近的制度。相似度都 0.9 了,为什么还是找错?”
下一篇,我们继续拆检索:关键词、向量、混合召回和重排,到底各自解决什么问题。
✍️ 我是阿锦
我会持续分享 AI 工具和 AI coding 的实操——不讲空话,用实践带你看更真实的东西。
觉得有用,点个赞、转给也在折腾 AI 的朋友,就是最大的支持。想看啥?评论区告诉我——下一篇,就是为你而探索。
想常来一起聊 AI,点下左下角 关注,回复 交流 就行。