LangChain实战-RAG问答机器人
·
引言:RAG与LangChain的完美结合
在人工智能应用蓬勃发展的今天,如何让大语言模型(LLM)突破其知识截止日期的限制,并基于特定、私有的数据源进行精准回答,成为了一个关键挑战。检索增强生成(Retrieval-Augmented Generation, RAG)技术应运而生,它通过从外部知识库中检索相关信息来增强LLM的生成过程,从而提供更准确、更具时效性且来源可追溯的答案。
本文将带领大家使用 LangChain 这一强大的LLM应用开发框架,从零开始构建一个功能完整的RAG问答机器人。我们将涵盖从环境搭建、文档加载与处理、向量数据库构建,到检索链组装和Web界面部署的全流程。
1. 环境准备与工具安装
首先,确保你的Python环境版本在3.8以上。我们使用 pip 安装必要的依赖包。
# 创建并激活虚拟环境(可选)
python -m venv rag_env
source rag_env/bin/activate # Linux/Mac
# rag_env\Scripts\activate # Windows
# 安装核心依赖
pip install langchain langchain-community langchain-openai
# 安装文本分割与向量化相关库
pip install tiktoken sentence-transformers
# 安装向量数据库(这里以Chroma为例,轻量易用)
pip install chromadb
# 安装文档加载器(支持多种格式)
pip install pypdf unstructured
# 安装Web框架(用于构建简单界面)
pip install streamlit
关键库说明:
langchain: 核心框架,提供链、代理、检索器等高级抽象。langchain-openai: OpenAI模型集成。sentence-transformers: 用于生成文本向量的嵌入模型。chromadb: 轻量级、内存友好的向量数据库。streamlit: 快速构建数据应用的原型工具。
2. 构建知识库:文档加载与处理
RAG系统的核心是一个包含我们私有知识的向量数据库。构建它需要三个步骤:加载、分割和向量化。
2.1 加载文档
我们使用LangChain的文档加载器来读取各种格式的文件。
from langchain_community.document_loaders import PyPDFLoader, TextLoader, UnstructuredMarkdownLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 示例:加载一个PDF文件
loader = PyPDFLoader("./docs/your_knowledge_base.pdf")
documents = loader.load()
print(f"Loaded {len(documents)} pages from PDF.")
2.2 分割文本
将长文档分割成语义上连贯的“块”(chunks),以便于检索。
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个块的最大字符数
chunk_overlap=50, # 块之间的重叠字符数,保持上下文连贯
separators=["\n\n", "\n", "。", "?", "!", " ", ""] # 分割符优先级
)
chunks = text_splitter.split_documents(documents)
print(f"Split into {len(chunks)} text chunks.")
2.3 生成嵌入并存入向量数据库
我们将文本块转换为向量(嵌入),并存储到ChromaDB中。
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
# 使用开源的嵌入模型(无需API Key)
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
# 创建向量数据库
vector_db = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db" # 数据持久化目录
)
print("向量数据库构建完成!")
3. 组装RAG问答链
有了知识库,下一步是创建检索和生成的管道。LangChain的 RetrievalQA 链将此过程封装得非常简洁。
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
# 1. 初始化LLM(这里以OpenAI GPT-4为例,也可替换为其他模型)
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 2. 从持久化目录加载已构建的向量数据库
vector_db = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
# 3. 将向量数据库转换为检索器
retriever = vector_db.as_retriever(search_kwargs={"k": 4}) # 每次检索返回最相关的4个块
# 4. (可选)自定义提示模板,指导模型如何利用检索到的上下文
prompt_template = """
请根据以下上下文信息回答问题。如果上下文信息不足以回答问题,请直接说“根据提供的信息,我无法回答这个问题”,不要编造答案。
上下文:
{context}
问题:{question}
请给出专业、清晰的回答:
"""
PROMPT = PromptTemplate(
template=prompt_template, input_variables=["context", "question"]
)
# 5. 创建RAG链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 将检索到的所有文档“塞”进提示词
retriever=retriever,
chain_type_kwargs={"prompt": PROMPT}, # 使用自定义提示
return_source_documents=True # 返回用于生成答案的源文档
)
# 6. 进行问答测试
query = "LangChain中如何加载PDF文档?"
result = qa_chain.invoke({"query": query})
print(f"问题:{query}")
print(f"答案:{result['result']}")
print("---")
print("参考来源:")
for i, doc in enumerate(result['source_documents'][:2]): # 展示前两个来源
print(f"[{i+1}] {doc.page_content[:200]}...")
4. 构建交互式Web应用
使用Streamlit快速创建一个用户友好的问答界面。
# 文件:app.py
import streamlit as st
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
# 页面设置
st.set_page_config(page_title="RAG问答机器人", page_icon="🤖")
st.title("🤖 LangChain RAG 问答机器人")
st.markdown("基于您的私有知识库进行智能问答")
# 侧边栏:模型配置
with st.sidebar:
st.header("配置")
model_name = st.selectbox("选择LLM模型", ["gpt-4", "gpt-3.5-turbo"])
temperature = st.slider("创造性 (Temperature)", 0.0, 1.0, 0.1, 0.1)
k = st.slider("检索文档数量 (k)", 1, 10, 4)
# 初始化组件(使用缓存避免重复加载)
@st.cache_resource
def load_qa_chain():
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
vector_db = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
retriever = vector_db.as_retriever(search_kwargs={"k": k})
llm = ChatOpenAI(model=model_name, temperature=temperature)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
return qa_chain
qa_chain = load_qa_chain()
# 主界面:问答区域
question = st.text_input("请输入您的问题:", placeholder="例如:LangChain的核心组件有哪些?")
if question:
with st.spinner("正在检索与生成答案..."):
result = qa_chain.invoke({"query": question})
st.success("答案生成完成!")
st.markdown("### 💡 答案")
st.write(result['result'])
with st.expander("查看参考来源"):
for i, doc in enumerate(result['source_documents']):
st.markdown(f"**来源 {i+1}** (相关性得分: {doc.metadata.get('score', 'N/A'):.3f})")
st.caption(doc.page_content)
st.divider()
运行应用:
streamlit run app.py
5. 进阶优化与部署建议
一个基础的RAG系统已经搭建完成。要提升其效果和可靠性,可以考虑以下优化方向:
-
检索优化:
- 重排序(Re-ranking):使用如
Cohere或BGE的交叉编码器对初步检索结果进行重排序,提升Top-1准确率。 - 混合搜索(Hybrid Search):结合关键词(BM25)和向量语义搜索,取长补短。
- 元数据过滤:在检索时加入文档类型、日期等元数据作为过滤条件。
- 重排序(Re-ranking):使用如
-
提示工程:
- 设计更精细的提示模板,明确要求模型“引用来源”、“分点回答”或“不确定时坦言”。
- 尝试不同的
chain_type,如map_reduce或refine,处理非常长的上下文。
-
评估与监控:
- 使用
RAGAS、TruLens等框架构建评估体系,从忠实度、答案相关性、上下文相关性等维度量化系统表现。 - 记录用户问答日志,持续迭代知识库和模型。
- 使用
-
部署与生产化:
- 将向量数据库部署至生产级服务(如
Pinecone、Weaviate、Qdrant)。 - 使用
FastAPI或Django构建更健壮的后端API。 - 通过
Docker容器化应用,实现一键部署。
- 将向量数据库部署至生产级服务(如
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)