使用langchain构建简单RAG
使用langchain构建简单RAG
环境准备
pip install chromadb #安装
chroma run #运行
#conda创建 python=3.10版本的虚环境
conda create -n python_10 python=3.10
#torch安装
conda install pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 pytorch-cuda=12.1 -c pytorch -c nvidia
#如果是本地部署ollama,langchain 对ollama的支持
pip install -U langchain-ollama
#支持chroma
pip install langchain_chroma
pip install -U langchain-community
#在控制台把ollama跑起来
ollama run deepseek-r1:1.5b
代码
import os
import requests
# 设置用户代理
os.environ["USER_AGENT"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
from langchain_community.document_loaders import WebBaseLoader # 修改后的导入路径
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser
from langchain_ollama.llms import OllamaLLM
from langchain_chroma import Chroma
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
def prepare_data():
loader = WebBaseLoader(
web_paths=["https://zhuanlan.zhihu.com/p/648063002"],
requests_kwargs={
"headers": {
"User-Agent": os.environ["USER_AGENT"]
}
}
)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)
print(chunks[0].page_content)
return chunks
#embedding 知识库,保存到向量数据库
def embedding_data(chunks):
#创建BAAI的embedding
rag_embeddings = HuggingFaceBgeEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
#embed保存知识到向量数据库
vector_store = Chroma.from_documents(documents=chunks, embedding=rag_embeddings,persist_directory="./chroma_langchain_db")
retriever = vector_store.as_retriever()
return vector_store,retriever
#使用ollama服务
llm = OllamaLLM(model="deepseek-r1:1.5b")
template = """您是问答任务的助理。
使用以下检索到的上下文来回答问题。
如果你不知道答案,就说你不知道。
最多使用三句话,不超过100字,保持答案简洁。
Question: {question} Context: {context} Answer:
"""
prompt = ChatPromptTemplate.from_template(template)
chunks = prepare_data()
vector_store,retriever = embedding_data(chunks)
#生成答案
def generate_answer(question):
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print("问题:"+question)
resp=rag_chain.invoke(question)
print(resp)
query = "Midjourney是什么"
generate_answer(query)
代码解释
retriever = vector_store.as_retriever()
retriever = vector_store.as_retriever() :这行代码的含义是将 Chroma 向量数据库(vector_store)转换为一个检索器对象(retriever),这是 LangChain 框架中一个非常重要的概念。以下是具体解析:
核心作用
- 封装检索逻辑
将向量数据库的底层操作(如相似性搜索、最大边际相关性搜索等)包装成一个标准化的检索接口,后续可以直接通过这个 retriever 对象进行语义检索。 - 统一交互方式
在 LangChain 的生态中,不同的向量数据库(Chroma/FAISS/Pinecone 等)都有自己的底层 API,.as_retriever()方法将它们统一成一致的检索接口,方便后续与其他组件(如 Chain、Agent)无缝集成。
关键特性
通过 retriever 可以:
- 直接执行语义搜索
results = retriever.get_relevant_documents("你的查询问题")
无需手动调用 similarity_search 等底层方法。
配置检索参数
可以通过参数控制搜索行为:
retriever = vector_store.as_retriever(
search_type="similarity", # 相似性搜索(默认)
search_kwargs={"k": 5} # 返回前5个结果
# 其他参数如 score_threshold(分数阈值)等
)
支持链式调用
retriever 可以直接作为 RetrievalQA 链的输入:
qa_chain = RetrievalQA.from_chain_type(
llm=your_llm,
chain_type="stuff",
retriever=retriever # 直接传入检索器
)
rag_chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser() )
这是用 LangChain 构建的 RAG(检索增强生成)流水线,其核心逻辑是通过管道操作符 | 将多个组件串联起来。它的工作流程如下:
1. 输入处理阶段
{"context": retriever, "question": RunnablePassthrough()}
- 作用:定义输入数据的来源和传递方式
- 关键组件:
retriever:向量数据库的检索器(负责获取相关上下文)RunnablePassthrough():直接透传用户的原始输入问题
- 数据流向:
context:自动调用retriever.get_relevant_documents(question)获取与问题相关的文档question:直接传递用户输入的问题(例如用户提问 "如何申请年假?")
2. 提示模板阶段
| prompt
- 作用:将检索到的上下文(context)和用户问题(question)组装成 LLM 能理解的提示词
- 典型提示模板示例:
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("""
根据以下上下文回答问题:
{context}
问题:{question}
答案:
""")
实际生成的提示词:
-
根据以下上下文回答问题: [文档1内容]... [文档2内容]... 问题:如何申请年假? 答案:
3. 语言模型推理阶段
| llm
-
作用:将组装好的提示词输入给大语言模型(如 GPT-3.5、Llama2 等)
-
典型模型调用:
-
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo") -
输出结果:模型生成的原始响应(通常为包含元数据的复杂对象)
4. 输出解析阶段
| StrOutputParser()
- 作用:提取模型响应中的纯文本内容
- 必要性:LLM 返回的原始响应可能包含冗余信息(如日志、置信度分数等),此步骤将其简化为字符串
- 示例转换:
# 输入(复杂对象):
AIMessage(content="申请年假需提交OA审批...", additional_kwargs={...})
# 输出(纯文本):
"申请年假需提交OA审批..."
运行结果


浙公网安备 33010602011771号