作者:彬彬侠
langgraph.prebuilt.InjectedState 是 LangGraph 库中 langgraph.prebuilt 模块的一个特殊类型注解,继承自 InjectedToolArg,用于在工具函数中注入 LangGraph 状态图的当前状态。它允许工具在运行时访问状态(如对话历史或用户上下文),同时隐藏该参数,使语言模型(LLM)无法生成或修改状态,从而提高安全性和开发效率。以下是对 InjectedState 类的有序、清晰介绍,基于提供的参考信息和 LangGraph 文档。
1. 定义与功能
1.1 类定义
InjectedState 是一个类型注解类,定义如下:- from langgraph.prebuilt import InjectedState
- classInjectedState(InjectedToolArg):"""
- 用于工具参数的注解,表示该参数将注入状态图的当前状态。
- 参数:
- field: 可选,指定状态中要注入的特定键。如果为 None,则注入整个状态。
- 示例:
- @tool
- def state_tool(x: int, state: Annotated[dict, InjectedState]) -> str:
- '''处理状态的工具。'''
- if len(state["messages"]) > 2:
- return state["foo"] + str(x)
- else:
- return "消息不足"
- """def__init__(self, field: Optional[str]=None)->None:
- self.field = field
复制代码继承:继承自 InjectedToolArg,表明它是工具参数注入机制的一部分。作用:标记工具函数中的参数,指示 LangGraph 在运行时注入状态图的状态。
- 关键特性:
隐藏参数:使用 InjectedState 注解的参数不会出现在工具的模式(schema)中,LLM 无法生成该参数的值。自动注入:当工具通过 ToolNode 执行时,LangGraph 自动将状态(或指定字段)注入到参数中。
1.2 核心功能
状态注入:将状态图的当前状态(或其某个字段)传递给工具函数,供工具使用。模式隔离:隐藏状态参数,防止 LLM 尝试生成或修改状态,确保安全和正确性。灵活性:支持注入整个状态(field=None)或特定字段(field="key"),适应不同场景。与 ToolNode 集成:与 ToolNode 配合使用,自动处理工具调用和状态注入。
1.3 使用场景
状态依赖工具:工具需要访问状态(如对话历史、用户信息)以执行上下文相关的操作。多轮对话:在聊天机器人中,工具需要引用对话历史或用户上下文。安全敏感场景:状态包含敏感数据(如用户 ID),不应暴露给 LLM。复杂工作流:工具需要状态中的中间结果或共享变量来完成任务。
2. 参数与用法
2.1 参数
- field:
类型:Optional[str]默认值:None
- 描述:
如果为 None,注入整个状态对象(通常是字典或自定义状态类)。如果指定为字符串(如 "foo"),仅注入状态中对应键的值。
- 示例:
InjectedState():注入整个状态,如 {"messages": [...], "foo": "bar"}。InjectedState("foo"):仅注入 state["foo"],如 "bar"。
2.2 用法
InjectedState 通常与 typing_extensions.Annotated 一起使用,注解工具函数的参数。以下是基本用法:
定义工具:
使用 @tool 装饰器创建工具,参数中添加 InjectedState 注解。
集成到状态图:
使用 ToolNode 处理工具调用,LangGraph 自动注入状态。
运行工作流:
通过状态图的 invoke 或 stream 方法执行,工具接收注入的状态。
3. 实现原理
3.1 状态注入机制
注解识别:LangGraph 的运行时(通过 ToolNode)识别工具函数中带有 InjectedState 注解的参数。
- 状态提取:
如果 field=None,将整个状态对象(通常是字典或 Pydantic 模型)传递给工具。如果 field 指定为键(如 "foo"),从状态中提取对应值。
参数注入:在工具调用时,运行时将状态(或字段值)注入到工具的参数中,绕过 LLM 的生成过程。模式隐藏:InjectedState 参数被从工具的模式中移除,LLM 只看到其他暴露的参数(如 x: int)。
3.2 与 ToolNode 的协作
ToolNode 是 LangGraph 的工具执行节点,负责解析 AIMessage 中的工具调用(tool_calls)。当工具包含 InjectedState 参数,ToolNode 在调用工具前自动注入状态,确保工具接收正确的上下文。注入过程对开发者透明,简化了状态管理。
3.3 状态格式
状态通常是字典(如 {"messages": [...], "foo": "bar"})或自定义 TypedDict。工具通过标准字典操作(如 state["key"])或属性访问(如果状态是 Pydantic 模型)获取数据。
4. 使用示例
以下是一个完整的示例,展示如何使用 InjectedState 在状态图中注入状态到工具。
4.1 示例代码
- from typing import List
- from typing_extensions import Annotated, TypedDict
- from langchain_core.messages import BaseMessage, AIMessage
- from langchain_core.tools import tool
- from langgraph.prebuilt import InjectedState, ToolNode
- # 定义状态classAgentState(TypedDict):
- messages: List[BaseMessage]
- foo:str# 定义工具 1:访问整个状态@tooldefstate_tool(x:int, state: Annotated[dict, InjectedState])->str:"""根据状态中的消息数量处理输入。"""iflen(state["messages"])>2:return state["foo"]+str(x)else:return"消息不足"# 定义工具 2:访问特定字段@tooldeffoo_tool(x:int, foo: Annotated[str, InjectedState("foo")])->str:"""处理状态中的 foo 字段。"""return foo +str(x +1)# 创建 ToolNode
- tools =[state_tool, foo_tool]
- node = ToolNode(tools)# 定义状态和工具调用
- tool_call1 ={"name":"state_tool","args":{"x":1},"id":"1","type":"tool_call"}
- tool_call2 ={"name":"foo_tool","args":{"x":1},"id":"2","type":"tool_call"}
- state ={"messages":[AIMessage("", tool_calls=[tool_call1, tool_call2])],"foo":"bar"}# 执行工具节点
- result = node.invoke(state)for msg in result["messages"]:print(f"{msg.__class__.__name__}: {msg.content}")
复制代码 4.2 输出示例
- ToolMessage: 消息不足
- ToolMessage: bar2
复制代码 4.3 代码解析
状态:AgentState 定义了状态结构,包含 messages 和 foo 字段。
- 工具:
state_tool:使用 InjectedState 注入整个状态,检查 messages 长度并操作 foo。foo_tool:使用 InjectedState("foo") 注入 state["foo"],直接操作该字段。
- 工具调用:
tool_call1 调用 state_tool,传入 x=1,注入整个状态。由于 messages 长度为 1,返回“消息不足”。tool_call2 调用 foo_tool,传入 x=1,注入 foo="bar",返回 bar2。
ToolNode:处理工具调用,自动注入状态并生成 ToolMessage。
4.4 集成到状态图
以下是将上述工具集成到完整状态图的示例:- from langgraph.graph import StateGraph, END
- from langchain_openai import ChatOpenAI
- from langchain_core.prompts import ChatPromptTemplate
- # 定义 Agent 节点defagent(state: AgentState)-> AgentState:
- prompt = ChatPromptTemplate.from_template("根据输入调用工具:{input}")
- llm = ChatOpenAI(model="gpt-3.5-turbo").bind_tools(tools)
- message = llm.invoke(state["messages"][-1].content)
- state["messages"].append(message)return state
- # 构建状态图
- workflow = StateGraph(AgentState)
- workflow.add_node("agent", agent)
- workflow.add_node("tools", node)
- workflow.add_edge("tools","agent")
- workflow.add_conditional_edges("agent",lambda state:"tools"if state["messages"][-1].tool_calls else END)
- workflow.set_entry_point("agent")# 编译并运行
- graph = workflow.compile()
- initial_state ={"messages":[HumanMessage(content="处理数字 1")],"foo":"bar"}
- result = graph.invoke(initial_state)
复制代码 5. 使用场景
InjectedState 适用于以下场景:
上下文相关工具:工具需要访问对话历史、用户信息或其他状态数据,例如个性化响应。敏感数据处理:状态包含敏感信息(如用户 ID、会话令牌),不应暴露给 LLM。多轮对话:在聊天机器人中,工具需要引用历史消息或上下文。复杂工作流:工具需要访问共享状态变量以协调多步骤任务。
示例场景:
聊天机器人:工具根据用户 ID 从状态中获取用户偏好,提供定制化回答。自动化工作流:工具根据状态中的中间结果决定操作,例如数据处理后更新状态。
6. 注意事项
状态格式:
确保状态包含工具期望的键(如 foo),否则可能引发 KeyError。如果使用 field,验证状态中存在该键。
工具模式:
InjectedState 参数不出现在工具模式中,LLM 只生成其他参数。确保工具的非注入参数有清晰的类型注解,便于 LLM 生成。
性能:
注入整个状态可能增加内存开销,对于大型状态,优先使用 field 指定字段。使用异步工具调用(ToolNode 支持 ainvoke)优化性能。
调试:
启用 debug=True 查看状态注入日志。使用 graph.get_graph().to_dot() 可视化状态图,验证工具节点行为。
版本兼容性:
InjectedState 是较新的功能(截至 2025 年 5 月,LangGraph 0.3+ 支持)。检查 LangGraph 文档 确认版本支持。
7. 与其他注解的对比
| 注解 | 用途 | 是否暴露给 LLM | 示例场景 | | InjectedState | 注入整个状态或指定字段 | 否 | 工具访问对话历史或用户上下文 | | InjectedToolArg | 注入运行时参数(如特定值) | 否 | 注入动态用户 ID 或会话令牌 | | RunnableConfig | 注入运行时配置(如执行设置) | 否 | 传递执行超时或元数据 | | InjectedStore | 注入 LangGraph 存储对象 | 否 | 工具访问持久化存储数据 | InjectedState 专注于状态注入,适合需要完整上下文的工具,而 InjectedToolArg 更适合单一值注入。
8. 总结
langgraph.prebuilt.InjectedState 是一个强大的类型注解,用于在 LangGraph 工具中注入状态图的状态。它通过隐藏状态参数,防止 LLM 生成敏感数据,同时允许工具访问上下文,实现安全、高效的上下文相关操作。支持注入整个状态或指定字段,与 ToolNode 无缝集成,适用于聊天机器人、自动化工作流等场景。通过清晰的注解和自动注入机制,它简化了状态管理,提升了开发效率。
原文地址:https://blog.csdn.net/u013172930/article/details/148011556 |