LangChain ツールアクセス -- InjectedState と InjectedStore

ツールが現在の会話の状態やユーザーの永続データなど、より多くのコンテキスト情報にアクセスする必要がある場合があります。

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})"
    )


# InjectedState は自動的に注入されるため、Agent がこのパラメータを渡す必要はありません
result = remember_preference.invoke({
    "preference": "ダークテーマ",
    # state は渡す必要がなく、フレームワークが自動的に注入します
})
print(result)

実行結果:

已记住偏好: 暗色主题。(当前对话共 0 条消息,之前偏好: 无)

Agent で InjectedState を使用

例

from typing import Annotated, Any
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 conversation_stats(
    state: Annotated[dict[str, Any], InjectedState],
) -> str:
    """現在の会話の統計情報(メッセージ数、会話の長さなど)を取得します。

パラメータは一切不要で、統計情報は現在の状態から自動的に読み取られます。
    """

    messages = state.get("messages", [])
    human_msgs = [m for m in messages if m.type == "human"]
    ai_msgs = [m for m in messages if m.type == "ai"]
    tool_msgs = [m for m in messages if m.type == "tool"]

    return (
        f"会話統計:合計 {len(messages)} 件のメッセージ | "
        f"ユーザーメッセージ {len(human_msgs)} 件 | "
        f"AI 応答 {len(ai_msgs)} 件 | "
        f"ツール呼び出し {len(tool_msgs)} 回"
    )

InjectedState を使用すると、AgentState のすべてのフィールドにアクセスできます。state_schema を拡張して(カスタムフィールドを追加して)、これらのフィールドも InjectedState で読み取ることができます。


InjectedStore——ツールで永続ストレージにアクセス

Agent の状態(state)は会話レベルのもので、会話が終了すると消えてしまいます。一方、Storeはセッションをまたぐ永続ストレージであり、ユーザーのプリファレンスや学習進捗などの長期的な情報を保存するために使用できます。

InjectedStoreツールが Store を直接読み書きできるようにします。

例

from typing import Annotated
from langgraph.store.base import BaseStore
from langgraph.store.memory import InMemoryStore
from langchain.tools import tool, InjectedStore, InjectedState
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


# 永続ストレージを作成する(実際のプロジェクトではデータベースストレージを使用可能)
store = InMemoryStore()
# データを事前にセットする
store.put(("users", "user_001"), "profile", {
    "data": {
        "name": "小明",
        "level": "入門",
        "completed_courses": ["HTML 基礎教程"]
    }
})


@tool
def get_user_profile(
    store: Annotated[BaseStore, InjectedStore()],
) -> str:
    """現在のユーザーの学習プロファイル情報を取得します。

永続ストレージからユーザーデータを読み取ります。
    """

    # Store からデータを読み取る
    # Store は名前空間 (namespace, key) を使用してデータを整理する
    item = store.get(("users", "user_001"), "profile")

    if item is None:
        return "ユーザープロファイルが見つかりません"

    profile = item.value["data"]
    return (
        f"ユーザープロファイル:氏名={profile['name']}、"
        f"レベル={profile['level']}、"
        f完了済みコース={', '.join(profile['completed_courses'])}
    )


@tool
def save_course_progress(
    course_name: str,
    store: Annotated[BaseStore, InjectedStore()],
) -> str:
    """ユーザーの学習進捗を永続ストレージに保存します。

    Args:
course_name: 完了したコース名
store: システムが自動的に注入する永続ストレージ
    """

    # 既存のデータを読み取る
    item = store.get(("users", "user_001"), "profile")
    profile = item.value["data"] if item else {"name": "小明", "level": "入門", "completed_courses": []}

    # コースリストを更新する
    if course_name not in profile["completed_courses"]:
        profile["completed_courses"].append(course_name)

    # Store に書き戻す
    store.put(("users", "user_001"), "profile", {"data": profile})

    return (
        f学習進捗が更新されました!完了したコースは {len(profile['completed_courses'])} 件です:
        f"{', '.join(profile['completed_courses'])}"
    )


# ツールをテストする
print(get_user_profile.invoke({}))
print(save_course_progress.invoke({"course_name": "Python3 基礎教程"}))
print(get_user_profile.invoke({}))

実行結果:

用户档案:姓名=小明,水平=入门,已完成课程=HTML 基础教程
学习进度已更新!已完成 2 门课程:HTML 基础教程, Python3 基础教程
用户档案:姓名=小明,水平=入门,已完成课程=HTML 基础教程, Python3 基础教程

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

# Store を作成しデータを事前にセットする
store = InMemoryStore()
store.put(("サンプル", "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:
    """サンプル 内の指定コースの価格情報を照会します。

    Args:
course_name: コース名
    """

    item = store.get(("サンプル", "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="あなたはサンプル のコースアドバイザーです。",
)

result = agent.invoke({
    "messages": [HumanMessage(content="Python3 基礎教程と Python データ分析はそれぞれいくらですか?")]
})
print(result["messages"][-1].content)

実行結果:

根据查询结果:
- 《Python3 基础教程》是免费的,学习时长约 20 小时
- 《Python 数据分析》是会员课程,学习时长约 30 小时

建议先从免费的 Python3 基础教程开始学习。

InjectedState vs InjectedStore の比較

観点InjectedStateInjectedStore
スコープ現在の会話(単一の Agent 実行)セッションをまたぐ(複数回の Agent 実行で共有)
ライフサイクル会話終了とともに消える永続ストレージ
代表的な用途メッセージ履歴、現在の会話の中間結果の読み取りユーザーのプリファレンス、学習進捗、設定情報
受け渡し方法InjectedState(自動注入)InjectedStore()(括弧が必要)
データ構成フラットな辞書名前空間 + キーの階層構造

InjectedToolArg——汎用注入パラメータのマーク

専用の InjectedState や InjectedStore 以外にも、InjectedToolArg を使用して、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 はカスタム注入ロジックを拡張するために使用します。

その他の拡張