Agent相关-文档加载器 Document Loader

0 阅读2分钟

文档加载器 Document Loader

文档加载器

一个demo

from langchain_community.document_loaders import TextLoader

DOC_PATH = "./docs/test.txt"
loader = TextLoader(DOC_PATH, encoding="utf-8")
# 读取全文
docs = loader.load()

for doc in docs:
    print("doc:",doc)

1 为什么是 list 而不是单个字符串

loader.load() 返回的是 List[Document] ,原因有三层:

① 一个文件可能拆成多个"文档块"
data/docs/test.txt  (1个文件)
        ↓ 加载
[Document(第1段), Document(第2段), Document(第3段)]  (N个Document)

比如:

  • PDF:每一页可以是一个 Document
  • CSV:每一行可以是一个 Document
  • Markdown:按标题层级切分成多个 Document
  • 大 txt:按 chunk size 切分
② Document 不是字符串,是带元数据的对象
Document(
    page_content="这是正文内容...",      # 真正的文本
    metadata={                          # 附加信息
        "source": "data/docs/test.txt",
        "page": 3,
        "file_type": ".txt"
    }
)

如果直接返回字符串,你就丢失了 source、page 这些溯源信息,做 RAG 时没法引用来源。

③ 统一接口:不管什么格式,输出结构一致
输入输出
1 个 txt[Document, Document, ...]
1 个 pdf[Document(page1), Document(page2), ...]
1 个 csv[Document(row1), Document(row2), ...]
1 个文件夹[所有文件的Document...]

用统一的 list 结构,下游代码不用关心源文件是什么格式。

2 docs 里到底是什么

打印出来大概长这样:

[
    Document(page_content="第一段内容...", metadata={"source": "test.txt"}),
    Document(page_content="第二段内容...", metadata={"source": "test.txt"}),
]

注意:Document 对象本身不是字符串,但可以转成字符串:

# 提取全部文本
full_text = "\n".join(doc.page_content for doc in docs)

# 看第一个文档
print(docs[0].page_content)
print(docs[0].metadata)

3 关键区分

你以为的实际的
docs = 整个文件的内容字符串docs = 一堆 Document 对象的列表
1 个文件 → 1 个结果1 个文件 → N 个 Document
内容就是纯文本内容 + 元数据

4 为什么这么设计(RAG 场景)

做检索增强生成时:

# 用户问:"test.txt 第3页讲了什么?"
# 系统需要:定位到具体 chunk + 知道它来自哪
for doc in docs:
    if doc.metadata.get("page") == 3:
        answer_context = doc.page_content   # 精确取用
        source = doc.metadata["source"]      # 精确溯源

如果 docs 只是一个巨大字符串,你没法定位、没法溯源、没法按块喂给 LLM。

5 为什么 TextLoader 加载的文档数量是 1

loader.load() 的行为取决于用的哪个 loader:

拿到一个文件
    │
    ├─ 是 PDF?   → load() 直接给 N 页 → N 个 Document
    ├─ 是 CSV?   → load() 直接给 N 行 → N 个 Document
    ├─ 是目录?   → load() 给 N 文件 → N 个 Document
    │
    └─ 是 txt / md / 纯文本? → load() → 1 个 Document(整篇)

注意:切分阶段会产生多个Document,以上只讨论加载阶段的情况。