有时工具需要访问更多上下文信息,比如当前对话的状态、用户的持久化数据等。
LangChain 通过依赖注入机制,让工具函数能够自动获取这些信息。
InjectedState——在工具中访问 Agent 状态
默认情况下,工具只能通过参数接收模型传来的数据。但有时工具需要知道当前对话的上下文——比如之前的对话历史、用户已确认的信息等。
InjectedState 让工具可以直接读取 Agent 的完整状态。
from typing import Annotated, Any
from dotenv import load_dotenv
load_dotenv()
from langchain.tools import tool, InjectedState
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
@tool
def remember_preference(
preference: str,
state: Annotated[dict[str, Any], InjectedState],
) -> str:
"""记住用户的偏好设置。
Args:
preference: 用户的偏好内容
state: 系统自动注入的当前 Agent 状态
"""
# 从状态中获取之前的消息历史
messages = state.get("messages", [])
message_count = len(messages)
# 可以读取状态中的任何字段
previous_prefs = state.get("user_preferences", "无")
return (
f"已记住偏好: {preference}。"
f"(当前对话共 {message_count} 条消息,"
f"之前偏好: {previous_prefs})"
)
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
model=model,
tools=[remember_preference],
system_prompt="当用户表达偏好时,必须调用 remember_preference 工具进行记录。",
)
# 通过 Agent 调用工具,InjectedState 会在工具执行时自动注入
result = agent.invoke({
"messages": [HumanMessage(content="请记住,我喜欢暗色主题。")]
})
for msg in result["messages"]:
msg.pretty_print()
运行结果:
Tool Message: 已记住偏好: 喜欢暗色主题。(当前对话共 2 条消息,之前偏好: 无)
InjectedState 让你可以访问 AgentState 中的所有字段。如果你扩展了 state_schema(增加了自定义字段),这些字段也可以被 InjectedState 读取到。
InjectedStore——在工具中访问持久化存储
Agent 状态(state)是对话级别的,对话结束就没了。而 Store 是跨会话的持久化存储,可以用来保存用户偏好、学习进度等长期信息。
InjectedStore 让工具可以直接读写 Store。
在 Agent 中结合 Store
将 Store 传给 create_agent(),Agent 中的所有工具都能通过 InjectedStore 访问它:
from typing import Annotated
from langgraph.store.base import BaseStore
from langgraph.store.memory import InMemoryStore
from langchain.tools import tool, InjectedStore
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from dotenv import load_dotenv
load_dotenv()
# 创建 Store 并预置数据
store = InMemoryStore()
store.put(("runoob", "courses"), "catalog", {
"data": {
"Python3 基础教程": {"price": "免费", "duration": "20小时"},
"Python 数据分析": {"price": "会员", "duration": "30小时"},
"HTML 基础教程": {"price": "免费", "duration": "15小时"},
}
})
@tool
def query_course_price(
course_name: str,
store: Annotated[BaseStore, InjectedStore()],
) -> str:
"""查询菜鸟教程 RUNOOB 中指定课程的价格信息。
Args:
course_name: 课程名称
"""
item = store.get(("runoob", "courses"), "catalog")
catalog = item.value["data"] if item else {}
if course_name in catalog:
info = catalog[course_name]
return f"《{course_name}》- 价格:{info['price']},学习时长:{info['duration']}"
return f"未找到课程《{course_name}》"
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
model=model,
tools=[query_course_price],
store=store, # 将 Store 传入 Agent
system_prompt="你是菜鸟教程 RUNOOB 的课程顾问。",
)
result = agent.invoke({
"messages": [HumanMessage(content="Python3 基础教程和 Python 数据分析分别多少钱?")]
})
for msg in result["messages"]:
msg.pretty_print()
运行结果:
================================== Ai Message ==================================
好的!我来帮您查询这两门课程的价格信息。
Tool Calls:
query_course_price (call_00_7QHxvF5r4hovsM3ztHsK3869)
Call ID: call_00_7QHxvF5r4hovsM3ztHsK3869
Args:
course_name: Python3 基础教程
query_course_price (call_01_kAnr1rVjFC5chrKJdMRk5105)
Call ID: call_01_kAnr1rVjFC5chrKJdMRk5105
Args:
course_name: Python 数据分析
================================= Tool Message =================================
Name: query_course_price
================================= Tool Message =================================
Name: query_course_price
《Python 数据分析》- 价格:会员,学习时长:30小时
================================== Ai Message ==================================
查询结果如下:
| 课程名称 | 价格 | 学习时长 |
|---------|:---:|:-------:|
| 🐍 **Python3 基础教程** | **免费** 🆓 | 20 小时 |
| 📊 **Python 数据分析** | **会员专属** 🏆 | 30 小时 |
**总结一下:**
- **《Python3 基础教程》** 完全 **免费**,适合零基础入门学习,时长 20 小时。
- **《Python 数据分析》** 需要 **成为会员** 才能观看,学习时长 30 小时,内容更深入,适合有 Python 基础后进阶学习。
如果您对会员价格或其他课程感兴趣,也可以随时问我哦!😊
InjectedState vs InjectedStore 对比
| 维度 | InjectedState | InjectedStore |
|---|---|---|
| 作用域 | 当前对话(单次 Agent 运行) | 跨会话(多次 Agent 运行共享) |
| 生命周期 | 对话结束即消失 | 持久化存储 |
| 典型用途 | 读取消息历史、当前对话的中间结果 | 用户偏好、学习进度、配置信息 |
| 传入方式 | InjectedState(自动注入) | InjectedStore()(需要括号) |
| 数据组织 | 扁平字典 | 命名空间 + 键的层级结构 |
InjectedToolArg——标记通用注入参数
除了专门的 InjectedState 和 InjectedStore,你还可以用 InjectedToolArg 标记任何需要框架注入的参数:
from typing import Annotated
from langchain.tools import tool, InjectedToolArg
@tool
def my_tool(
normal_param: str,
injected_param: Annotated[str, InjectedToolArg],
) -> str:
"""一个包含注入参数的示例工具。
Args:
normal_param: 这个参数由模型提供
injected_param: 这个参数由框架注入(Agent 不需要提供)
"""
return f"normal={normal_param}, injected={injected_param}"
InjectedToolArg 是通用的注入标记,InjectedState、InjectedStore 和 InjectedToolCallId 都是基于它实现的。大多数情况下使用专门的注入标记即可,InjectedToolArg 用于扩展自定义注入逻辑。
