[LangChain] 11. 本地资源Loader

很多时候,我们需要加载额外的数据,比如 RAG 架构中,需要外挂知识库。

外部数据的形式千差万别:可能是一份 PDF 文件、一张表格、一段代码,甚至是来自网络的实时信息。针对这些需求,LangChain 提供了一整套开箱即用的 Loader 工具,帮助我们高效地加载各种结构化或非结构化的数据,并统一转换成 LLM 能够理解和处理的格式。

Document对象

在 LangChain 中,无论你的数据来自哪里——文本文件、数据库、网页还是 GitHub 项目,最终都会被封装成一种统一的数据结构 Document 对象。

好处:LangChain 的后续模块(如向量化、检索器、分片器等)不需要关心你的数据来源,只需要对 Document 进行处理即可。

一个 Document 对象由两个部分构成:

interface Document {
  pageContent: string;             // 文本内容,表示这段文档的主体内容
  metadata: Record<string, any>;   // 元数据,附加的上下文信息,如来源、页码、标题等
}

手动创建一个 Document 对象示例:

import { Document } from "@langchain/core/documents";

const doc = new Document({
  pageContent: "这是一段测试文字",
  metadata: {
    source: "abc",
  },
});

console.log(doc)

效果:

Document {
  pageContent: '这是一段测试文字',
  metadata: { source: 'abc' },
  id: undefined
}

真实项目中,更多是通过 Loader 工具读取外部资源,然后封装成一组 Document 实例。

Loader 的种类很多:

  1. 本地资源Loader
  2. Web资源Loader

文本Loader

文本Loader位于langchain包下面

pnpm add langchain

用来加载纯文本文件的 Loader,适合处理 .txt 类型的文件。

示例代码:

import { TextLoader } from "@langchain/classic/document_loaders/fs/text";

const res = await new TextLoader("test.txt").load();

console.log(res);

效果:

[
  Document {
    pageContent: '这是一段测试文本,啦啦啦啦',
    metadata: { source: 'data/test.txt' },
    id: undefined
  }
]

🤔这里返回的是一个数组,数组里面又只有一项。那什么时候数组里面有多项呢?

  1. 读取一个目录中的多个文件

  2. 一个文件很长,设置了文本切割。

import { TextLoader } from "@langchain/classic/document_loaders/fs/text";
import { RecursiveCharacterTextSplitter } from "@langchain/classic/text_splitter";

const res = await new TextLoader("test.txt").load();

const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 100,
  chunkOverlap: 20,
}).splitDocuments(res);

const splitRes = splitter.splitDocuments(res);

console.log(splitRes);

PDFLoader

PDF 文件是许多知识密集型场景中的常见数据源。在 LangChain 中,可以使用 PDFLoader 来方便地读取 PDF 文件内容,并将其转换为标准的 Document 对象。

它的默认行为是:将 PDF 每一页内容都拆成一个独立的 Document 对象。

安装依赖:

pnpm add @langchain/community pdf-parse

示例代码:

import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";

const loader = new PDFLoader("data/novel.pdf", {
  splitPages: false,
});

const result = await loader.load();

console.log(result);

如果你希望一次性读取整个 PDF 的所有页,而不是拆分成每页一个 Document,可以通过设置 splitPages: false 来关闭分页行为:

const loader = new PDFLoader("data/bananaphone.pdf", {
  splitPages: false,
});

目录Loader

在实际项目中,数据通常不是孤零零存在,而是统一放在一个文件夹中、由多种格式的文件组成(比如:.txt.pdf.md 等等)。这时逐个调用对应的 Loader,会非常麻烦。

LangChain.js 为我们提供了一个统一入口 —— DirectoryLoader,可以自动识别目录中不同类型的文件,并调用对应的 Loader 执行加载任务。

DirectoryLoader 接收两个参数:

  • 第一个参数:要加载的文件夹路径
  • 第二个参数:一个对象,键是文件后缀名,值是对应的 Loader 工厂函数

每种类型的文件会自动使用我们配置的 Loader 进行处理。返回结果是一个 Document[] 数组,每个元素代表一个文档对象。

import { DirectoryLoader } from "@langchain/classic/document_loaders/fs/directory";
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
import { TextLoader } from "@langchain/classic/document_loaders/fs/text";

const loader = new DirectoryLoader("./data", {
  ".pdf": (path) => new PDFLoader(path, { splitPages: false }),
  ".txt": (path) => new TextLoader(path),
});

const result = await loader.load();
console.log(result);

最佳实践

使用场景 是否适合使用 DirectoryLoader
加载同类型文件(比如全是 .txt) ❌ 推荐直接用 TextLoader,效率更高
加载多类型文件(pdf / txt / md 混合) ✅ 推荐使用 DirectoryLoader 批量处理
加载小规模单个文档 ❌ 不推荐使用 DirectoryLoader,配置成本不划算
大型知识库统一导入 ✅ 非常推荐,可结合向量化批处理

支持的 Loader 类型

除了示例中用到的 .txt.pdf,你还可以按需加载:

  • .md:使用 TextLoader 加载 Markdown 文件
  • .csv:使用 CSVLoader(来自 fs/csv)加载结构化数据
  • .json:使用 JSONLoader 按 key 提取文本内容
  • .docx:使用 DocxLoader 处理 Word 文档

几乎所有支持的 Loader 都可以配合 DirectoryLoader 使用,只需要在映射对象中正确配置后缀名和构造器即可。

文档地址:https://v03.api.js.langchain.com/classes/langchain.document_loaders_fs_json.JSONLoader.html


-EOF-

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