[LangChian] 13. 文本切割

为什么需要切割?

回忆一下 RAG 的流程:

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

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

快速上手

如何切割?

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

import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 64,
  chunkOverlap: 0,
});
  • chunkSize:每块的最大长度
  • chunkOverlap:块之间的重叠长度

在线的 可视化工具,可以快速看到不同 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);

其它类型切割器

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

  • 📄 Markdown 教案
  • 🌐 HTML 页面
  • 🧑‍💻 JS/Python 代码片段
  • 🧾 LaTeX 报告
  • 📚 跨语言 API 文档……

LangChain 中提供了不同的切割器

Splitter 名称 适用文档类型 切分策略说明
RecursiveCharacterTextSplitter 普通文本(小说、说明) 默认最常用,按字符层级递进切分
MarkdownTextSplitter Markdown 文件 根据标题层级(#、## 等)结构来切
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", {...})

  • 切割逻辑:在 chunkSizechunkOverlap 基础上,会根据指定语言(这里是 "js")注入专门的分隔符表。

  • JS 例子:

    • 优先按函数或类定义等结构分割(function / class 等关键字周围)

    • 再按语句结束符(;)分割

    • 再按换行符、空格等兜底分割

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

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 对象

  • 输入:必须是 LangChain 的 Document 实例数组(形如 { pageContent, metadata })。
  • 作用:
    • 会保留原来的 metadata
    • 切割完的每个 chunk 也会带上对应的 metadata
  • 常见用法:用 loader 加载了文档(TextLoader, PDFLoader 等),直接把 docs 交给它切。

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

  • 输入:纯文本数组(string[]),可选 metadata[]
  • 作用:
    • 先把字符串封装成 Document 对象
    • 再按规则切割成多个小的 Document
  • 常见用法:你手里没有现成的 Document 对象,只有一段文本(比如从接口返回的字符串),需要直接切成 LangChain 能用的 Document[]

注意事项:

  • TokenTextSplitter 不会“考虑语言结构”!它只按 token 数硬切。
  • 切出来的块有可能把一个句子、段落、甚至一个词给切断。
  • 它默认使用的 tokenizer 是 Tiktoken(适配 OpenAI 模型),如果是其他模型,可能 token 数会略有差异。

-EOF-

posted @ 2025-11-06 15:07  Zhentiw  阅读(14)  评论(0)    收藏  举报