Appearance
文档怎样变成可检索索引:Chunking、Embedding 与 Vector Store
前置:RAG 从哪里开始:Retrieval 边界、架构模式与 Ingestion
核心问题:为什么 chunk boundary 会直接决定召回上限,代码符号、标题层级和自然段分别应该怎样切?
API 文档按 heading/function 切比固定每 500 字切更合理,因为函数签名与参数说明必须保持在同一 chunk。查询错误码 GS-00601 时 lexical/BM25 可能优于纯 embedding;查“数据库连接超时怎么处理”时 semantic embedding 更有优势。
Mental Model
RAG 的错误应先定位在哪一层发生:source/index、query rewrite、retrieval、filter、rerank、grounding 还是 generation,而不是把所有失败都叫“幻觉”。
Chunking
Chunking 决定 Retriever 能命中的最小语义单元。块太小会把必要上下文拆散,太大又降低定位精度并浪费后续 Context token;因此应先尊重 heading、段落、函数、代码块和表格等结构边界,再用 size/overlap 调整。固定“每 N 字一块”只能作为 baseline,最终参数应由真实 query 的 retrieval eval 决定。
一个 Chunk Boundary 为什么会直接影响召回
假设文档里有:
text
### Token Refresh
refresh_token 失效时返回 401。
客户端必须重新登录,不应该无限重试 refresh。如果固定字符切分恰好把标题和“返回 401”拆到两个 chunk,用户搜索“token refresh 401”时,两个片段的语义都可能变弱。按 heading/段落保留完整单元,再在过长时做 secondary split,通常比纯字符切分更稳。
Embeddings
Embedding 把 chunk/query 映射到向量空间,适合语义近邻;对精确符号、编号和稀有 token 不一定可靠,所以常与 lexical retrieval 组合。Embedding model 本身也是索引版本的一部分,升级后不能默认与旧向量继续混排。
Vector Store
Vector Store 保存向量、chunk metadata 并执行近邻查询;原始文档和 provenance 仍由独立 source/version 体系管理。工程上真正要关心的是 namespace/ACL filter、增量更新与删除、索引版本和重建,而不是把“有向量库”直接等同于“已经有 RAG”。
Failure Modes
Chunk 切分破坏语义边界
症状: 按固定字符数把标题、代码块、表格或同一论证拆散。
为什么危险: Embedding/Retrieval 命中后缺少必要上下文,相关 chunk 也无法独立支撑答案。
处理: 按文档结构/语义边界切分,必要时保留 parent/overlap metadata,并通过 retrieval eval 调参。
Embedding/Index 版本变化但旧向量继续混用
症状: 更换 embedding model 或 chunk policy 后向同一 index 直接追加新向量。
为什么危险: 相似度空间不可比较,结果质量随机下降且难定位版本问题。
处理: Index 与 embedding/chunk/source version 绑定;变更时重建或显式多版本隔离。
如何验证
| Case | 断言 |
|---|---|
| Chunk 切分破坏语义边界 | 建立带答案证据的 query set,比较不同 chunk policy 的 recall@K 与 end-to-end grounding。 |
| Embedding/Index 版本变化但旧向量继续混用 | 同时写入两种 embedding version,断言查询不会跨不兼容 index 混排。 |
自测
- 函数定义和实现被切到两个 chunk 后,为什么即使 embedding 模型没变,Recall@K 也可能明显下降?
- 代码符号、Markdown 标题层级、普通自然段的 chunk boundary 能否用同一规则?你会怎样做一组对照评测?