澳八机器人 15天学会AI应用开发(十二)从PDF、WORD、网页构建RAG



前面的教程我们已经掌握了从纯文本TXT文件读取内容、搭建基础向量检索的方法,但日常办公和实际业务里,纯文本文件占比极低,大家接触更多的是PDF、Word这类标准办公文档,还有大量分布在公开网页里的行业资料。今天我们就把这三类主流数据源打通,一步步实现从多格式文件直接构建可用的RAG知识库,全程不需要依赖LangChain等重型框架,自己动手就能掌握每一个核心环节。


一、环境准备:安装三类文档解析依赖库


在开始写代码前,先在终端执行命令安装对应解析工具,不同文件格式有专门适配的高效库,比通用解析方案准确率更高:


bash

# PDF解析工具,比传统PyPDF2更擅长处理复杂排版

pip install pdfplumber

# Word文档解析工具,专门处理docx格式办公文件

pip install python-docx

# 网页正文提取工具,自动剔除广告、导航栏等冗余内容

pip install trafilatura

# 网页请求基础库

pip install requests

# 向量模型和向量检索依赖

pip install sentence-transformers faiss-cpu numpy



所有依赖都适配Python 3.8及以上版本,安装完成后就可以开始逐个实现数据源的文本读取逻辑。


二、分格式实现文本解析


我们针对三类不同数据源分别编写解析函数,保证不同格式的内容都能被完整、干净地提取出来。


1. PDF文件解析


pdfplumber可以精准识别PDF里的文字排版、换行和表格结构,逐页读取后拼接成完整文本,还能自动过滤页眉页脚的冗余内容:


python

import pdfplumber


def extract_pdf_text(file_path):

    full_text = ""

    with pdfplumber.open(file_path) as pdf:

        for page in pdf.pages:

            # 提取单页文本,自动保留段落换行

            page_text = page.extract_text()

            if page_text:

                full_text += page_text + "\n"

    return full_text



这个方法对扫描版PDF无效,如果是扫描件需要先搭配OCR工具完成文字识别,再接入后续流程。


2. Word文档解析


通过python-docx直接读取docx文件的所有段落文本,同时可以扩展支持读取表格内容,适配绝大多数办公场景的Word文档:


python

from docx import Document


def extract_docx_text(file_path):

    doc = Document(file_path)

    full_text = []

    # 读取所有普通段落

    for para in doc.paragraphs:

        if para.text.strip():

            full_text.append(para.text)

    # 可选:读取表格内容,适合财报、数据类文档

    for table in doc.tables:

        for row in table.rows:

            row_text = " | ".join([cell.text for cell in row.cells])

            full_text.append(row_text)

    return "\n".join(full_text)



注意这个方案仅支持docx格式,老旧的doc格式需要先转成docx再处理,避免解析失败。


3. 网页内容解析


直接用requests爬取网页源码后,通过trafilatura自动提取纯净正文,自动剔除侧边栏、广告、无关链接等噪音内容,比传统BeautifulSoup解析更省心:


python

import requests

import trafilatura


def extract_webpage_text(url):

    headers = {

        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

    }

    resp = requests.get(url, headers=headers, timeout=10)

    resp.encoding = "utf-8"

    # 自动提取正文,返回干净的纯文本

    clean_text = trafilatura.extract(resp.text)

    return clean_text if clean_text else "网页内容提取失败"



这个方法对绝大多数静态资讯网页适配效果很好,动态渲染的网页需要搭配Selenium等工具先完成页面加载。


三、统一文本分块逻辑


不管是从PDF、Word还是网页拿到的长文本,都需要切分成适合向量化的小片段,我们按句号作为语义分割边界,保证每个文本块的语义完整性,避免把完整句子从中间切断:


python

def split_text(raw_text, max_chunk_len=120):

    # 先统一处理换行和多余空格

    raw_text = raw_text.replace("\n", "").strip()

    # 按中文句号分割句子

    sentences = raw_text.split("。")

    chunks = []

    current_chunk = ""

    for sen in sentences:

        sen = sen.strip()

        if not sen:

            continue

        # 补回句号保证语义完整

        sen += "。"

        if len(current_chunk) + len(sen) <= max_chunk_len:

            current_chunk += sen

        else:

            if current_chunk:

                chunks.append(current_chunk.strip())

            current_chunk = sen

    # 加入最后剩余的片段

    if current_chunk:

        chunks.append(current_chunk.strip())

    return chunks



这里的max_chunk_len可以根据你使用的Embedding模型上下文长度调整,中文场景下100-200字是比较稳妥的选择。


四、整合构建完整RAG检索流程


把前面的解析、分块逻辑和向量模型、FAISS向量库结合起来,就可以直接实现一个支持多数据源的轻量RAG系统:


python

from sentence_transformers import SentenceTransformer

import faiss

import numpy as np


# 1. 加载中文Embedding模型,这里用bge-small-zh-v1.5,效果轻量且精准

embed_model = SentenceTransformer("./bge-small-zh-v1.5", device="cpu")


# 2. 示例:从医保局公开网页构建知识库,也可以替换成本地PDF/Word路径

target_url = "https://www.nhsa.gov.cn/art/2025/12/25/art_14_19130.html"

raw_knowledge = extract_webpage_text(target_url)

# 也可以替换成本地文件读取:

# raw_knowledge = extract_pdf_text("政策文件.pdf")

# raw_knowledge = extract_docx_text("内部培训资料.docx")


# 3. 文本分块

knowledge_chunks = split_text(raw_knowledge)


# 4. 生成向量并构建FAISS索引

vectors = embed_model.encode(knowledge_chunks, normalize_embeddings=True)

vector_dim = vectors.shape

index = faiss.IndexFlatIP(vector_dim)

index.add(np.array(vectors).astype("float32"))


# 5. 实现检索函数

def rag_query(user_query, top_k=3):

    query_vec = embed_model.encode([user_query], normalize_embeddings=True)

    scores, indices = index.search(np.array(query_vec).astype("float32"), top_k)

    # 返回最相关的文本片段和对应相似度得分

    return [

        {"content": knowledge_chunks[idx], "score": float(scores[i])}

        for i, idx in enumerate(indices)

    ]


# 测试:输入问题即可拿到相关知识库片段

result = rag_query("2025年医保报销的新规则是什么?")

for item in result:

    print(f"相似度:{item['score']:.2f} 内容:{item['content']}")


五、实战优化小技巧

不同数据源可以给文本块打上来源元数据,比如标记是来自PDF第几页、哪个网页链接,后续回答时可以直接标注信息来源,方便用户溯源。

网页爬取时要遵守目标网站的robots协议,控制请求频率避免给对方服务器造成压力。

如果是大量文档批量构建知识库,可以把生成好的FAISS索引和文本块持久化保存到本地,下次启动直接加载,不用重复向量化节省时间。


到这里你就已经掌握了从三类最常用数据源搭建RAG的完整流程,没有黑盒框架的遮挡,每一步文本怎么来、怎么切、怎么转成向量都完全可控,后续遇到检索不准的问题,你可以直接从解析、分块、向量化三个环节逐一排查,不用再对着框架的黑盒参数盲目调试。


需要我为你补充‌多文件批量导入的完整代码‌吗?这样你可以一次性把整个文件夹的PDF、Word文件全部导入RAG知识库。