学习笔记 · Obsidian
文本切分策略与多语言边界
结论
- 通用文本优先
RecursiveCharacterTextSplitter;字符切分适合结构简单的文本,token 切分用于严格控制模型上下文,代码切分应使用语言感知 separators。 chunkSize、chunkOverlap、分隔符、tokenizer 和预处理规则共同构成索引契约。任一项改变都可能需要重建索引和重新评估召回。/splitters与/splitters/index是同正文别名;本组保留两条 source,共覆盖 6 条路由。
四类策略
| 策略 | 衡量单位 | 优势 | 风险 |
|---|---|---|---|
| Recursive character | 字符,按分隔符层级递归 | 尽量保留段落、句子、词 | 字符数不等于 token 数 |
| Character | 指定字符序列,默认双换行 | 简单、可预测 | 结构弱时容易产生语义断裂 |
| Token | 目标 tokenizer | 更贴近模型 context limit | tokenizer 不匹配会估算错误;切片可能破坏自然边界 |
| Language-aware code | 语言预置 separators | 尽量保留类、函数与语法结构 | 不是 AST parser,超长函数仍会被切开 |
RecursiveCharacterTextSplitter
默认分隔符顺序为 ['\n\n', '\n', ' ', ''],从段落逐步退化到句/词/字符,直到满足 chunk size。chunkOverlap 用重复上下文缓冲边界信息,但过大会增加索引量、embedding 成本和重复召回。
.splitText()返回字符串。.createDocuments()生成 Document 并保留传入 metadata。chunkSize的实际含义由lengthFunction决定,不要在字符配置和 token 配置之间直接复用数值。
中文、日文、泰文
默认空格分隔会切断没有显式词边界的语言。官方建议把这些符号加入 separators:
- ASCII/全角/表意句号:
.、.、。; - ASCII/全角/表意逗号:
,、,、、; - 泰语、缅甸语、高棉语和部分日文内容中的 zero-width space。
中文生产语料应额外验证标题、列表、表格、代码块和中英混排;只加入标点仍不等于真正的语义分句。
TokenTextSplitter
Token 分割必须选择与目标模型一致的 tokenizer。文档以 js-tiktoken 与 cl100k_base 为例,并提醒最终 split 仍可能大于期望 token chunk size。实际系统需留出 prompt、引用、工具 schema 和回答的预算,而不是把模型最大上下文全部给检索片段。
推荐预算:
可用于检索的 token = context limit - system/history - tool schema - output reserve - safety margin
代码切分
RecursiveCharacterTextSplitter.fromLanguage() 内置 Python、JS、TS、Markdown、LaTeX、HTML、Solidity、C#、Haskell、PHP、PowerShell、VB6 等 separators。它基于文本规则,不理解符号引用和 AST:
- 对代码检索同时保存 repo、path、language、symbol、line range、commit;
- 对生成代码、minified bundle、notebook 和超长函数建立单独策略;
- 若需要准确类/函数边界,先用 parser/AST 提取,再用 splitter 处理超长节点。
评估与版本化
- 建立真实查询集,比较 recall@k、MRR/nDCG、重复率、无答案率和最终回答正确率。
- 观察 chunk 长度分布与极端值,而不只看平均值。
- metadata 中保存 parent document id 与 chunk ordinal,支持邻接扩展和引用回原文。
- splitter 配置生成版本哈希;改变配置时写入新索引,验证后切流量。
- embedding batch 失败可从 chunk checkpoint 恢复,避免重新加载源文档。