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

作者:袖梨 2026-07-07

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

img_6a4c559af3c6630.webp

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

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

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

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

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

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

# 创建并激活虚拟环境 (强烈建议)
python -m venv .venv && source .venv/bin/activate # Windows使用: .venvScriptsactivate# 安装新版LangChain核心组件、文本分割器及HuggingFace集成包
pip install langchain-core langchain-community langchain-text-splitters langchain-huggingface# 安装轻量级文档解析库及其底层依赖
pip install unstructured pypdf sentence-transformers

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

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

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

import os
from typing import List
from langchain_core.documents import Document# 采用社区标准的加载器工厂方法,兼容性最好
from langchain_community.document_loaders import TextLoader, PyPDFLoadertry:
    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

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*页|Pages*d+)', '', text)        # 3. 去除特殊控制字符和乱码
        text = re.sub(r'[x00-x08x0bx0cx0e-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 进行测试:

from src.loaders import LocalDocLoader
from src.cleaner import clean_documentsif __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,恭喜你!你的本地知识库数据基石已经牢牢打下。

预期运行结果

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

 正在加载: 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

img_6a4c559af3c6c31.webp **

关注后续系列文章更新

**

相关文章

精彩推荐