LangGraph : Prebuilt エージェント : メモリ

LangGraph は会話エージェントの構築のために不可欠な 2 種類のメモリ (短期メモリ & 長期メモリ) をサポートしています。このガイドは LangGraph のエージェントで両方のメモリタイプを使用する方法を示します。

LangGraph : Prebuilt エージェント : メモリ

作成 : クラスキャット・セールスインフォメーション
作成日時 : 06/15/2025

* 本記事は langchain-ai.github.io の以下のページを独自に翻訳した上で、補足説明を加えてまとめ直しています :

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

クラスキャット 人工知能 研究開発支援サービス ⭐️ リニューアルしました 😉

クラスキャット は人工知能に関する各種サービスを提供しています。お気軽にご相談ください :

  • 人工知能導入個別相談会(無償)実施中! [詳細]

  • 人工知能研究開発支援 [詳細]
    1. 自社特有情報を含むチャットボット構築支援
    2. 画像認識 (医療系含む) / 画像生成

  • PoC(概念実証)を失敗させないための支援 [詳細]

お問合せ : 下記までお願いします。

  • クラスキャット セールス・インフォメーション
  • sales-info@classcat.com
  • ClassCatJP

 

LangGraph : Get started : Prebuilt エージェント : メモリ

LangGraph は会話エージェントの構築のために不可欠な 2 種類のメモリをサポートしています :

  • 短期メモリ : セッション内でメッセージ履歴を維持することで進行中の会話を追跡します。

  • 長期メモリ : セッション全体に渡りユーザ固有またはアプリケーションレベルのデータをストアします。

このガイドは LangGraph のエージェントで両方のメモリタイプを使用する方法を示します。メモリの概念の深い理解のためには、LangGraph メモリ・ドキュメント を参照してください。



短期メモリ長期メモリ も両方とも LLM インタラクション全体に渡り連続性を維持するには永続的なストレージを必要とします。プロダクション環境では、このデータは通常はデータベースに保存されます。

Terminology : LangGraph では :

  • 短期メモリはまた スレッドレベル (thread-level) メモリ とも呼ばれます。

  • 長期メモリはまた クロススレッド (cross-threa) メモリ とも呼ばれます。

スレッド は、同じ thread_id でグループ化された一連の関連する実行を表します。

 

短期メモリ

短期メモリはエージェントが複数ターンの会話を追跡することを可能にします。それを使用するには、以下が必要です :

  1. エージェントを作成するときチェックポインターを提供します。チェックポインターはエージェント状態を 永続化 できます。

  2. エージェントを実行するとき、config で thread_id を供給します。thread_id は会話セッションのための一意の識別子です。
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver() 


def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"


agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[get_weather],
    checkpointer=checkpointer 
)

# Run the agent
config = {
    "configurable": {
        "thread_id": "1"  
    }
}

sf_response = agent.invoke(
    {"messages": [{"role": "user", "content": "what is the weather in sf"}]},
    config
)

# Continue the conversation using the same thread_id
ny_response = agent.invoke(
    {"messages": [{"role": "user", "content": "what about new york?"}]},
    config 
)

エージェントが同じ thread_id で 2 度目に呼び出される場合、最初の会話の元のメッセージ履歴は自動的に含まれ、エージェントはユーザがニューヨークの天気について具体的に尋ねていることを推論できます。

Note : LangGraph Platform は production-ready なチェックポインターを提供します。
LangGraph Platform を使用している場合、配備中、チェックポインターは production-ready データベースを使用するように自動的に設定されます。

 

メッセージ履歴の管理

長い会話は LLM のコンテキスト・ウィンドウを超える可能性があります。一般的な解決法は :

  • 要約 : 会話の実行中の要約を維持する。

  • トリミング : 履歴の最初または最後の N メッセージを削除する

これはエージェントが、LLM のコンテキスト・ウィンドウを超えることなく、会話を追跡することを可能にします。

メッセージ履歴を管理するには、pre_model_hook を指定します – これは言語モデルを呼び出す前に常に実行される関数 ( ノード ) です。

メッセージ履歴を要約する

長い会話は LLM のコンテキスト・ウィンドウを超える可能性があります。一般的な解決法は会話の実行中の要約を維持することです。これはエージェントが LLM のコンテキスト・ウィンドウを超えることなく会話を追跡することを可能にします。

メッセージ履歴を要約するには、事前構築済みの SummarizationNodepre_model_hook を使用できます :

from langchain_anthropic import ChatAnthropic
from langmem.short_term import SummarizationNode
from langchain_core.messages.utils import count_tokens_approximately
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.checkpoint.memory import InMemorySaver
from typing import Any

model = ChatAnthropic(model="claude-3-7-sonnet-latest")

summarization_node = SummarizationNode( 
    token_counter=count_tokens_approximately,
    model=model,
    max_tokens=384,
    max_summary_tokens=128,
    output_messages_key="llm_input_messages",
)

class State(AgentState):
    # NOTE: we're adding this key to keep track of previous summary information
    # to make sure we're not summarizing on every LLM call
    context: dict[str, Any]  


checkpointer = InMemorySaver() 

agent = create_react_agent(
    model=model,
    tools=tools,
    pre_model_hook=summarization_node, 
    state_schema=State, 
    checkpointer=checkpointer,
)

 

メッセージ履歴のトリミング

メッセージ履歴をトリムするには、trim_messages 関数で pre_model_hook を使用します :

from langchain_core.messages.utils import (
    trim_messages,
    count_tokens_approximately
)
from langgraph.prebuilt import create_react_agent

# This function will be called every time before the node that calls LLM
def pre_model_hook(state):
    trimmed_messages = trim_messages(
        state["messages"],
        strategy="last",
        token_counter=count_tokens_approximately,
        max_tokens=384,
        start_on="human",
        end_on=("human", "tool"),
    )
    return {"llm_input_messages": trimmed_messages}

checkpointer = InMemorySaver()
agent = create_react_agent(
    model,
    tools,
    pre_model_hook=pre_model_hook,
    checkpointer=checkpointer,
)

pre_model_hook を使用してメッセージ履歴を管理する方法についての詳細を学習するには、この how-to ガイド をご覧ください。

 

ツール内での読み取り

LangGraph はエージェントがツール内で短期メモリ (状態) にアクセスすることを可能にします。

from typing import Annotated
from langgraph.prebuilt import InjectedState, create_react_agent

class CustomState(AgentState):
    user_id: str

def get_user_info(
    state: Annotated[CustomState, InjectedState]
) -> str:
    """Look up user info."""
    user_id = state["user_id"]
    return "User is John Smith" if user_id == "user_123" else "Unknown user"

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[get_user_info],
    state_schema=CustomState,
)

agent.invoke({
    "messages": "look up user information",
    "user_id": "user_123"
})

See the Context guide for more information.

 

ツールからの書き込み

実行中にエージェントの短期メモリ (状態) を変更するには、ツールから直接、状態更新を返すことができます。これは、中間結果を永続化したり、続くツールやプロンプトが情報にアクセスできるようにするために有用です。

from typing import Annotated
from langchain_core.tools import InjectedToolCallId
from langchain_core.runnables import RunnableConfig
from langchain_core.messages import ToolMessage
from langgraph.prebuilt import InjectedState, create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.types import Command

class CustomState(AgentState):
    user_name: str

def update_user_info(
    tool_call_id: Annotated[str, InjectedToolCallId],
    config: RunnableConfig
) -> Command:
    """Look up and update user info."""
    user_id = config["configurable"].get("user_id")
    name = "John Smith" if user_id == "user_123" else "Unknown user"
    return Command(update={
        "user_name": name,
        # update the message history
        "messages": [
            ToolMessage(
                "Successfully looked up user information",
                tool_call_id=tool_call_id
            )
        ]
    })

def greet(
    state: Annotated[CustomState, InjectedState]
) -> str:
    """Use this to greet the user once you found their info."""
    user_name = state["user_name"]
    return f"Hello {user_name}!"

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[update_user_info, greet],
    state_schema=CustomState
)

agent.invoke(
    {"messages": [{"role": "user", "content": "greet the user"}]},
    config={"configurable": {"user_id": "user_123"}}
)

For more details, see how to update state from tools.

 

長期メモリ

長期メモリを使用して、ユーザ固有またはアプリケーション固有の会話全体に渡るデータをストアします。これは、ユーザの優先設置やその他の情報を記憶したい、チャットボットのようなアプリケーションに有用です。

長期メモリを使用するには、以下が必要です :

  • 呼び出しに渡るデータを永続化するために ストアを設定 します。

  • ツール内ちゃプロンプトからストアにアクセスするには get_store 関数を使用します。

 

READ

A tool the agent can use to look up user information

from langchain_core.runnables import RunnableConfig
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore

store = InMemoryStore() 

store.put(  
    ("users",),  
    "user_123",  
    {
        "name": "John Smith",
        "language": "English",
    } 
)

def get_user_info(config: RunnableConfig) -> str:
    """Look up user info."""
    # Same as that provided to `create_react_agent`
    store = get_store() 
    user_id = config["configurable"].get("user_id")
    user_info = store.get(("users",), user_id) 
    return str(user_info.value) if user_info else "Unknown user"

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[get_user_info],
    store=store 
)

# Run the agent
agent.invoke(
    {"messages": [{"role": "user", "content": "look up user information"}]},
    config={"configurable": {"user_id": "user_123"}}
)

 

WRITE

Example of a tool that updates user information

from typing_extensions import TypedDict

from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore

store = InMemoryStore() 

class UserInfo(TypedDict): 
    name: str

def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: 
    """Save user info."""
    # Same as that provided to `create_react_agent`
    store = get_store() 
    user_id = config["configurable"].get("user_id")
    store.put(("users",), user_id, user_info) 
    return "Successfully saved user info."

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[save_user_info],
    store=store
)

# Run the agent
agent.invoke(
    {"messages": [{"role": "user", "content": "My name is John Smith"}]},
    config={"configurable": {"user_id": "user_123"}} 
)

# You can access the store directly to get the value
store.get(("users",), "user_123").value

 

セマンティック検索

LangGraph はまた、セマンティック類似性により長期メモリ内の項目を 検索する こともできます。

 

Prebuilt メモリツール

LangMem は、エージェントで長期メモリを管理するためのツールを提供する、LangChain-maintained ライブラリです。See the LangMem documentation for usage examples.

 

追加リソース

 

以上