注入状态 指的是让工具函数能够直接访问 LangGraph 图的当前状态(如定义的 AgentState),同时这个状态参数对 LLM 是不可见的。也就是说,LLM 在决定调用工具时,不会、也不需要去生成这个参数,它由 LangGraph 框架自动填充。这样做的好处是安全且解耦,工具内部可以按需读取或更新上下文
如何实现
实现状态注入的核心是使用 langgraph.prebuilt.InjectedState 这个特殊的类型注解,并结合 ToolNode 来执行工具
1. 定义带注入状态参数的工具
在工具函数中,为需要接收状态的那个参数添加 Annotated[状态类型, InjectedState] 注解
python
from typing import Annotated
from langgraph.prebuilt import InjectedState
from langchain_core.tools import tool
# 假设状态定义如下
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
document: str # 新增的文档字段
@tool
def update_document(content: str, state: Annotated[AgentState, InjectedState]) -> str:
"""使用新内容更新当前文档。"""
# 直接读取和修改状态
old_content = state.get("document", "")
state["document"] = content
return f"文档已更新。\n旧内容: {old_content}\n新内容: {content}"
在这个例子里:
content: str是正常的工具参数,由 LLM 根据提示词和工具描述来生成state: Annotated[AgentState, InjectedState]则是一个注入参数。InjectedState注解告诉ToolNode在执行时,自动将当前的AgentState对象传递给这个参数
关键点:
- LLM 对此参数无感知 :LLM 在生成工具调用时,只会生成
content字段,不会生成state字段,state由系统在后台注入 - 支持注入子字段 :也可以只注入状态中的某个特定字段,如
Annotated[str, InjectedState("document")],这样工具的这个参数就会直接接收到state["document"]的值
2. 使用 ToolNode 执行工具
用 ToolNode 包装工具列表,并将其作为图中的一个节点。ToolNode 会自动处理 InjectedState 注解的参数注入
python
from langgraph.prebuilt import ToolNode
tools = [update_document, save_document]
tool_node = ToolNode(tools)
# ... 在图构建中 ...
graph.add_node("tools", tool_node)
3. 在 Agent 节点中绑定工具并调用
在主 Agent 节点函数中,将工具列表绑定到模型,并处理模型的响应
python
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="mimo-v2.5-pro").bind_tools(tools)
def our_agent(state: AgentState) -> AgentState:
# 构造消息并调用模型
response = model.invoke([system_prompt] + state["messages"])
return {"messages": [response]} # 响应可能包含 tool_calls
注意事项
ToolNode是必须的 :InjectedState注解的自动处理依赖于ToolNode的执行上下文。如果通过其他方式直接调用工具函数,注入可能不会生效- 检查点与状态更新 :直接在工具中修改的
state对象,它的变更会在图执行过程中被checkpointer(如果配置了)自动记录下来,从而实现对话记忆或状态回滚功能,因此可以放心地修改它