如何使用 Python + LangChain 构建基于 LLM 的本地知识库问答系统

# 如何使用 Python + LangChain 构建基于 LLM 的本地知识库问答系统

## 背景介绍

很多公司都有大量的内部文档:技术手册、FAQ、产品说明之类的。问题是,用传统关键词搜索来查这些资料,效果通常不怎么样。用户搜”电脑开不了机”,系统可能返回”显示器不显示”——虽然有点关系,但不完全是一回事。

大语言模型出现以后,情况变了。RAG(检索增强生成)这个架构,能让 AI 在回答问题之前先从你的知识库里查相关资料,然后把查到的内容和问题一起发给 LLM,让 AI 基于真实文档来生成答案。这样既保留了 LLM 的语言能力,又解决了它”胡编乱造”的问题,还能让它学到你的私有知识。

LangChain 是现在最火的 LLM 开发框架,封装了各种工具,做 RAG 系统特别方便。这篇文章就手把手教你怎么用 Python、LangChain、开源 Embedding 模型和向量数据库,在本地搭一个完整的知识库问答系统。

## 问题描述

实际落地的时候,有几个坑需要填:

**数据安全**——很多公司的文档是敏感的,不能传上云。必须整个系统跑在本地,所有数据不出门。

**检索不准**——关键词匹配解决不了同义词、多义词的问题。用户说”打印机不工作”,你得能返回”复印机故障”相关内容。

**答案可信度**——直接让 LLM 回答专业问题,它可能会瞎编。通过 RAG 架构,让它根据你的文档来回答,就能避免这个问题。

**成本**——用 OpenAI API 方便是方便,但量大起来费用惊人。得支持本地部署的开源模型。

## 详细步骤

整个系统搭建分这几步:

**环境准备**

Python 3.8 以上,装一堆包:langchain、langchain-community、sentence-transformers、chromadb、pypdf。具体命令如下:

“`bash
pip install langchain langchain-community langchain-openai \
sentence-transformers chromadb pypdf
“`

**文档加载与预处理**

LangChain 带的加载器支持 PDF、Word、Markdown、TXT 各种格式。加载完了要把长文档切成小块——这个叫文本分块(Text Chunking)。一般设 chunk_size=500、chunk_overlap=50。分块大小很关键,太大了检索不精准,太小了上下文不够。

**文本向量化和存储**

用预训练的中文 Sentence Transformer 模型(shibing624/text2vec-base-chinese)把文本块变成向量,然后存到 ChromaDB 里。ChromaDB 是个轻量级向量数据库,直接存本地文件,很适合本地部署。

**构建检索和问答链**

用 LangChain 的 RetrievalQA 链把检索和 LLM 连起来。用户问问题 → 检索器从向量数据库找相关文档 → 把问题和文档一起发给 LLM → LLM 生成答案。

**LLM 选择**

可以用本地部署的开源模型(Qwen、ChatGLM 之类的),也可以用 OpenAI API。后面示例用 OpenAI,但换成开源模型只需要改几行配置。

## 完整代码示例

下面是完整代码,直接能跑:

“`python
# 导入必要的库
import os
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA

# 配置 OpenAI API(请替换为您的实际 API Key)
os.environ[“OPENAI_API_KEY”] = “your-api-key-here”

class LocalKnowledgeBaseQA:
def __init__(self, pdf_path: str, persist_directory: str = “./chroma_db”):
self.pdf_path = pdf_path
self.persist_directory = persist_directory
self.embeddings = None
self.vectorstore = None
self.qa_chain = None

def load_documents(self):
“””加载 PDF 文档”””
print(“正在加载文档…”)
loader = PyPDFLoader(self.pdf_path)
documents = loader.load()
print(f”成功加载 {len(documents)} 页文档”)
return documents

def split_documents(self, documents):
“””将文档分割成文本块”””
print(“正在分割文档…”)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
length_function=len,
)
texts = text_splitter.split_documents(documents)
print(f”分割完成,共 {len(texts)} 个文本块”)
return texts

def create_vectorstore(self, texts):
“””创建向量数据库”””
print(“正在创建向量数据库…”)
# 使用中文 Embedding 模型
self.embeddings = HuggingFaceEmbeddings(
model_name=”shibing624/text2vec-base-chinese”,
model_kwargs={‘device’: ‘cpu’}
)

# 检查是否已有持久化的向量数据库
if os.path.exists(self.persist_directory):
print(“加载已有向量数据库…”)
self.vectorstore = Chroma(
persist_directory=self.persist_directory,
embedding_function=self.embeddings
)
else:
print(“创建新的向量数据库…”)
self.vectorstore = Chroma.from_documents(
documents=texts,
embedding=self.embeddings,
persist_directory=self.persist_directory
)
print(“向量数据库创建完成”)
return self.vectorstore

def setup_qa_chain(self):
“””设置问答链”””
print(“正在初始化 LLM 和问答链…”)

# 初始化 LLM
llm = ChatOpenAI(
model_name=”gpt-3.5-turbo”,
temperature=0,
openai_api_key=os.environ[“OPENAI_API_KEY”]
)

# 创建检索器
retriever = self.vectorstore.as_retriever(
search_type=”similarity”,
search_kwargs={“k”: 3}
)

# 创建 RetrievalQA 链
self.qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type=”stuff”,
retriever=retriever,
return_source_documents=True
)
print(“问答系统初始化完成”)

def initialize(self):
“””初始化整个系统”””
documents = self.load_documents()
texts = self.split_documents(documents)
self.create_vectorstore(texts)
self.setup_qa_chain()

def ask(self, question: str):
“””问答接口”””
if not self.qa_chain:
raise ValueError(“请先调用 initialize() 初始化系统”)

result = self.qa_chain.invoke({“query”: question})

return {
“answer”: result[“result”],
“source_documents”: result[“source_documents”]
}

# 使用示例
if __name__ == “__main__”:
qa_system = LocalKnowledgeBaseQA(
pdf_path=”./knowledge_base/manual.pdf”,
persist_directory=”./chroma_db”
)
qa_system.initialize()

while True:
question = input(“\n请输入您的问题(输入 q 退出):”)
if question.lower() == ‘q’:
break

result = qa_system.ask(question)

print(“\n=== 回答 ===”)
print(result[“answer”])

print(“\n=== 参考来源 ===”)
for i, doc in enumerate(result[“source_documents”], 1):
print(f”{i}. {doc.page_content[:200]}…”)
“`

## 运行结果

跑起来是这样的:

**初始化时:**
系统加载 PDF,切成小文本块,用中文模型转成向量,存到 Chroma。文档大的话这个过程要几分钟。

**问答时:**
用户提问 → 系统把问题转成向量 → 在向量库里找最像的 3 个文档块 → 把问题和这些块发给 LLM → LLM 生成答案,同时给出参考来源。

比如问”怎么重置打印机?”,系统会找出知识库里相关的操作说明,生成清晰回答,最后标明这条回答参考了哪几页文档。

## 总结

这篇文章介绍了怎么用 Python 和 LangChain 在本地搭知识库问答系统。这个方案的好处:

**安全**——全程本地处理,不用把敏感资料传上网,满足合规要求。

**灵活**——支持各种开源模型(中文用 shibing624/text2vec-base-chinese,LLM 用 Qwen 或 ChatGLM),想换就换。

**省钱**——用开源模型不用付 API 费,大规模部署也不心疼。

**可扩展**——LangChain 组件很丰富,加聊天历史、支持多文档都很容易。

把代码复制下来改改路径就能跑起来,先跑通原型,再根据自己业务需求调整。RAG 是现在 LLM 落地的标配,学会这个,你就能把 AI 能力真正用到工作里去了。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇