跳到主要内容

切块器全景

本章目标:看完能选对切块器。先讲它们共享的骨架 BaseChunker,再把 11 种策略按「复杂度阶梯」排开,最后给一张选型表。

1. 共享骨架:BaseChunker

所有切块器都继承 BaseChunker(src/chonkie/chunker/base.py:67)。子类只需实现一个抽象方法 chunk(text) -> list[Chunk](base.py:199-210),其余入口骨架由基类白送。

基类提供四种调用入口,职责各不相同:

入口输入干什么源码
__call__单串或列表语法糖:自动分派到 chunkchunk_batchbase.py:95-116
chunk_batch一批文本顺序或多进程并行地逐条切base.py:212-233
achunk / achunk_batch同上异步版,用 asyncio.to_thread 包同步实现base.py:235-260
chunk_documentDocumentDocument 并把文档级元数据下放进每个块base.py:295-315

直觉:为什么入口要分这么多种?

因为切块器在不同场景下「输入形态」不同:

  • 裸文本 → 你只想快速切一段字符串,用 __call__
  • 一批文本 → 切几千个文档,想吃满 CPU,用 chunk_batch(可开多进程)。
  • Pipeline 里 → 上游传来的是 Document 对象,得走 chunk_document,因为它还要做一件特别的事:重切已有块

巧妙处 1:chunk_document 的「双模式」

chunk_document 不是简单地切 document.content。它先看文档有没有已经切好的块(base.py:308-313):

# 示意,非源码(提炼 base.py:308-314 的逻辑)
if document.chunks: # 已经被别的切块器切过
results = [self.chunk(c.text) for c in document.chunks] # 对每块再切
document.chunks = self._merge_new_chunks(document.chunks, results)
else:
document.chunks = self.chunk(document.content) # 首次切整篇

这让你能链式套用多个切块器(Pipeline 里 .chunk_with("recursive").chunk_with("semantic") 就靠这个)。重点看 _merge_new_chunks(base.py:262-284):它用 dataclasses.replace 把子块的索引平移加上父块的起始偏移,保证最终每个块的 start_index/end_index 仍指向原始整篇文本的正确位置——而不是父块内部的相对位置。

巧妙处 2:批量并行的「最优工人数」

chunk_batch 默认顺序处理(_use_multiprocessing = False),但基类备好了多进程路径。它的工人数不是写死的(_get_optimal_worker_count,base.py:118-135):

# 真实源码 base.py:124
worker_count = min(8, max(1, cpu_cores * 3 // 4))

即「CPU 核数的 3/4,封顶 8」——留出余量给系统、又不让进程开销吃掉收益。注意默认关闭并行:多进程的 pickle/IPC 开销对短文本常常得不偿失。

2. 11 种切块器:一条复杂度阶梯

把切块器按「需要多少外部资源 / 多聪明」从轻到重排:

切块器别名一句话切法需要什么源码
TokenChunkertoken按固定 token 数硬切,可设重叠仅 tokenizerchunker/token.py
FastChunkerfastSIMD 字节级切,100+ GB/s无(默认装)chunker/fast.py
SentenceChunkersentence按句子边界切,再合并到 chunk_sizetokenizerchunker/sentence.py
RecursiveChunkerrecursive段落→句子→停顿→词→token 逐级降级tokenizerchunker/recursive.py
TableChunkertable按行或字符数切 markdown 表格chunker/table.py
CodeChunkercode按代码结构(AST)切tree-sitterchunker/code.py
SemanticChunkersemantic按嵌入相似度找语义边界嵌入模型chunker/semantic.py
LateChunkerlate先整体嵌入再切,块嵌入更准嵌入模型chunker/late.py
NeuralChunkerneural用神经模型判断边界HF 模型chunker/neural.py
SlumberChunkerslumber让 LLM 判断「在第几段切」(即 AgenticChunker)LLM(genie)chunker/slumber.py
TeraflopAIChunkerteraflopai走 TeraflopAI 分段 API 做领域分段外部 APIchunker/teraflopai.py

怎么读这张阶梯

  • 越往上越快越笨:TokenChunker 不看语义,纯按数量切,可能从句中劈断,但零依赖、极快。
  • 中段是「结构感知」:Recursive/Sentence/Code/Table 利用文本的天然边界(段落、句号、AST、表行),不需要嵌入或 LLM,是性价比甜区。
  • 越往下越聪明越贵:Semantic/Late 要跑嵌入模型;Slumber 每切一刀都调一次 LLM,质量最高但最慢最贵;TeraflopAI 则把分段外包给外部 API。

3. 选型速查

你的情况理由
不确定 / 通用文档RecursiveChunker(默认)结构感知、零模型依赖、快
海量纯文本、只要均匀块TokenChunker / FastChunker最快,语义无关
源代码CodeChunker按函数/类边界切,不切断逻辑
markdown 大表格TableChunker按行切,保住表结构
检索质量优先、能跑嵌入SemanticChunker / LateChunker按语义边界,块更连贯
质量第一、预算充足SlumberChunkerLLM 判边界,最贴近人类直觉

4. 一个共享细节:统一的分隔符切分

Sentence/Semantic/Recursive/Slumber 这几个「按分隔符切」的切块器,共享同一个底层函数 split_text_by_delimiters(src/chonkie/chunker/base.py:18-64)。它的关键在于把热点交给 Rust,并按分隔符复杂度走两条路:

# 真实源码 base.py:44-61(节选)
has_complex_delimiters = any(len(d) > 1 or not d.isascii() for d in delimiters)
if has_complex_delimiters:
offsets = chonkie_core.split_pattern_offsets(text_bytes, patterns=..., ...)
else:
offsets = chonkie_core.split_offsets(text_bytes, delimiters=..., ...)
  • 简单分隔符(单字符、纯 ASCII,如 ". " 拆成 . )→ 走 split_offsets,把所有分隔字符拼成一个字节集合,一趟扫描。
  • 复杂分隔符(多字符或非 ASCII,如 ". " 整体、中文标点)→ 走 split_pattern_offsets,做模式匹配。

两者都返回字节偏移 (start, end),Python 侧再 decode 回字符串(base.py:63)。在字节层面切、只在末尾 decode,是它能快的原因之一。include_delim 控制分隔符归前一块还是后一块(默认 "prev"),min_chars 防止切出太短的碎片。

5. 代码地图

主题文件符号
切块器基类 / 抽象方法src/chonkie/chunker/base.pyBaseChunkerBaseChunker.chunk
共享分隔符切分(下沉 Rust)src/chonkie/chunker/base.pysplit_text_by_delimiters
块重切 + 索引平移src/chonkie/chunker/base.pychunk_document_merge_new_chunks
并行工人数src/chonkie/chunker/base.py_get_optimal_worker_count
按 token 硬切 + 重叠src/chonkie/chunker/token.pyTokenChunker_token_group_generator
递归切(默认)src/chonkie/chunker/recursive.pyRecursiveChunker
语义切src/chonkie/chunker/semantic.pySemanticChunker
LLM 切src/chonkie/chunker/slumber.pySlumberChunker
块数据结构src/chonkie/types/base.pyChunk

6. 横向对比

Chonkie 同处 ai-agent-referencerag-retrieval 区。相对其它 RAG 库,Chonkie 刻意只做「切块 + 入库胶水」,不做检索、不做重排、不做生成——这正是它「轻」的来源。要看完整 RAG 编排,参见同 shelf 的检索/编排类子库。