项目目标
构建一个能够理解企业内部文档(PDF、Word、TXT等),支持自然语言提问,并能进行多轮上下文对话的智能助手。
核心依赖
bash
# 安装核心库
# pip install langchain langchain-openai chromadb pypdf unstructured python-dotenv
第一步:文档加载与预处理
这是RAG的起点。我们需要把非结构化的文档转化为向量数据库能理解的"文本块"。
ini
import os
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载文档目录
def load_documents(directory: str):
loader = DirectoryLoader(directory, glob="**/*.*")
documents = loader.load()
return documents
# 分割文本(避免超出模型上下文)
def split_documents(documents, chunk_size=1000, chunk_overlap=200):
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=len
)
return text_splitter.split_documents(documents)
# 示例调用
docs = load_documents("./data/knowledge_base/")
chunks = split_documents(docs)
print(f"共加载并分割出 {len(chunks)} 个文本块")
第二步:向量化与向量存储
将文本块转化为向量,并存入向量数据库(这里使用ChromaDB)。
ini
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
import os
from dotenv import load_dotenv
load_dotenv()
# 初始化嵌入模型(使用OpenAI)
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
# 创建向量数据库
def create_vector_db(chunks, persist_directory="chroma_db"):
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory=persist_directory
)
vectorstore.persist()
return vectorstore
# 创建或加载向量库
vector_db = create_vector_db(chunks)
第三步:基础检索问答
实现最简单的"提问-检索-生成"流程。
python
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
# 初始化大模型
llm = ChatOpenAI(
model_name="gpt-3.5-turbo",
temperature=0,
openai_api_key=os.getenv("OPENAI_API_KEY")
)
# 创建检索问答链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vector_db.as_retriever(search_kwargs={"k": 3}), # 返回3个最相关片段
return_source_documents=True
)
# 简单问答
def ask_question(question: str):
result = qa_chain.invoke({"query": question})
print(f"问题: {question}")
print(f"回答: {result['result']}")
print("\n参考资料:")
for i, doc in enumerate(result["source_documents"]):
print(f" [{i+1}] {doc.metadata['source']} (页码: {doc.metadata.get('page', 'N/A')})")
return result
# 测试
ask_question("我们公司的数据安全政策是什么?")
第四步:多轮对话优化(关键!)
基础问答缺乏上下文记忆。真实场景中,用户会追问:"那具体怎么操作?" 这需要对话记忆。
python
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
# 添加对话记忆
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
# 创建支持对话的检索链
conversational_chain = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=vector_db.as_retriever(),
memory=memory
)
# 支持多轮对话的函数
def chat(query: str):
result = conversational_chain.invoke({"question": query})
print(f"用户: {query}")
print(f"AI: {result['answer']}")
return result['answer']
# 多轮对话示例
chat("介绍一下我们的产品线")
chat("其中哪个产品最适合中小企业?") # AI能理解"其中"指代上文的产品线
chat("它的价格是多少?") # AI继续关联上下文
第五步:优化检索质量(进阶)
默认的关键词检索可能不够精准。我们可以使用"自查询检索器"提升语义理解能力。
ini
from langchain.retrievers import SelfQueryRetriever
from langchain.chains.query_constructor.schema import AttributeInfo
# 定义元数据信息(帮助AI理解如何过滤)
metadata_field_info = [
AttributeInfo(
name="source",
description="文档来源文件名",
type="string",
),
AttributeInfo(
name="page",
description="页码",
type="integer",
),
]
document_content_description = "企业内部文档内容"
# 创建自查询检索器
self_query_retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vector_db,
document_contents=document_content_description,
metadata_field_info=metadata_field_info,
enable_limit=True # 支持LIMIT语法
)
# 替换原有检索器
conversational_chain.retriever = self_query_retriever
# 现在可以处理更复杂的查询
chat("在员工手册第5页提到了什么福利政策?")
总结:为什么这套流程值得掌握?
- 真实可用:这不是玩具,而是能直接部署到企业内部的知识助手。
- 全链路覆盖:从数据加载、向量化、检索、生成到对话记忆,一气呵成。
- 可扩展性强:可轻松替换为私有化部署的Embedding模型(如bge)、向量库(如Milvus)、大模型(如Llama 3)。
- 成本可控:相比纯大模型微调,RAG成本极低,且知识更新方便。
作为一名程序员,我越来越相信:未来的"编程",不再是写一堆if-else,而是设计智能的"信息流转管道" 。LangChain + RAG 正是构建这类管道的利器。掌握它,你不仅是在学一个框架,更是在掌握一种面向AI时代的新型软件架构思维。
项目完整源码已上传至GitHub :
https://github.com/yourname/langchain-rag-knowledge-base(包含Docker部署、FastAPI接口封装、前端交互界面)