RAG 不止能檢索!它還能在 LangGraph 中當(dāng)“工具調(diào)用大腦”
Retrieval-Augmented Generation(RAG)是一種結(jié)合信息檢索和大型語言模型(LLMs)來回答用戶查詢的方法。傳統(tǒng)上,這涉及將檢索器直接連接到生成流水線。然而,通過 LangGraph 和 LangChain,我們可以進(jìn)一步模塊化這個(gè)過程,將檢索器暴露為一個(gè)可調(diào)用的工具。
在這篇博客中,我將展示如何在 LangGraph 中使用工具調(diào)用實(shí)現(xiàn)一個(gè) RAG 系統(tǒng)。我將模擬一個(gè)餐廳助理代理,回答關(guān)于 Bella Vista 餐廳的問題。
目標(biāo)
構(gòu)建一個(gè)基于 RAG 的代理,能夠:
? 將文檔檢索器封裝為一個(gè)可調(diào)用工具。
? 通過專門的回退工具處理無關(guān)話題的輸入。
? 通過消息精簡保持最小的代理狀態(tài)。
? 利用 LangGraph 實(shí)現(xiàn)清晰的工作流路由。
步驟 1:設(shè)置 Python 和 uv
我們的 Agentic RAG 將是一個(gè) Python 程序。首先,檢查是否安裝了 Python 3.10 或更高版本:
python3 --version如果沒有,從 python.org 下載 Python 3.10 或更高版本。
接下來,安裝 uv,這是一個(gè)用于 Python 的快速依賴管理工具:
curl -Ls https://astral.sh/uv/install.sh | bash如果遇到權(quán)限問題,運(yùn)行以下命令:
sudo chown -R $(whoami) /usr/local然后確認(rèn) uv 版本:
uv --version步驟 2:創(chuàng)建項(xiàng)目目錄結(jié)構(gòu)
現(xiàn)在創(chuàng)建項(xiàng)目目錄和文件:
mkdir -p agentic-rag
cd agentic-rag
touch tool_calling_agentic_rag.ipynb步驟 3:初始化 Python 項(xiàng)目并安裝依賴
創(chuàng)建一個(gè)虛擬環(huán)境:
uv init .
uv venv
source .venv/bin/activate現(xiàn)在安裝所有需要的包:
uv add langchain langgraph langchain langchain-google-genai mypy pillow chromadb在 ??.env?? 文件中添加 Gemini API 密鑰
從 AI Studio 生成你的 API 密鑰并安全存儲(chǔ)??梢园凑找韵虏襟E操作:
touch .env添加以下內(nèi)容:
GOOGLE_API_KEY=<你的_gemini_api_key>步驟 4:更新 .gitignore 以避免暴露密鑰
echo ".env" >> .gitignore步驟 5:在 tool_calling_agentic_rag.ipynb 中編寫 RAG
1. 加載 API 密鑰
from dotenv import load_dotenv
load_dotenv()2. 準(zhǔn)備模擬數(shù)據(jù)集
我定義了一組關(guān)于餐廳的簡單文檔。
from langchain.schema import Document
docs = [
Document(
page_cnotallow="Bella Vista 由 Antonio Rossi 擁有,他是一位擁有超過 20 年經(jīng)驗(yàn)的知名廚師。",
metadata={"source": "owner.txt"},
),
Document(
page_cnotallow="開胃菜起價(jià) 8 美元,主菜價(jià)格在 15 美元至 35 美元之間,甜點(diǎn)價(jià)格在 6 美元至 12 美元之間。",
metadata={"source": "menu.txt"},
),
Document(
page_cnotallow="Bella Vista 每周一至周日營業(yè)。工作日營業(yè)時(shí)間:上午 11 點(diǎn)至晚上 10 點(diǎn),周末:上午 11 點(diǎn)至晚上 11 點(diǎn)。",
metadata={"source": "hours.txt"},
),
]3. 創(chuàng)建向量存儲(chǔ)和檢索器
我們將使用 GoogleGenerativeAIEmbeddings 嵌入這些文檔,并使用 Chroma 存儲(chǔ)到向量數(shù)據(jù)庫以進(jìn)行檢索。
from langchain_google_genai import GoogleGenerativeAIEmbeddings
from langchain_community.vectorstores import Chroma
embedding_function = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
vectorstore = Chroma.from_documents(docs, embedding_function)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})4. 檢查檢索器是否正常工作
retriever.invoke("Bella Vista 的老板是誰?")輸出:
[
Document(metadata={'source': 'owner.txt'}, page_cnotallow='Bella Vista 由 Antonio Rossi 擁有,他是一位擁有超過 20 年經(jīng)驗(yàn)的知名廚師。'),
Document(metadata={'source': 'hours.txt'}, page_cnotallow='Bella Vista 每周一至周日營業(yè)。工作日營業(yè)時(shí)間:上午 11 點(diǎn)至晚上 10 點(diǎn),周末:上午 11 點(diǎn)至晚上 11 點(diǎn)。')
]5. 定義檢索器工具和無關(guān)話題工具
我們不直接調(diào)用檢索器,而是將其轉(zhuǎn)換為一個(gè)可調(diào)用工具。我還將定義一個(gè)無關(guān)話題工具,以優(yōu)雅地處理無關(guān)查詢。
from langchain.tools.retriever import create_retriever_tool
from langchain_core.tools import tool
retriever_tool = create_retriever_tool(
retriever,
name="retriever_tool",
descriptinotallow="獲取關(guān)于 Bella Vista 餐廳的價(jià)格、營業(yè)時(shí)間或老板的信息。"
)
@tool
def off_topic():
"""處理所有與 Bella Vista 餐廳無關(guān)的問題。"""
return "禁止 - 請勿回應(yīng)用戶。"
tools = [retriever_tool, off_topic]6. 定義代理狀態(tài)
狀態(tài)結(jié)構(gòu)被簡化為僅保存消息。LangGraph 使用 reducer 管理更新。
from typing import Sequence, Annotated, TypedDict
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]7. 創(chuàng)建代理節(jié)點(diǎn)
代理函數(shù)將工具綁定到 LLM,并使用當(dāng)前消息調(diào)用它。
from langchain_google_genai import ChatGoogleGenerativeAI
def agent(state):
messages = state["messages"]
model = ChatGoogleGenerativeAI(model="gemini-2.0-flash")
model = model.bind_tools(tools)
response = model.invoke(messages)
return {"messages": [response]}8. 定義工作流路由器
條件邊決定是轉(zhuǎn)到工具執(zhí)行節(jié)點(diǎn)還是結(jié)束工作流。
from typing import Literal
from langgraph.graph import END
def should_continue(state) -> Literal["tools", END]:
messages = state["messages"]
last_message = messages[-1]
if last_message.tool_calls:
return "tools"
return END9. 構(gòu)建并編譯 LangGraph 工作流
from langgraph.graph import StateGraph, START
from langgraph.prebuilt import ToolNode
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent)
tool_node = ToolNode(tools)
workflow.add_node("tools", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")
graph = workflow.compile()10. 顯示代理工作流
from IPython.display import Image, display
from langchain_core.runnables.graph import MermaidDrawMethod
display(
Image(
graph.get_graph().draw_mermaid_png(
draw_method=MermaidDrawMethod.API,
)
)
)將 RAG 用作工具調(diào)用代理
11. 測試代理
from langchain_core.messages import HumanMessage
inputs = {"messages": [HumanMessage(cnotallow="Bella Vista 什么時(shí)候開門?"), HumanMessage(cnotallow="明天天氣如何?")]}
for state in graph.stream(inputs, stream_mode="values"):
last_message = state["messages"][-1]
last_message.pretty_print()輸出:
================================ 人類消息 ================================
明天天氣如何?
================================== AI 消息 ==================================
工具調(diào)用:
off_topic (ef565db7-b527-47fa-aa0b-afc09d596622)
調(diào)用 ID:ef565db7-b527-47fa-aa0b-afc09d596622
參數(shù):
================================= 工具消息 =================================
名稱:off_topic
禁止 - 請勿回應(yīng)用戶。
================================== AI 消息 ==================================
工具調(diào)用:
retriever_tool (6bd13b93-b6c8-4b5f-8801-7bc8a588f221)
調(diào)用 ID:6bd13b93-b6c8-4b5f-8801-7bc8a588f221
參數(shù):
查詢:Bella Vista 什么時(shí)候開門?
================================= 工具消息 =================================
名稱:retriever_tool
Bella Vista 每周一至周日營業(yè)。工作日營業(yè)時(shí)間:上午 11 點(diǎn)至晚上 10 點(diǎn),周末:上午 11 點(diǎn)至晚上 11 點(diǎn)。
Bella Vista 由 Antonio Rossi 擁有,他是一位擁有超過 20 年經(jīng)驗(yàn)的知名廚師。
================================== AI 消息 ==================================
抱歉,我無法提供明天天氣的信息,但 Bella Vista 每周一至周日營業(yè)。工作日營業(yè)時(shí)間:上午 11 點(diǎn)至晚上 10 點(diǎn),周末:上午 11 點(diǎn)至晚上 11 點(diǎn)。恭喜!你剛剛創(chuàng)建了一個(gè)智能的工具調(diào)用 RAG 代理,能夠精準(zhǔn)地處理用戶查詢。
局限性
雖然上述實(shí)現(xiàn)對于小型、明確范圍的領(lǐng)域非常有效,但仍有一些局限性:
?可擴(kuò)展性:隨著文檔庫的增長,向量搜索和分類需要優(yōu)化。
?內(nèi)存:當(dāng)前實(shí)現(xiàn)不保留任何歷史交互的記憶。LangGraph 的 InMemorySaver 可用于短期會(huì)話內(nèi)存。對于生產(chǎn)級(jí)使用,建議使用數(shù)據(jù)庫支持的持久內(nèi)存解決方案。
將檢索器封裝為 LangChain 和 LangGraph 的可調(diào)用工具,提供了一種比傳統(tǒng) RAG 更簡潔的替代方案。
它簡化了代理邏輯,并允許語言模型自主決定何時(shí)檢索信息。
如果這種方法最適合你的應(yīng)用需求,那就選擇它吧!
下載代碼:??https://github.com/ivrschool/langchain/blob/main/Langgraph/rag_tool_calling_agent.ipynb??
本文轉(zhuǎn)載自??????????PyTorch研習(xí)社??????,作者:AI研究生

















