面向嵌入与 RAG 的文本分块工具 — 按 token 切分

为嵌入和 RAG 把长文本切成带重叠的 token 分块。切口落在句子和段落边界上,绝不切在词中间,并把每个切口都显示出来。

为嵌入做文本分块:切在哪里,决定你能检索到什么

检索系统的失败是安静的。你把语料嵌入、接上搜索、提个问题,回来的东西话题相关,却答不上来。第一反应是怪嵌入模型或相似度度量。但更多时候,问题发生在这两者之前:文本被切成了每一块都不含完整意思的碎片,而在切分时被毁掉的语义,再聪明的重排也救不回来。

这个工具把文本切成有 token 上限、带重叠的块,并且尽量切在最有意义的边界上,而不是固定偏移量。它把每一个边界都展示给你,因为一次糟糕的切分只有在你读到「上一块在哪结束、下一块从哪开始」时才看得出来。全部在这个浏览器标签页里运行。

递归边界切分

最朴素的做法是每 N 个 token 切一刀。它快,而且是错的,因为 token 边界跟语义边界没有任何关系——你会切在句子中间,有时切在词中间,得到的向量描述的是一个没人写过的残片。

这里的方法沿着一梯分隔符往下找,用第一个能把片段切到装得下的那一级。顺序是:Markdown 标题之前、空行、任意换行、句子边界、逗号和分号处的分句边界,最后是词与词之间的空白。只有当这些都不存在时——一个压缩打包过的 bundle、一个超长的单词——才退回到按 token 下标硬切。

实际效果是:只要文本有结构,结构就会被保住。有标题的文档按小节切,散文按段落切,段落太长就按句子切,一整片没有断点的文字按词切。每一块都结束在人会结束的地方,除非文本根本没给这个机会。

重叠到底是干什么用的

重叠把上一块的尾部重复到下一块的开头。它存在,是因为一个事实和它所指的对象经常分处边界两侧。「迁移是通宵跑的。它在第三张表上失败了。」在这两句之间切开,第二块里就有一个没有主语的失败,第一块里则有一次没有结果的迁移,两块都检索不出有用的东西。有了重叠,第二块就带上了那个先行词。

代价是重复:重叠的 token 会被多存一遍、多嵌入一遍、多检索一遍。块大小的百分之十到十五是常见的折中,预设值就落在这里。统计面板会报告重叠到底多加了多少 token,于是这个权衡是一个数字,而不是一种感觉。

有一个防护值得知道:重叠等于或大于块大小,意味着每一块的开头都是上一块结尾的全部,过程永远不会前进。这种情况会被夹住,而不是让它挂死。

怎么选块大小

块大小是精度和上下文之间的取舍,没有放之四海皆准的答案:

  • 小块,256 token 上下,匹配锐利。覆盖两三句话的向量,被这两三句说的内容主导。适合在密集的参考资料上做问答。风险是块匹配得很好,却缺少真正回答问题所需的上下文。
  • 中等块,512 上下,是常见的默认值,也是多数嵌入模型最舒服的区间,大致相当于一个像样的段落。
  • 大块,1024 及以上,每次命中带来的上下文更多,但向量被稀释了。一个覆盖四个主题的块,位置在这四者的平均值上,对哪个都匹配不强。
  • 超大块,几千 token,已经不再是检索单元,而是分页单元——用来把一份长文档分批顺序喂给模型,而不是拿来搜索。

四种切分策略

智能切分就是上面说的递归梯子,适合大多数散文。按段落整段整段地装,绝不切开一段,适合段落本身就是思维单元、你宁可块大小参差也不要切坏的文本。按 Markdown 标题一节一块,对「标题恰好说明了下面写什么」的文档来说是自然选择。按行整行整行地装,适合日志、CSV 摘录和每行独立的列表。

无论哪种模式,仍然超出上限的单元都会先经递归切分器缩小再装箱,所以选策略永远不会产出超尺寸的块。

计数,以及这个数字的含义

token 用的是本站给仓库估算体积时同一个分词器,来自 OpenAI 模型所用的那一族。Claude 和 Gemini 的计数会有出入——不同词表切同一段文本的方式不同——但足够接近,可以拿来对着上限估块的大小。预算紧的话,留点余量,别把这个数字当成精确值。

还要注意,嵌入模型标称的上限是一个硬截断点,不是一个目标。超过它,尾部会被无声丢掉,这种失败模式不报错,却会让检索质量下降,而且真的很难诊断。

能直接喂给下一步的输出

三种下载。纯文本,可选带 --- Chunk n/N --- 分隔头,方便阅读和检查。JSON,一个对象数组,每项含下标、token 数和文本,适合一次性摄入的脚本。JSONL,一行一个对象,这是流式摄入和多数批量嵌入接口期待的形式,也是语料大到无法作为单个已解析数组放进内存时你要的形式。

这和站内其他工具天然配套:先把仓库、PDF、网页或字幕稿转成文本,再拿到这里分块。两步都不会上传任何东西。