【RAG搭建纯干货】从零手搓本地知识库(第一篇):数据清洗流水线搭建指南

本系列文章将手把手带你搭建本地知识库,满满的干货分你想,保证代码完美跑通,系列文章结束将共享最终实践交付代码,敬请期待。

导读:为什么你接入大模型后,它总是胡说八道?因为"Garbage In, Garbage Out"。这是《从零构建个人知识库》系列的第一篇,我们将彻底抛弃昂贵的云端 SaaS,在纯 CPU 环境下,用新版 LangChain 搭建一条工业级的本地文档加载与清洗流水线。跟着本文敲完代码,你的私有化 RAG 项目就迈出了最坚实的第一步。

为什么我们必须自建本地知识库?

在动手之前,我们需要明确两个核心痛点:

  1. 大模型幻觉:通用大模型不知道你的公司规章、私人笔记或最新论文。把整本书塞进 Prompt 不仅超出上下文限制,还会导致模型"注意力分散",产生严重幻觉。
  2. 隐私与成本焦虑:将核心数据上传至第三方 API 存在极大的合规风险;而长期调用商业 Embedding 和解析接口,费用是个无底洞。

我们的解法:全程本地化、开源化、CPU 可运行。今天,我们先解决"如何把非结构化文档变成干净文本"的问题。

第一步:配置极简 CPU 开发环境

新版 LangChain 已经彻底模块化,我们不再需要安装臃肿的单体包。针对纯 CPU 环境,请在终端执行以下精简安装命令:

bash 复制代码
# 创建并激活虚拟环境 (强烈建议)
python -m venv .venv && source .venv/bin/activate # Windows使用: .venv\Scripts\activate

# 安装新版LangChain核心组件、文本分割器及HuggingFace集成包
pip install langchain-core langchain-community langchain-text-splitters langchain-huggingface

# 安装轻量级文档解析库及其底层依赖
pip install unstructured pypdf sentence-transformers

避坑提示Unstructured 功能强大但依赖复杂。对于个人知识库,我们仅安装 [md] 等基础解析器即可。如果后续需要解析复杂的扫描件 PDF,再考虑安装 unstructured[all-docs] 或使用更轻量的 PyMuPDF (fitz) 作为备选。

第二步:多格式文档加载器实战

在新版 LangChain 中,文档加载器被统一归入了 langchain_community.document_loaders。我们来编写一个自动识别文件后缀并加载的工厂函数。

在项目根目录创建 src/loaders.py

python 复制代码
import os
from typing import List
from langchain_core.documents import Document

# 采用社区标准的加载器工厂方法,兼容性最好
from langchain_community.document_loaders import TextLoader, PyPDFLoader

try:
    from langchain_community.document_loaders import UnstructuredMarkdownLoader
except ImportError:
    UnstructuredMarkdownLoader = None
    print("未找到UnstructuredMarkdownLoader,请确保已安装 unstructured")


class LocalDocLoader:
    """本地文档加载器,支持 TXT, MD, PDF"""

    LOADER_MAPPING = {
        ".txt": TextLoader,
        ".md": UnstructuredMarkdownLoader,
        ".pdf": PyPDFLoader,
    }

    @classmethod
    def load(cls, file_path: str) -> List[Document]:
        ext = os.path.splitext(file_path)[-1].lower()
        if ext not in cls.LOADER_MAPPING:
            raise ValueError(f"暂不支持的文件格式: {ext}")

        loader_class = cls.LOADER_MAPPING[ext]

        if ext == ".pdf":
            loader = loader_class(file_path)
        else:
            loader = loader_class(file_path, encoding="utf-8")

        print(f"正在加载: {os.path.basename(file_path)}")
        return loader.load()

第三步:文本清洗------RAG 质量的隐形护城河

很多新手做完加载就直接去切片向量化,结果检索出来的全是页眉、页脚和乱码。清洗比加载更重要!

我们使用 Python 原生正则表达式进行轻量级清洗,无需额外依赖。在项目根目录创建 src/cleaner.py

python 复制代码
import re
from typing import List
from langchain_core.documents import Document


def clean_documents(docs: List[Document]) -> List[Document]:
    """
    基础文本清洗流水线
    1. 去除多余空白符与换行
    2. 清除常见PDF页眉页脚特征
    3. 过滤无效短文本
    """
    cleaned_docs = []

    for doc in docs:
        text = doc.page_content

        # 1. 将连续的换行和空格替换为单个空格
        text = re.sub(r'\s+', ' ', text).strip()

        # 2. 去除类似 "第X页"、"Page X" 的页码残留
        text = re.sub(r'(第\s*\d+\s*页|Page\s*\d+)', '', text)

        # 3. 去除特殊控制字符和乱码
        text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f]', '', text)

        # 4. 过滤掉清洗后过短的无效片段 (如纯目录项)
        if len(text) > 50:
            doc.page_content = text
            cleaned_docs.append(doc)

    print(f"清洗完成: 原始 {len(docs)} 个片段 -> 有效 {len(cleaned_docs)} 个片段")
    return cleaned_docs

第四步:串联流水线,跑通第一个测试

现在,让我们把加载和清洗串联起来,验证整个流水线。

创建 main.py 进行测试:

python 复制代码
from src.loaders import LocalDocLoader
from src.cleaner import clean_documents

if __name__ == "__main__":
    # 请在此处替换为你本地的真实文件路径
    test_files = [
        "./data/test_doc.md",
        "./data/manual.pdf"
    ]

    all_docs = []
    for path in test_files:
        try:
            docs = LocalDocLoader.load(path)
            all_docs.extend(docs)
        except Exception as e:
            print(f"加载失败 [{path}]: {e}")

    # 执行清洗
    final_docs = clean_documents(all_docs)

    # 打印第一个有效片段验证效果
    if final_docs:
        print("\n--- 清洗后的首个文档片段预览 ---")
        print(final_docs[0].page_content[:300])
        print(f"\n元数据保留完整: {final_docs[0].metadata}")

运行 python main.py,如果你能看到干净的文本输出以及包含 sourcepage 等信息的 metadata,恭喜你!你的本地知识库数据基石已经牢牢打下。

预期运行结果

当你运行这段代码时,控制台会输出类似以下内容(取决于你的文档内容):

text 复制代码
✅ 正在加载: test_doc.md
✅ 正在加载: manual.pdf
🧹 清洗完成: 原始 4 个片段 -> 有效 3 个片段

--- 清洗后的首个文档片段预览 ---
一、 榜单说话:56.6分背后的含金量 在Artificial Analysis最新公布的全球大模型综合榜单中,Qwen3.7-Max以56.6分的成绩位列全球第五、国产第一。 这个分数意味着什么?它标志着国产模型已经跨越了"可用"到"好用"的鸿沟,正式进入全球顶级模型的"俱乐部"。不同于以往部分榜单的自说自话,Artificial Analysis以其严苛的工程化评测标准著称。Qwen3.7-Max能在该榜单中脱颖而出,说明其在实际应用场景中的综合能力(而非单纯的刷题能力)得到了国际认可。 更令技术圈振奋的是其在垂直领域的突破: Terminal Bench 2.0-Terminus(编程智

📊 元数据保留完整: {'source': './data/test_doc.md'}

进程已结束,退出代码为 0

系列预告 这是《从零构建个人知识库》系列的第一篇,下一篇我将详细讲解如何用新版 LangChain LCEL 语法实现语义切片,并在纯 CPU 环境下完成极速向量化。点击关注,更新时第一时间收到通知,带你一步步把这个项目真正跑在你的电脑上!

**

关注后续系列文章更新

**

相关推荐
这是谁的博客?4 小时前
LangChain 框架深度解析:从 LCEL 到 Agent 架构的核心原理
ai·架构·langchain·llm·agent·架构设计
后端小肥肠5 小时前
文章没人看?多半是标题的锅:我用 Codex + Obsidian 做了个爆款标题 Skill
人工智能·aigc·agent
一个处女座的程序猿6 小时前
Agent之Hermes:Hermes Agent的简介、安装和使用方法、案例应用之详细攻略
agent·hermes
MomentYY7 小时前
第 5 篇:Agent 记不住事?补上 Memory + RAG 检索
前端·python·agent
蓝桉~MLGT7 小时前
Ai-Agent学习历程—— 阶段2——LangChain Core(基本调用、tools、简单上下文等)
学习·大模型·agent
rannn_1119 小时前
从 Function Calling 到 Tool Use:三大 LLM Agent 工具调用机制原理与设计对比
python·ai·agent·开发
元思未来9 小时前
Hermes Agent 源码探秘 (7):记忆与技能 — Agent 的"学习"能力
agent·源码阅读
宋哥转AI9 小时前
【Spring AI Graph:从0到Supervisor·预告】动手之前,先定好3个架构决策
java·agent