因为模型有最大token限制,通常需要对文本进行分割处理,拆分成一个个小文本片段。LangChain具有许多内置的文档转换器,使拆分、合并、过滤和其他操作文档变得简单。
文本拆分器
当您想要处理大段文本时,有必要将文本拆分为块。尽管听起来很简单,但这里存在许多潜在的复杂性。理想情况下,您希望将语义相关的文本片段保持在一起。”语义相关”的含义可能取决于文本的类型。本笔记本展示了几种进行文本拆分的方法。
在高级别上,文本拆分器的工作方式如下:
- 将文本拆分为小的、具有语义意义的块(通常是句子)。
- 将这些小块合并成一个较大的块,直到达到某个大小(通过某个函数测量)。
- 一旦达到该大小,使该块成为自己的文本片段,然后开始创建一个具有一定重叠的新文本块(以保持块之间的上下文)。
这意味着有两个不同的轴可以对文本拆分器进行自定义:
- 文本如何拆分
- 块大小如何计量
开始使用文本拆分器
推荐的文本拆分器是RecursiveCharacterTextSplitter
。这将通过不同的字符进行递归性拆分文档,从"\n\n"
、"\n"
、" "
开始拆分。这样做是很好的,因为它会尽可能长时间地保持所有语义相关的内容在同一位置。
这里要了解的重要参数是chunkSize
和chunkOverlap
。chunkSize
控制最终文档的最大大小(以字符数为单位)。chunkOverlap
指定块之间应有多少重叠。这通常有助于确保文本不会被奇怪地拆分。在下面的示例中,我们将这些值设置得很小(仅用于说明目的),但实际上它们的默认值分别为1000
和200
。
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
const text = `嗨。\n\n我是Harrison。\n\n你好吗?\n好的 f f f f。
这是一段奇怪的文本,但必须测试一下拆分测试一下。\n\n
再见!\n\n-H.`;
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 10,
chunkOverlap: 1,
});
const output = await splitter.createDocuments([text]);
您会注意到在上面的示例中,我们在拆分原始文本字符串并返回文档列表。我们也可以直接拆分文档。
import { Document } from "langchain/document";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
const text = `嗨。\n\n我是Harrison。\n\n你好吗?\n好的 f f f f。
这是一段奇怪的文本,但必须测试一下拆分测试一下。\n\n
再见!\n\n-H.`;
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 10,
chunkOverlap: 1,
});
const docOutput = await splitter.splitDocuments([
new Document({ pageContent: text }),
]);
按字符拆分
这是最简单的方法。这是基于字符拆分(默认为”\n\n”),并通过字符数量测量块长度。
- 文本如何拆分:根据单个字符
- 块大小如何计量:根据字符数量
字符文本拆分器
除了RecursiveCharacterTextSplitter
之外,还有更常见的CharacterTextSplitter
。它只在一种类型的字符上拆分(默认为"\n\n"
)。您可以以完全相同的方式使用它。
import { Document } from "langchain/document";
import { CharacterTextSplitter } from "langchain/text_splitter";
const text = "foo bar baz 123";
const splitter = new CharacterTextSplitter({
separator: " ",
chunkSize: 7,
chunkOverlap: 3,
});
const output = await splitter.createDocuments([text]);
拆分代码和标记
CodeTextSplitter允许您使用多种语言拆分代码和标记。
LangChain支持各种不同的标记和特定编程语言的文本拆分器,根据特定的语法将文本拆分为更具语义自包含的块,对于向量存储或其他获取器更有用。支持流行的编程语言如JavaScript、Python、Solidity和Rust,还支持Latex、HTML和Markdown。
使用方法
使用fromLanguage
工厂方法初始化一个标准的RecursiveCharacterTextSplitter
。以下是一些不同语言的示例。
JavaScript
import {
SupportedTextSplitterLanguages,
RecursiveCharacterTextSplitter,
} from "langchain/text_splitter";
console.log(SupportedTextSplitterLanguages); // 支持的语言数组
/*
[
'cpp', 'go',
'java', 'js',
'php', 'proto',
'python', 'rst',
'ruby', 'rust',
'scala', 'swift',
'markdown', 'latex',
'html'
]
*/
const jsCode = `function helloWorld() {
console.log("Hello, World!");
}
// 调用函数
helloWorld();`;
const splitter = RecursiveCharacterTextSplitter.fromLanguage("js", {
chunkSize: 32,
chunkOverlap: 0,
});
const jsOutput = await splitter.createDocuments([jsCode]);
console.log(jsOutput);
/*
[
Document {
pageContent: 'function helloWorld() {',
metadata: { loc: [Object] }
},
Document {
pageContent: 'console.log("Hello, World!");',
metadata: { loc: [Object] }
},
Document {
pageContent: '}\n// 调用函数',
metadata: { loc: [Object] }
},
Document {
pageContent: 'helloWorld();',
metadata: { loc: [Object] }
}
]
*/
Markdown
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
const text = `
---
sidebar_position: 1
---
一旦加载了文档,您经常会希望对其进行转换以更好地适应您的应用程序。最简单的例子是您可能希望将长文档分割成可以适应您模型上下文窗口的较小块。LangChain 天然地具备了许多内置文档转换器,使得分割、合并、过滤和其他操作文档变得很容易。
当您想处理长文本时,有必要将该文本分割成块。这听起来很简单,但这里有很多潜在的复杂性。理想情况下,您希望将具有语义关联的文本块放在一起。"语义关联" 的含义可能取决于文本的类型。本笔记本演示了多种实现方式。
在高层次上,文本分割器的工作方式如下所示:
1. 将文本分割成小的、语义上有意义的块(通常是句子)。
2. 将这些小块合并成一个较大的块,直到达到某个大小(以某个函数测量)。
3. 一旦达到这个大小,将该块作为一个独立的文本片段,并开始创建一个具有一定重叠的新文本块(以保持块之间的上下文)。
这意味着您可以在两个不同的方向上定制您的文本分割器:
1. 文本如何分割
2. 如何测量块的大小
import GetStarted from "@snippets/modules/data_connection/document_transformers/get_started.mdx"
`;
const splitter = RecursiveCharacterTextSplitter.fromLanguage("markdown", {
chunkSize: 500,
chunkOverlap: 0,
});
const output = await splitter.createDocuments([text]);
console.log(output);
[
Document {
pageContent: '---\n' +
'sidebar_position: 1\n' +
'---\n' +
'# Document transformers\n' +
'\n' +
"一旦加载了文档,您经常会希望对其进行转换以更好地适应您的应用程序。最简单的例子是您可能希望将长文档分割成可以适应您模型上下文窗口的较小块。LangChain天然地具备了许多内置文档转换器,使得分割、合并、过滤和其他操作文档变得很容易。",
metadata: { loc: [Object] }
},
Document {
pageContent: '## Text splitters\n' +
'\n' +
'当您想处理长文本时,有必要将该文本分割成块。这听起来很简单,但这里有很多潜在的复杂性。理想情况下,您希望将具有语义关联的文本块放在一起。"语义关联" 的含义可能取决于文本的类型。本笔记本演示了多种实现方式。\n' +
'\n' +
'在高层次上,文本分割器的工作方式如下所示:',
metadata: { loc: [Object] }
},
Document {
pageContent: '1. 将文本分割成小的、语义上有意义的块(通常是句子)。\n' +
'2. 将这些小块合并成一个较大的块,直到达到某个大小(以某个函数测量)。\n' +
'3. 一旦达到这个大小,将该块作为一个独立的文本片段,并开始创建一个具有一定重叠的新文本块(以保持块之间的上下文)。',
metadata: { loc: [Object] }
},
Document {
pageContent: '## Get started with text splitters\n' +
'\n' +
'import GetStarted from "@snippets/modules/data_connection/document_transformers/get_started.mdx"\n',
metadata: { loc: [Object] }
}
]
Python
from langchain.text_splitter import RecursiveCharacterTextSplitter
pythonCode = """
def hello_world():
print("你好,世界!")
hello_world()
"""
splitter = RecursiveCharacterTextSplitter.fromLanguage("python", {
"chunkSize": 32,
"chunkOverlap": 0,
})
pythonOutput = await splitter.createDocuments([pythonCode])
print(pythonOutput)
'''
[
Document {
pageContent: 'def hello_world():',
metadata: { loc: [Object] }
},
Document {
pageContent: 'print("你好,世界!")',
metadata: { loc: [Object] }
},
Document {
pageContent: '# 调用函数',
metadata: { loc: [Object] }
},
Document {
pageContent: 'hello_world()',
metadata: { loc: [Object] }
}
]
'''
HTML
from langchain.text_splitter import RecursiveCharacterTextSplitter
text = """
🦜️🔗 LangChain
body {
font-family: Arial, sans-serif;
}
h1 {
color: darkblue;
}
🦜️🔗 LangChain
⚡ 通过组合性构建LLM的应用程序 ⚡
作为一个快速发展领域中的开源项目,我们非常欢迎贡献。
"""
splitter = RecursiveCharacterTextSplitter.fromLanguage("html", {
"chunkSize": 175,
"chunkOverlap": 20,
})
output = await splitter.createDocuments([text])
print(output)
'''
[
Document {
pageContent: '\n',
metadata: { loc: [Object] }
},
Document {
pageContent: '\n 🦜️🔗 LangChain',
metadata: { loc: [Object] }
},
Document {
pageContent: '\n' +
' body {\n' +
' font-family: Arial, sans-serif;\n' +
' }\n' +
' h1 {\n' +
' color: darkblue;\n' +
' }\n' +
' \n' +
' ',
metadata: { loc: [Object] }
},
Document {
pageContent: '\n' +
' \n' +
' 🦜️🔗 LangChain\n' +
' ⚡ 通过组合性构建LLM的应用程序 ⚡\n' +
' ',
metadata: { loc: [Object] }
},
Document {
pageContent: '\n' +
' 作为一个快速发展领域中的开源项目,我们非常欢迎贡献。\n' +
' \n' +
' \n' +
'',
metadata: { loc: [Object] }
}
]
'''