尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Pathway xpacks LLM 文本切块实战指南:TokenCountSplitter、RecursiveSplitter 与 DoclingParser 的 RAG 分块机制

Pathway xpacks LLM 文本切块实战指南:TokenCountSplitter、RecursiveSplitter 与 DoclingParser 的 RAG 分块机制 Pathway xpacks LLM 文本切块实战指南TokenCountSplitter、RecursiveSplitter 与 DoclingParser 的 RAG 分块机制【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway本文基于 Pathway Live Data Framework下称 Pathway的开发者文档docs/2.developers/4.user-guide/50.llm-xpack/.splitters/splitters.md展开系统讲解 RAG检索增强生成流水线中文档分块chunking的三种实现——TokenCountSplitter、RecursiveSplitter与DoclingParser——并深入源码python/pathway/xpacks/llm/splitters.py剖析其切分算法、参数默认值与测试验证方式。读完后你将能够在自己的实时 RAG 管道中正确选型、配置分块器并理解每个参数在底层是如何生效的。为什么 RAG 必须先分块将整篇文档作为一个向量嵌入往往会导致检索质量下降嵌入模型被迫把整篇文档的信息压缩进单一向量表示难以捕获细粒度细节重要上下文可能丢失检索效果随之变差。文档中还指出简单的“每 n 个字符切一刀”策略存在两个问题切分点生硬会截断句子或短语产生不完整、语义扭曲的块粒度不一致token 的粒度不一一个 token 可能是一个字符、一个单词或标点按字符数无法保证各块 token 规模一致。更好的做法是按 token 分块让每个块既语义完整又对齐句子或段落边界即在句号、逗号、换行等逻辑断点处切分。Pathway 的 LLM xpack 正是围绕这一思路提供了下面三类分块组件。分块器模块的整体设计BaseSplitter 与元数据传播所有分块器的实现在 splitters.py 中它们共同继承自抽象基类BaseSplitter源码 L21-L81该基类有两个关键设计它是一个 Pathway UDF继承pw.UDF因此可以直接作为列表达式挂到表格列上例如t t.select(chunks splitter(pw.this.text))在流式管道中对不断更新的文本列做增量分块统一的输入输出约定__wrapped__方法接受str或(str, dict | pw.Json)元组L44-L77即“文本 元数据”对。切分后同一输入文本派生出的所有 chunk 都会继承同一份 metadata若输入没有元数据则用空字典兜底。返回类型统一为list[tuple[str, dict]]。这意味着分块器与上游 parser如UnstructuredParser、DoclingParser天然衔接parser 产出的每个文档块都带有来源、标题等元数据splitter 会把这些元数据原样复制到每个子块上供后续嵌入与检索阶段使用。此外模块还提供一个极简的NullSplitterL161-L174原样返回输入文本和元数据不做任何切分适合调试管道或确认无需分块的场景单测test_null即验证了这一点见 test_splitters.py。TokenCountSplitter基于 token 计数的分块器文档给出的标准用法Python 形式from pathway.xpacks.llm.splitters import TokenCountSplitter text_splitter TokenCountSplitter( min_tokens100, max_tokens500, encoding_namecl100k_base )在模板template工程中则通过 YAML 声明splitter: pw.xpacks.llm.splitters.TokenCountSplitter min_tokens: 100 max_tokens: 500 encoding_name: cl100k_base注意原关联文档的 YAML 示例中把第一个参数写成了min_tokes这是一个拼写错误从 splitters.py L215-L227 的构造函数签名看正确的关键字是min_tokens。这组配置的含义是使用cl100k_basetokenizer与 OpenAI 嵌入模型兼容生成 100–500 token 的块。可用编码名的完整列表可查阅 tiktoken 的官方文档。参数与默认值构造函数L215-L227的完整参数参数默认值说明min_tokens50每个块的 token 数下限max_tokens500每个块的 token 数上限encoding_namecl100k_basetiktoken 编码名决定 token 化方式由于BaseSplitter把构造参数存入self.kwargs且chunk()支持**kwargs覆盖所有默认参数都可以在 UDF 调用时逐次覆盖例如splitter(pw.this.text, max_tokens300)。传入未知参数会直接抛出ValueErrorL251-L252有助于尽早发现配置笔误。底层切分算法从chunk()的实现L229-L272可以读出具体流程先用_normalize_unicode对文本做NFKC规范化L14-L18消除连字ligatures等 Unicode 变体保证 token 计数稳定用tiktoken.get_encoding(...)得到编码encode_ordinary把全文切成 token 序列按max_tokens依次截取 token 窗口并解码回文本标点回退在块内查找最后一个标点位置PUNCTUATION [., ?, !, \n]见 L213若其位置超过CHARS_PER_TOKEN * min_tokens其中CHARS_PER_TOKEN 3即按“约 3 字符/token”粗略估计就把块截断到该标点处避免在句中被拦腰截断用截断后文本重新编码的 token 数推进指针并把(chunk, metadata)追加到输出。也就是说min_tokens并非硬性下限而是标点回退的阈值系数max_tokens才是真正的硬上限。测试与示例印证单测 test_splitters.py 用一句波兰语含特殊字符和 emoji验证短文本不会被切碎仓库中的 RAG 示例 examples/projects/question-answering-rag/main.py 正是按文档同款参数min_tokens100, max_tokens500, encoding_namecl100k_base构造TokenCountSplitter接入DocumentStore与OpenAIEmbedderexamples/projects/conf42/main.py 则演示了更省事的写法TokenCountSplitter(max_tokens400)其余取默认值并把 splitter 直接传给VectorStoreServer实现“入参即分块”的向量化服务。RecursiveSplitter按分隔符递归下钻的分块器文档给出的用法splitter RecursiveSplitter( chunk_size400, chunk_overlap200, separators[\n#, \n##, \n\n, \n], # separators for markdown documents model_namegpt-4o-mini, )对应的模板 YAMLsplitter: pw.xpacks.llm.splitters.RecursiveSplitter chunk_size: 400 chunk_overlap: 200 separators: - \n# - \n## - \n\n - \n model_name: gpt-4o-mini工作原理RecursiveSplitter与TokenCountSplitter一样以 token 数度量块长但切分点的确定方式不同它持有一个有序分隔符列表separators从列表中第一个粒度最细分隔符开始尝试切分只要某段子文本仍超过chunk_size就落到列表中的下一个分隔符继续切直到所有块都小于chunk_size为止。以文档示例为例它会先尝试在\n#Markdown 一级标题处切必要时退回\n##、\n\n段落、\n行。参数与默认值构造函数见 splitters.py L114-L154参数默认值说明chunk_size500块的最大长度字符数或 token 数取决于 tokenizer 配置chunk_overlap0相邻块之间的重叠量separatorsSEPARATORS [\n\n, \n, , ]L84按优先级排序的分隔符列表默认从段落、行、空格逐层下钻is_separator_regexFalse分隔符是否按正则解释encoding_nameNonetiktoken 编码名提供后按该编码的 token 数度量块长model_nameNonetiktoken 模型名如gpt-4o-mini提供后按该模型的 token 化度量hf_tokenizerNoneHugging FacePreTrainedTokenizerBase提供后按其 token 化度量构造函数中的选择逻辑值得注意L141-L154给了encoding_name或model_name→ 走RecursiveCharacterTextSplitter.from_tiktoken_encoder块长按token 数计算给了hf_tokenizer→ 走from_huggingface_tokenizer块长按该 HF tokenizer 的 token 数计算三者都不给 → 退化为按字符数计算块长。也就是说文档中“以 token 数度量”的表述成立的前提是你在构造时传入了 tokenizer 配置之一否则它是纯字符级切分。关于 chunk_overlap 的取舍文档特别提醒chunk_overlap能引入重叠块、帮助不同块捕获不同上下文例如跨越切分点的长句子但重叠会增加总块数从而增大嵌入与检索开销。上面的示例把 overlap 设为 200约为chunk_size的一半是典型的“语义连续性优先”配置。测试覆盖仓库为三条构造路径都提供了测试test_recursive_from_encodingtests/test_splitters.py L34-L47encoding_namecl100k_base、chunk_size30用 5 段以\n\n连接的 26-token 文本断言恰好切出 5 块且每块携带空元数据pw.Json({})——这正是BaseSplitter元数据传播约定的直接验证test_recursive_from_model_nameL50-L61用model_namegpt-4走同一断言集成测试 integration_tests/xpack/test_splitters.py用transformers.AutoTokenizer加载bert-base-uncased以hf_tokenizer构造并验证同样切出 5 块。另外底层实际是langchain_text_splitters.RecursiveTextSplitterMIT 许可的封装这一点在 类 docstring L97 中有明确声明且langchain_text_splitters通过optional_imports(xpack-llm)延迟导入L126-L130只有在安装了xpack-llm可选依赖组时才需要。DoclingParser基于文档结构语义的分块文档把DoclingParser归入分块主题因为它走的是完全不同的路线不依赖 token 或字符计数而是利用文档固有结构标题、段落、列表、表格等标记决定块边界。这样切出的块能保留逻辑章节每个块内部上下文连贯——例如不会把一张表从中间劈开。实现位于 parsers.py 中的 DoclingParserL342 起其 docstring 与构造参数给出了比文档更细的实现事实它是一个pw.UDF内部封装docling的DocumentConverter并额外支持用视觉 LLM 解析 PDF 中的图片与表格chunk: bool True默认开启分块。文档中“想关掉分块就把构造参数设为chunkFalse”的说法与此对应——置False时整篇文档作为单个块返回docstring L379-L380底层 chunker分块由经过改造的HybridChunker源自docling完成L369-L378。改造点包括正确处理视觉 LLM 解析图片/表格的功能表格不再转成“行/列/值”三元组而是直接转成 Markdown 文本。图片与表格会各自成为独立块并携带 caption标题/说明文字长度不敏感文档说“这种切法会产生长度不一的块”的根源在此——该 chunker 只按结构切块不感知字符或 token 长度相似 metadata 的块会被合并merge避免碎片化附加上下文每个块会包裹标题、caption 等附加元素图片、表格尤其如此这为检索提供了额外语境提升命中率。与 token 级分块器组合由于DoclingParser的块长不均匀文档建议若需要更均匀的块可以在DoclingParser之上再套一层TokenCountSplitter或RecursiveSplitter。从类型约定看这是天然可行的——parser 输出(text, metadata)元组列表splitter 的输入恰好接受这种元组且元数据会逐层传播到最细粒度的子块。即“结构化粗切 token 级精切”的两级方案。另外DoclingParser还支持table_parsing_strategydocling或llm、image_parsing_strategyllm、pdf_pipeline_options等参数来调节解析行为如pdf_pipeline_options{table_structure_options: {mode: accurate}}默认管道选项见 L441-L461默认表格结构解析为fast模式且开启do_cell_matching。三种方案选型小结方案切分依据长度控制元数据适用场景TokenCountSplittertoken 窗口 标点回退硬上限max_tokens标点回退阈值min_tokens全块继承纯文本、需要均匀 token 块贴合嵌入模型上下文窗口RecursiveSplitter分隔符列表递归下钻chunk_size硬上限可配chunk_overlap全块继承Markdown/结构化长文、需要重叠上下文、可指定 tiktoken/HF tokenizerDoclingParserchunkTrue文档语义结构标题/段落/表格/图片不敏感块长不一块合并 标题/caption 包裹PDF 等复杂版式文档、表格/图片不可劈开三者的公共契约由BaseSplitter保证输入接受str或(str, metadata)输出统一为(chunk, metadata)元组列表metadata 全量传播。因此在 Pathway 的流式 RAG 管道中它们可以像积木一样串接在 parser 与 embedder 之间并随源数据更新自动增量重算分块结果。参考文件文档源文件docs/2.developers/4.user-guide/50.llm-xpack/.splitters/splitters.md模板版同一内容位于 docs/2.developers/7.templates/40.rag-customization/40.splitters.md分块器实现python/pathway/xpacks/llm/splitters.pyDoclingParser实现python/pathway/xpacks/llm/parsers.py单元测试python/pathway/xpacks/llm/tests/test_splitters.py集成测试HF tokenizer 路径integration_tests/xpack/test_splitters.py示例项目examples/projects/question-answering-rag/main.py、examples/projects/conf42/main.py【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表