LangChain 工具访问

有时工具需要访问更多上下文信息,比如当前对话的状态、用户的持久化数据等。

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 用于扩展自定义注入逻辑。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇