Pathway RAG 中 TokenCountSplitter 和 RecursiveSplitter 分块策略怎么选?
【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway
在 Pathway Live Data Framework 里搭建 RAG 时,DocumentStore会把文档依次做解析、分块(chunking)和建索引。整个文档被压缩成单个向量往往检索效果差——模型被迫把全部信息塞进一个表示里,细节和上下文容易丢失。分块是这一步里直接影响检索质量的选择,而 Pathway LLM xpack 提供的主要选项就是TokenCountSplitter和RecursiveSplitter。这篇文章基于项目文档(Chunking 说明、Document Indexing 说明)和源码,给出两者的行为差异、选型依据,以及一套可以用retrieve_query验证的分块配置方法。
准备条件
按文档要求安装 LLM xpack(llm-app 文档 中的安装命令):
pip install pathway[xpack-llm] python-dotenv两个 splitter 都用 tiktoken 统计 token 数,所以 token 长度上限是以“编码后的 token 数”为准,而不是字符数。
两个 Splitter 的行为差异
两者的差异在 Chunking 文档 和 splitters.py 源码 中有明确说明:
TokenCountSplitter:先按encoding_name指定的 tiktoken 编码把全文 tokenize,再切成 token 数落在min_tokens到max_tokens之间的块,并尝试在标点(. ? !和换行)处断开。它不关心句子或段落结构,产出的是大小相对均匀的块。构造参数为min_tokens、max_tokens、encoding_name。RecursiveSplitter:同样按 token 数衡量块长,但切分点由一组有序的separators决定——从最细的分隔符开始尝试,块仍超过chunk_size时回退到下一个更粗的分隔符,直到所有块都小于chunk_size。例如可以先按\n\n切,必要时再回退到句号.。它额外支持chunk_overlap,让相邻块重叠以保留跨块上下文。文档同时提醒:开启 overlap 会增加检索时的总块数,可能影响性能。
选型时可以按文档给出的这两条线索判断:
- 你要严格约束块的 token 上限/下限,并且希望长度计算与 embedding 模型所用的分词对齐(
cl100k_base兼容 OpenAI 的 embedding 模型)——用TokenCountSplitter; - 你的文档有清晰的结构性分隔(Markdown 标题、段落、句子),希望块尽量落在这些边界上,并且可能需要重叠上下文——用
RecursiveSplitter,并显式传入适合文档格式的separators。
另一个来自文档的边界情况:如果 parser 用的是DoclingParser,它本身会按标题、段落、列表等结构做分块,块长不均匀;文档明确说“若需要更均匀的块,可以在 DoclingParser 之上再叠加TokenCountSplitter或RecursiveSplitter”。也就是说结构感知的解析和 token 尺度的分块并不互斥。
配置方法
以下 Python 示例直接取自文档。
TokenCountSplitter:
from pathway.xpacks.llm.splitters import TokenCountSplitter text_splitter = TokenCountSplitter( min_tokens=100, max_tokens=500, encoding_name="cl100k_base" )这组配置产生 100–500 token 的块,使用cl100k_base分词器,文档说明其兼容 OpenAI 的 embedding 模型。
RecursiveSplitter,以 Markdown 文档为例:
splitter = RecursiveSplitter( chunk_size=400, chunk_overlap=200, separators=["\n#", "\n##", "\n\n", "\n"], # separators for markdown documents model_name="gpt-4o-mini", )separators的顺序就是回退顺序,文档示例给的就是面向 Markdown 的一组分隔符;model_name用于让 tiktoken 按该模型的编码方式统计 token 数。注意chunk_overlap=200意味着相邻块之间有 200 token 的重叠,检索返回的块总量会比无重叠时更多。
如果走 YAML 模板而非 Python,项目文档同样提供了两种 splitter 的 YAML 配置形态(见 RAG 配置示例 的 “Chunking (Splitters)” 部分),字段与上面的 Python 参数一一对应,本文以 Python 形式为准。
把 Splitter 接进 DocumentStore
来自 Document Indexing 文档 的最小用法:准备一个字节流的data列、一个 embedder 和一个 retriever_factory,再把 splitter 传给DocumentStore:
from pathway.xpacks.llm.document_store import DocumentStore from pathway.xpacks.llm.splitters import TokenCountSplitter import pathway as pw data_sources = pw.io.fs.read( "./sample_docs", # 替换为你的文档目录,需能读出 binary 数据 format="binary", with_metadata=True, ) text_splitter = TokenCountSplitter() store = DocumentStore( docs=data_sources, retriever_factory=retriever_factory, # 由 BruteForceKnnFactory 等构造,见上文文档示例 splitter=text_splitter, )换成RecursiveSplitter时只需把text_splitter换成上一节的配置对象,其余不变。
验证分块结果
分块是否正确,可以在两个层面检查,验证手段都来自项目文档和测试代码。
1. 用检索结果验证(端到端)。文档给出的方式是构造一个 queries CSV,列固定为query、k、metadata_filter(可选)、filepath_globpattern(可选):
printf "query,k,metadata_filter,filepath_globpattern\n\"Who is Regina Phalange?\",3,,\n" > queries.csvquery = pw.io.fs.read( "queries.csv", format="csv", schema=DocumentStore.RetrieveQuerySchema ) result = store.retrieve_query(query)运行retrieve_query后,看命中的块是否落在你预期的边界上:切得太大(整段文档一块)或太碎(块内没有完整语义)都会让查询匹配偏离。这一步能直接观察到 splitter 选择对检索内容的影响。
2. 用单文档微验证(只看分块行为,不依赖向量)。项目测试 test_splitters.py 展示了一个可以照抄的验证方式:取一句 26 token(cl100k_base编码下)的句子,用\n\n重复拼接 5 段,再用RecursiveSplitter(encoding_name="cl100k_base", chunk_size=30, chunk_overlap=0)切分——由于chunk_size=30大于一句的 26 token 而小于两句,预期每个段落恰好成为一个块,共 5 块,且第一块内容等于原句。测试里的断言即验证标准:len(result) == 5且result.iloc[0].ret[0] == txt。
TokenCountSplitter的文档字符串(splitters.py 中的 Example 段)也给了一个文档示例输出:对"cooltext"用TokenCountSplitter(min_tokens=1, max_tokens=1)分块,结果为(('cool', pw.Json({})), ('text', pw.Json({})))。这只是文档示例,用来说明输出形态是(chunk_text, metadata)的配对列表,metadata 会传播给同一段输入产生的所有块;实际分块时请按你的min_tokens/max_tokens判断,不要把这个示例当成固定预期。
限制与边界
chunk_overlap开启后总块数增加,文档明确提示这“could impact performance”——这是 RecursiveSplitter 路径上唯一被文档点名的代价,配置 overlap 前需权衡检索延迟与跨块上下文的收益。- 文档示例中
cl100k_base是“兼容 OpenAI embedding 模型”的编码;如果你的 embedder 不是 OpenAI 系,编码名应改为与该 embedder 匹配的分词口径,文档没有给出其他编码的对照表,只能依据 tiktoken 的编码列表自行确认。 DoclingParser自身的结构分块不按 token 计数,块长不均;文档给出的处理方式是叠加分块器或设chunk=False关闭其分块,二者择一,不要假设结构块与 token 上限同时受控。
下一步可以按 Document Indexing 文档 中的 REST Server 一节,把DocumentStore用DocumentStoreServer暴露为服务,用curl -X POST http://localhost:8765/v1/retrieve发起查询请求,在生产形态下复核分块效果。
【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考