基于LangChain構建高效RAG問答系統:向量檢索與LLM集成實戰
在本文中,我將詳細介紹如何使用LangChain框架構建一個完整的RAG(檢索增強生成)問答系統。通過向量檢索獲取相關上下文,并結合大語言模型,我們能夠構建出一個能夠基于特定知識庫回答問題的智能系統。
1. 基礎設置與向量檢索準備
首先,我們需要導入必要的庫并設置向量存儲訪問:
import os
from dotenv import load_dotenv
from langchain_core.output_parsers import StrOutputParser
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_redis import RedisConfig, RedisVectorStore# 加載環境變量
load_dotenv()# 定義查詢問題
query = "我的生日是幾月幾日?"# 初始化阿里云百煉平臺的向量模型
embedding = DashScopeEmbeddings(model="text-embedding-v3", dashscope_api_key=os.getenv("ALY_EMBADING_KEY"))
redis_url = "redis://localhost:6379" # Redis數據庫的連接地址# 配置Redis向量存儲
config = RedisConfig(index_name="my_index2", # 索引名稱redis_url=redis_url, # Redis數據庫的連接地址
)# 創建向量存儲實例和檢索器
vector_store = RedisVectorStore(embedding, config=config)
retriever = vector_store.as_retriever()
這部分代碼完成了以下工作:
- 加載環境變量以安全地使用API密鑰
- 初始化阿里云文本嵌入模型
- 配置Redis向量數據庫連接
- 創建檢索器(retriever),用于執行向量相似度檢索
2. 執行向量檢索
接下來,我們使用檢索器從向量庫中獲取與查詢相關的文本段落:
# 執行檢索,獲取相關文本段落
retriever_segments = retriever.invoke(query, k=5)
print(retriever_segments)# 將檢索結果整合
text = []
for segment in retriever_segments:text.append(segment.page_content)
在這段代碼中:
retriever.invoke(query, k=5)
檢索與查詢語義最相關的5個文本段落- 我們將檢索到的每個段落的文本內容提取并整合到一個列表中
3. 構建Prompt模板
我們需要設計一個提示模板,將檢索到的相關信息和用戶問題一起傳遞給大語言模型:
from langchain_core.prompts import ChatPromptTemplateprompt_template = ChatPromptTemplate.from_messages([("system", """你是一個問答機器人,你的任務是根據下述給定的已知信息回答用戶的問題已知信息:{context}用戶問題:{query}如果已知問題不包含用戶問題的答案,或者已知信息不足以回答用戶的問題,請回答"抱歉,我無法回答這個問題。"請不要輸出已知信息中不包含的信息或者答案。用中文回答用戶問題"""),]
)# 格式化prompt
prompt = prompt_template.invoke({"context": text, "query": query})
print(prompt.to_messages()[0].content)
這個提示模板:
- 明確定義了AI助手的角色和任務
- 設置了兩個變量:
{context}
用于傳入檢索結果,{query}
用于傳入用戶問題 - 提供了清晰的回答指令,包括當信息不足時如何響應
4. 調用大語言模型獲取回答
現在,我們使用LLM來生成基于上下文的回答:
from langchain_openai import ChatOpenAI# 結果解析器,直接獲取純文本回復
parser = StrOutputParser()# 初始化LLM模型接口
model = ChatOpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.getenv("OPENAI_KEY"),model="qwen/qwq-32b:free")# 調用模型獲取回答
result = model.invoke(prompt)
print(result)
這里我們:
- 使用了OpenRouter平臺上的通義千問模型
- 通過
model.invoke(prompt)
將格式化后的提示發送給模型 - 獲取模型的文本響應
5. 構建完整的RAG鏈
最后,我們將把所有步驟整合成一個完整的LangChain處理鏈,實現端到端的RAG問答:
from operator import itemgetter# 輔助函數:收集文檔內容
def collect_documents(segments):text = []for segment in segments:text.append(segment.page_content)return text# 構建完整的處理鏈
chain = ({"context": itemgetter("query") | retriever | collect_documents,"query": itemgetter("query")
} | prompt_template | model | parser)# 設置新的查詢并執行鏈
query = "你能幫助史可軒處理日常事務嗎"
response = chain.invoke({"query": query})
print(response)
這個鏈式處理流程:
- 接收用戶查詢
- 執行向量檢索獲取相關上下文
- 將上下文和查詢組合到提示模板中
- 調用LLM生成回答
- 解析并返回最終的文本響應
詳細解析鏈式處理
讓我們解析一下這個鏈式處理的構建方式:
chain = ({"context": itemgetter("query") | retriever | collect_documents,"query": itemgetter("query")
} | prompt_template | model | parser)
這個鏈式結構使用了LangChain的管道操作符 |
,實現了以下流程:
itemgetter("query")
從輸入字典中提取查詢文本- 將查詢傳遞給
retriever
執行向量檢索 collect_documents
函數處理檢索結果,提取文本內容- 將處理后的上下文和原始查詢分別作為
context
和query
傳遞給提示模板 - 提示模板格式化后的內容發送給LLM模型處理
- 最后通過
parser
解析LLM的響應,獲取純文本結果
總結
本文介紹了如何使用LangChain框架構建一個完整的RAG問答系統,主要包含以下步驟:
- 向量檢索:從Redis向量數據庫中檢索與用戶問題語義相似的文本段落
- 提示工程:設計合適的提示模板,將檢索結果作為上下文與用戶問題一起發送給模型
- 模型調用:利用LangChain的接口調用大語言模型生成答案
- 鏈式處理:使用LangChain的管道操作將各個組件整合成一個端到端的工作流
這種RAG架構具有很好的可解釋性和可靠性,能夠基于特定的知識庫回答問題,避免了大語言模型"幻覺"問題,特別適合構建企業級知識問答系統、客服助手等應用。
通過向量檢索提供相關上下文,我們可以讓大語言模型更準確地回答特定領域的問題,同時也能降低知識更新的成本(只需更新向量庫而無需重新訓練模型)。這種方案在實際應用中具有很高的靈活性和可擴展性。