Skip to content

文本切割

为什么需要切割?

回忆一下 RAG 的流程:

  1. 用户提问
  2. 从知识库检索相关内容
  3. 将检索到的内容和用户问题一起交给模型推理

如果文档不切割,检索阶段就只能以整篇为单位,长文会超出模型的 Token 限制,无法一次性送进模型。

快速上手#

如何切割?

最通用的是使用 RecursiveCharacterTextSplitter 来进行切割。

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 64,
chunkOverlap: 0,
})

在线的 可视化工具,可以快速看到不同 chunkSize 和 chunkOverlap 的切分效果。初学推荐设置:chunkSize = 1000,chunkOverlap = 200,再通过工具观察效果慢慢调。

快速上手示例:

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
import { TextLoader } from 'langchain/document_loaders/fs/text'
const loader = new TextLoader('data/kong.txt')
const docs = await loader.load()
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 64,
chunkOverlap: 10,
})
const result = await splitter.splitDocuments(docs)
console.log(result)

其它类型切割器#

现实场景里,处理的文档类型五花八门,比如:

LangChain 中提供了不同的切割器

Splitter 名称适用文档类型切分策略说明
RecursiveCharacterTextSplitter普通文本(小说、说明)默认最常用,按字符层级递进切分
MarkdownTextSplitterMarkdown 文件根据标题层级(#、## 等)结构来切
TokenTextSplitter精确控制 token 情况按 token 数切分,不考虑语义
CharacterTextSplitter非结构文本纯字符切,简单粗暴

切割Markdown示例

import { TextLoader } from 'langchain/document_loaders/fs/text'
import { MarkdownTextSplitter } from 'langchain/text_splitter'
const loader = new TextLoader('data/markdown语法.md')
const docs = await loader.load()
const splitter = new MarkdownTextSplitter({
chunkSize: 300,
chunkOverlap: 0,
})
const result = await splitter.splitDocuments(docs)
console.log(result)

切割代码

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
import { TextLoader } from 'langchain/document_loaders/fs/text'
const loader = new TextLoader('data/test.js')
const docs = await loader.load()
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 320,
chunkOverlap: 0,
})
const result = await splitter.splitDocuments(docs)
console.log(result)

RecursiveCharacterTextSplitter.fromLanguage("js", {...})

这样会尽量避免把一行代码切成两半或破坏语法结构,利于后续大模型理解。

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'
import { TextLoader } from 'langchain/document_loaders/fs/text'
const loader = new TextLoader('data/test.js')
const docs = await loader.load()
const splitter = RecursiveCharacterTextSplitter.fromLanguage('js', {
chunkSize: 320,
chunkOverlap: 0,
})
const result = await splitter.splitDocuments(docs)
console.log(result)

支持的编程语言:

import { SupportedTextSplitterLanguages } from 'langchain/text_splitter'
console.log(SupportedTextSplitterLanguages)

也可以在 这里 看到。

按照Token切割

适合用在 token 预算敏感的场景。

import { TokenTextSplitter } from 'langchain/text_splitter'
const text =
'I stand before you today the representative of a family in grief, in a country in mourning before a world in shock.'
const splitter = new TokenTextSplitter({
chunkSize: 10, // 每块最多 10 个 token
chunkOverlap: 0, // 不需要重叠
})
const docs = await splitter.createDocuments([text])
console.log(docs)

splitDocuments(docs) —— 传 Document 对象

createDocuments(texts, metadatas?) —— 传纯字符串

注意事项: