#split #nlp #tokenizer #ai #language-model #text

text-splitter

将文本拆分为语义块,最多达到所需的块大小。支持按字符和标记计算长度,并可以从 Rust 和 Python 调用。

35 个版本 (14 个破坏性更新)

0.15.0 2024年8月11日
0.14.1 2024年7月6日
0.14.0 2024年6月21日
0.8.1 2024年3月26日
0.4.2 2023年7月2日

32文本处理 中排名

Download history 2060/week @ 2024-05-02 1352/week @ 2024-05-09 1616/week @ 2024-05-16 2027/week @ 2024-05-23 3000/week @ 2024-05-30 2133/week @ 2024-06-06 2401/week @ 2024-06-13 4282/week @ 2024-06-20 3082/week @ 2024-06-27 2569/week @ 2024-07-04 2705/week @ 2024-07-11 3084/week @ 2024-07-18 2708/week @ 2024-07-25 2465/week @ 2024-08-01 3324/week @ 2024-08-08 2218/week @ 2024-08-15

11,273 每月下载量
15 crates 中使用 (12 个直接使用)

MIT 许可证

140KB
2.5K SLoC

text-splitter

Docs Licence Crates.io codecov

大型语言模型(LLMs)可以用于许多任务,但通常具有有限上下文大小,可能小于您可能希望使用的文档。为了使用较长的文档,您通常需要将文本拆分为块以适应此上下文大小。

此 crate 提供将较长的文本拆分为较小块的方法,旨在最大化所需的块大小,但尽可能在语义上合理的边界处拆分。

开始使用

将以下内容添加到您的项目中

cargo add text-splitter

按字符数量

使用此 crate 的最简单方法是使用默认实现,它使用字符计数作为块大小。

use text_splitter::TextSplitter;

// Maximum number of characters in a chunk
let max_characters = 1000;
// Default implementation uses character count for chunk size
let splitter = TextSplitter::new(max_characters);

let chunks = splitter.chunks("your document text");

使用 Hugging Face Tokenizer

需要启用 tokenizers 功能并将 tokenizers 添加到依赖项中。下面的示例还要求启用 tokenizers http 功能。

cargo add text-splitter --features tokenizers
cargo add tokenizers --features http
use text_splitter::{ChunkConfig, TextSplitter};
// Can also use anything else that implements the ChunkSizer
// trait from the text_splitter crate.
use tokenizers::Tokenizer;

let tokenizer = Tokenizer::from_pretrained("bert-base-cased", None).unwrap();
let max_tokens = 1000;
let splitter = TextSplitter::new(ChunkConfig::new(max_tokens).with_sizer(tokenizer));

let chunks = splitter.chunks("your document text");

使用 Tiktoken Tokenizer

需要启用 tiktoken-rs 功能并将 tiktoken-rs 添加到依赖项中。

cargo add text-splitter --features tiktoken-rs
cargo add tiktoken-rs
use text_splitter::{ChunkConfig, TextSplitter};
// Can also use anything else that implements the ChunkSizer
// trait from the text_splitter crate.
use tiktoken_rs::cl100k_base;

let tokenizer = cl100k_base().unwrap();
let max_tokens = 1000;
let splitter = TextSplitter::new(ChunkConfig::new(max_tokens).with_sizer(tokenizer));

let chunks = splitter.chunks("your document text");

使用范围指定块容量

您还可以指定块容量为范围。

一旦块达到长度在范围内,它将被返回。

可能返回的块小于 start 值,因为添加下一部分文本可能使其大于 end 容量。

use text_splitter::{ChunkConfig, TextSplitter};

// Maximum number of characters in a chunk. Will fill up the
// chunk until it is somewhere in this range.
let max_characters = 500..2000;
// Default implementation uses character count for chunk size
let splitter = TextSplitter::new(max_characters);

let chunks = splitter.chunks("your document text");

Markdown

上述所有示例也可以与Markdown文本一起工作。如果您启用markdown功能,您可以使用与TextSplitter相同的方式使用MarkdownSplitter

cargo add text-splitter --features markdown
use text_splitter::MarkdownSplitter;
// Maximum number of characters in a chunk. Can also use a range.
let max_characters = 1000;
// Default implementation uses character count for chunk size.
// Can also use all of the same tokenizer implementations as `TextSplitter`.
let splitter = MarkdownSplitter::new(max_characters);

let chunks = splitter.chunks("# Header\n\nyour document text");

代码

上述所有示例也可以与可以使用tree-sitter解析的代码一起工作。如果您启用code功能,您可以使用与TextSplitter相同的方式使用CodeSplitter

cargo add text-splitter --features code
cargo add tree-sitter-<language>
use text_splitter::CodeSplitter;
// Maximum number of characters in a chunk. Can also use a range.
let max_characters = 1000;
// Default implementation uses character count for chunk size.
// Can also use all of the same tokenizer implementations as `TextSplitter`.
let splitter = CodeSplitter::new(tree_sitter_rust::language(), max_characters).expect("Invalid tree-sitter language");

let chunks = splitter.chunks("your code file");

方法

为了在块中尽可能保留语义意义,每个块都由可以适合下一个给定块的最大的语义单元组成。对于每种拆分器类型,都有一组定义的语义级别。以下是一个使用步骤的示例

  1. 按递增语义级别拆分文本。
  2. 检查每个级别的第一个项目,并选择第一个项目仍然适合块大小的高级别。
  3. 将此级别或更高级别的相邻部分尽可能多地合并成一个块,以最大化块长度。合并时始终包含更高语义级别的边界,这样块就不会无意中跨越语义边界。

使用chunks方法拆分文本时使用的边界,按升序排列

TextSplitter语义级别

  1. 字符
  2. Unicode图形簇边界
  3. Unicode单词边界
  4. Unicode句子边界
  5. 新行序列的递增长度。(换行符是\r\n\n\r)每个连续换行符序列的唯一长度被视为其自己的语义级别。因此,2个换行符的序列比1个换行符的序列级别更高,依此类推。

拆分不会低于字符级别,否则可能会得到不完整的字符字节,这可能不是一个有效的Unicode字符串。

MarkdownSplitter语义级别

Markdown按照CommonMark规范进行解析,以及一些可选功能,如GitHub Flavored Markdown。

  1. 字符
  2. Unicode图形簇边界
  3. Unicode单词边界
  4. Unicode句子边界
  5. 软换行符(单个换行符),这不一定是一个Markdown中的新元素。
  6. 内联元素,如:文本节点、强调、加粗、删除线、链接、图片、表格单元格、内联代码、脚注引用、任务列表标记和内联HTML。
  7. 块元素,如:段落、代码块、脚注定义、元数据。还包括可以包含其他“块”类型元素的块引用或表格或列表中的行/项,以及包含项目的列表或表格。
  8. 主题分隔线或水平线。
  9. 按级别划分的标题

拆分不会低于字符级别,否则可能会得到不完整的字符字节,这可能不是一个有效的Unicode字符串。

CodeSplitter语义级别

  1. 字符
  2. Unicode图形簇边界
  3. Unicode单词边界
  4. Unicode句子边界
  5. 语法树的递增深度。因此,函数的级别比函数内部的语句级别更高,依此类推。

拆分不会低于字符级别,否则可能会得到不完整的字符字节,这可能不是一个有效的Unicode字符串。

关于句子的说明

有许多确定句子分割的方法,准确度各不相同,许多需要ML模型来完成。我们不是试图找到完美的句子分割,而是依赖于Unicode句子边界的方法,在大多数情况下,如果段落太大,这种方法足以找到合理的语义分割点,并避免了许多其他方法带来的性能惩罚。

功能标志

文档格式支持

功能 描述
code 启用CodeSplitter结构以通过tree-sitter解析器解析代码文档。
markdown 启用MarkdownSplitter结构以通过CommonMark规范解析Markdown文档。

令牌化支持

依赖特征 支持的版本 描述
rust_tokenizers ^8.0.0 启用 (Text/Markdown)Splitter::new 接受提供的任何标记化器作为参数。
tiktoken-rs ^0.5.0 启用 (Text/Markdown)Splitter::new 接受 tiktoken_rs::CoreBPE 作为参数。这对于为 OpenAI 模型分割文本很有用。
标记化器 ^0.20.0 启用 (Text/Markdown)Splitter::new 接受 tokenizers::Tokenizer 作为参数。这对于分割具有 Hugging Face 兼容标记化器的文本模型很有用。

灵感

这个软件包受到 LangChain 的 TextSplitter 的启发。但是,在查看实现时,我们发现有可能在性能和语义块化方面有更好的表现。

向 unicode-rs 团队致以诚挚的感谢,他们开发的 unicode-segmentation 软件包管理了匹配单词和句子的 Unicode 规则的许多复杂性。

依赖项

~4–16MB
~170K SLoC