0

AI RAG搭建教程:用本地大模型打造企业级知识库问答系统

2026.05.31 | youres | 22次围观

为什么你需要一个本地RAG系统?

我接触过不少企业,它们面临一个共同的痛点:内部文档散落在各个角落——钉钉文档、飞书云文档、本地Word文件、 wiki系统……员工想找一个信息,往往要在多个平台反复搜索,甚至还得私信问同事"那个XXX的文档在哪?"

市面上的RAG方案不少,但大多数要么依赖云端API(数据安全是个大问题),要么配置门槛高得离谱,搞得像我这种非算法出身的人看了就头大。经过反复折腾,我摸索出一条纯本地部署、低门槛、高可用的RAG搭建路径。今天把它完整分享出来,力求让你照着做就能跑通。

先搞清楚RAG到底是什么

RAG(Retrieval-Augmented Generation,检索增强生成)说人话就是:先从你的知识库里找到相关内容,再让大模型基于这些内容来回答问题。这解决了纯大模型的两个致命缺陷:

  • 幻觉问题:大模型不知道你的内部信息,容易编造答案
  • 知识过时:模型训练数据有截止日期,不会自动更新

打个比方——如果你让一个聪明的实习生来回答客户问题,RAG就相当于让他先去翻阅公司文档,然后再回答。而不是让他凭"印象"瞎说。

核心架构:三步走通RAG

不管用什么工具框架,RAG的核心流程就三步:

文档输入 → 向量化存储 → 检索+生成
阶段做什么关键工具
文档处理把PDF/Word/HTML解析为纯文本,切成小块LangChain + Unstructured / PyMuPDF
向量化嵌入把文本块转成向量,存入向量数据库BGE-M3嵌入模型 + ChromaDB
检索生成用户提问时检索相关文本块,喂给大模型本地大模型(Ollama)+ LangChain

第一步:环境准备——别被Python环境搞崩溃

先说一句实话:Python版本管理是RAG项目的第一大坑。我建议直接用Miniconda,别在系统Python上折腾。

conda create -n rag python=3.11 -y
conda activate rag
pip install langchain chromadb sentence-transformers pymupdf unstructured

这里有一个容易忽略的细节:unstructured的安装在某些Windows环境下会失败,因为它依赖一些C库。如果遇到报错,可以改用pip install unstructured[all-docs],或者干脆只装pymupdf处理PDF——对大多数场景够用了。

接下来安装本地大模型运行时:

# 安装Ollama(Windows直接去官网下载安装包)
# 安装后拉取模型
ollama pull qwen2.5:7b

选择Qwen2.5的7B参数版本是有讲究的:中文能力在同类开源模型里属于第一梯队,7B大小在8GB内存的机器上就能跑,性价比很高。

第二步:文档解析与向量化

这是很多人折戟的地方。文档解析的质量直接决定了RAG的最终效果——垃圾进,垃圾出

拿PDF来说,不要直接把整个文档文本一股脑塞进去。关键技巧是语义分块:按段落或章节来切分,而不是机械地按固定字数切割。

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader

# 加载PDF
loader = PyMuPDFLoader("企业手册.pdf")
pages = loader.load()

# 语义分块:按段落切分,保留上下文重叠
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100,
    separators=["

", "
", "。", "!", "?", ";"]
)
chunks = splitter.split_documents(pages)
print(f"切分完成,共 {len(chunks)} 个文本块")

注意chunk_overlap=100这个参数——它让相邻文本块有100个字符的重叠,这样检索时不会因为信息恰好被切在块边界而遗漏。

向量化我用的是BGE-M3(BAAI General Embedding Model),它是目前中文效果最好的开源嵌入模型之一:

from langchain_community.embeddings import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-m3",
    encode_kwargs={"normalize_embeddings": True}
)

# 存入ChromaDB
from langchain_community.vectorstores import Chroma
vectordb = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

ChromaDB是一个轻量级向量数据库,数据直接存在本地文件夹里,不需要额外部署服务。对于企业内部几十GB的知识库规模,完全够用。

第三步:搭建问答检索链

有了向量数据库,接下来就是构建检索链——用户提问时自动找到最相关的文本片段,交给大模型生成回答。

from langchain_community.llms import Ollama
from langchain.chains import RetrievalQA

# 连接本地Ollama模型
llm = Ollama(model="qwen2.5:7b", temperature=0.3)

# 构建检索问答链
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # 把所有检索到的块拼在一起
    retriever=vectordb.as_retriever(search_kwargs={"k": 5}),
    return_source_documents=True
)

# 测试问答
result = qa_chain({"query": "员工年假怎么算?"})
print(result['result'])

search_kwargs={"k": 5}表示每次检索返回最相关的5个文本块。在实际使用中,我建议这个值设为3-8之间——太少了可能遗漏关键信息,太多了反而会引入噪音降低回答质量。

进阶优化:从"能用"到"好用"

上面的代码已经能跑通基本流程,但在实际生产中,你会发现几个常见问题:

1. 检索不精准怎么办?

单一向量检索有个固有缺陷:它擅长语义相似性匹配,但不擅长精确匹配。比如用户问"第23条规定的报销标准是什么",向量检索可能找不到。解决方案是加入混合检索(Hybrid Search):

from langchain.retrievers import BM25Retriever, EnsembleRetriever

# BM25关键词检索
bm25 = BM25Retriever.from_documents(chunks)
bm25.k = 5

# 向量语义检索
vector_retriever = vectordb.as_retriever(search_kwargs={"k": 5})

# 混合检索:融合关键词+语义
ensemble = EnsembleRetriever(
    retrievers=[bm25, vector_retriever],
    weights=[0.4, 0.6]
)

权重比例[0.4, 0.6]意味着40%权重给关键词检索,60%给语义检索。对中文场景这个比例通常效果不错,但建议根据你的实际数据调整。

2. 引用来源很重要

企业场景中,用户往往需要知道"这个答案来自哪份文档的哪一页"。我在系统中加入了来源追溯:

def ask_with_sources(query):
    result = qa_chain({"query": query})
    answer = result['result']
    sources = []
    for doc in result['source_documents']:
        sources.append({
            "来源": doc.metadata.get('source', '未知'),
            "页码": doc.metadata.get('page', '未知'),
            "相关片段": doc.page_content[:200] + "..."
        })
    return {"回答": answer, "引用来源": sources}

这个小功能看似简单,但对企业用户来说价值巨大——它让AI回答从"值得怀疑"变成了"可溯源、可验证"。

3. 处理表格和图片

很多企业文档里包含大量表格(如报价单、规格表),纯文本解析会丢失结构化信息。我的处理方式是:

  • 表格:用camelotpdfplumber提取为Markdown表格格式,再分块存储
  • 图片:用多模态大模型(如Qwen-VL)提取图片中的文字信息,转成文本描述后存储
  • 混合内容:手动标记每块的类型(文本/表格/图片描述),检索时可以根据问题类型加权

性能优化实战数据

在我实测的企业知识库场景中(约2000份PDF,总计约800MB文本),各环节性能如下:

指标数据优化备注
向量化速度~1200块/分钟(RTX 3060)CPU-only约400块/分钟
向量库大小约1.2GB800MB原始文本 → 1.2GB向量
检索延迟50-150msChromaDB本地查询,无需网络
生成延迟2-8秒(7B模型)取决于回答长度
GPU显存占用约6GB模型+向量库常驻内存

如果你没有GPU,纯CPU环境下生成延迟会增加到10-30秒,但在企业内部场景(非实时客服)中,大多数用户是可以接受的。

常见踩坑与解决方案

最后分享几个我在实际搭建中遇到的坑:

  • PDF解析乱码:部分扫描件PDF用PyMuPDF提取出来是空白。改用OCR方案(如PaddleOCR)先识别再切分。
  • 中文分块不理想:默认的英文分隔符对中文不友好。一定要在separators参数中加上中文标点。
  • 回答过于啰嗦:调低大模型的temperature(建议0.1-0.3),并在Prompt中明确要求"简洁回答"。
  • ChromaDB查询变慢:当文档超过5000份时,考虑切换到Milvus或Qdrant这类生产级向量数据库。

总结

RAG不是什么黑魔法,本质上就是好的文档处理 + 合适的嵌入模型 + 靠谱的大模型三个环节的有机组合。最难的部分往往不在代码,而在对文档质量和分块策略的理解。

如果你正在考虑给企业搭一套知识库问答系统,建议先用几十份核心文档做个MVP验证效果,再逐步扩展。别一上来就搞几千份文档——调试的效率会低很多。

相关阅读:AI OCR图片文字识别免安装教程 | AI部署实战教程:从零开始搭建生产级环境 | AI Agent自动化处理Excel表格实战教程

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论