このチュートリアルでは、メッセージリストに依存することなく複雑な動作を定義するために、状態にフィールドを追加します。チャットボットは検索ツールを使用して特定の情報を見つけてそれらをレビューのために人間に転送します。
LangGraph : Get started : 基本 – 状態のカスタマイズ
作成 : クラスキャット・セールスインフォメーション
作成日時 : 06/05/2025
* 本記事は langchain-ai.github.io の以下のページを独自に翻訳した上で、補足説明を加えてまとめ直しています :
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
◆ お問合せ : 下記までお願いします。
- クラスキャット セールス・インフォメーション
- sales-info@classcat.com
- ClassCatJP
LangGraph : Get started : 基本 – 状態のカスタマイズ
このチュートリアルでは、メッセージリストに依存することなく複雑な動作を定義するために、状態にフィールドを追加します。チャットボットは検索ツールを使用して特定の情報を見つけてそれらをレビューのために人間に転送します。
1. キーを状態に追加する
エンティティの誕生日を調べるために、name と birthday のキーを追加してチャットボットを更新します :
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
name: str
birthday: str
この情報を状態に追加すると、グラフの永続化層に加えて (情報をストア or 処理する下流ノードのような) 他のグラフノードにより簡単にアクセスできるようになります。
2. ツール内の状態の更新
次に、human_assistance ツール内の状態キーを設定します。これは情報が状態にストアされる前に人間がレビューすることを可能にします。ツール内から状態更新を実行するには Command を使用します。
from langchain_core.messages import ToolMessage
from langchain_core.tools import InjectedToolCallId, tool
from langgraph.types import Command, interrupt
@tool
# Note that because we are generating a ToolMessage for a state update, we
# generally require the ID of the corresponding tool call. We can use
# LangChain's InjectedToolCallId to signal that this argument should not
# be revealed to the model in the tool's schema.
def human_assistance(
name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]
) -> str:
"""Request assistance from a human."""
human_response = interrupt(
{
"question": "Is this correct?",
"name": name,
"birthday": birthday,
},
)
# If the information is correct, update the state as-is.
if human_response.get("correct", "").lower().startswith("y"):
verified_name = name
verified_birthday = birthday
response = "Correct"
# Otherwise, receive information from the human reviewer.
else:
verified_name = human_response.get("name", name)
verified_birthday = human_response.get("birthday", birthday)
response = f"Made a correction: {human_response}"
# This time we explicitly update the state with a ToolMessage inside
# the tool.
state_update = {
"name": verified_name,
"birthday": verified_birthday,
"messages": [ToolMessage(response, tool_call_id=tool_call_id)],
}
# We return a Command object in the tool to update our state.
return Command(update=state_update)
The rest of the graph stays the same.
3. チャットボットにプロンプトを提供する
チャットボットに LangGraph ライブラリの “birthday” を参照するようにプロンプトを提供して、チャットボットが必要な情報を取得したら human_assistance ツールにアクセスするように指示します。ツールの引数に name と birthday を設定することで、チャットボットにこれらのフィールドのための提案を生成させます。
user_input = (
"Can you look up when LangGraph was released? "
"When you have the answer, use the human_assistance tool for review."
)
config = {"configurable": {"thread_id": "1"}}
events = graph.stream(
{"messages": [{"role": "user", "content": user_input}]},
config,
stream_mode="values",
)
for event in events:
if "messages" in event:
event["messages"][-1].pretty_print()
================================ Human Message ================================= Can you look up when LangGraph was released? When you have the answer, use the human_assistance tool for review. ================================== Ai Message ================================== [{'text': "Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search function. Then, I'll use the human_assistance tool for review.", 'type': 'text'}, {'id': 'toolu_01JoXQPgTVJXiuma8xMVwqAi', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] Tool Calls: tavily_search_results_json (toolu_01JoXQPgTVJXiuma8xMVwqAi) Call ID: toolu_01JoXQPgTVJXiuma8xMVwqAi Args: query: LangGraph release date ================================= Tool Message ================================= Name: tavily_search_results_json [{"url": "https://blog.langchain.dev/langgraph-cloud/", "content": "We also have a new stable release of LangGraph. By LangChain 6 min read Jun 27, 2024 (Oct '24) Edit: Since the launch of LangGraph Platform, we now have multiple deployment options alongside LangGraph Studio - which now fall under LangGraph Platform. LangGraph Platform is synonymous with our Cloud SaaS deployment option."}, {"url": "https://changelog.langchain.com/announcements/langgraph-cloud-deploy-at-scale-monitor-carefully-iterate-boldly", "content": "LangChain - Changelog | ☁ 🚀 LangGraph Platform: Deploy at scale, monitor LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain Changelog Sign up for our newsletter to stay up to date DATE: The LangChain Team LangGraph LangGraph Platform ☁ 🚀 LangGraph Platform: Deploy at scale, monitor carefully, iterate boldly DATE: June 27, 2024 AUTHOR: The LangChain Team LangGraph Platform is now in closed beta, offering scalable, fault-tolerant deployment for LangGraph agents. LangGraph Platform also includes a new playground-like studio for debugging agent failure modes and quick iteration: Join the waitlist today for LangGraph Platform. And to learn more, read our blog post announcement or check out our docs. Subscribe By clicking subscribe, you accept our privacy policy and terms and conditions."}] ================================== Ai Message ================================== [{'text': "Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Platform was announced. However, the search results don't provide a specific release date for the original LangGraph. \n\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}] Tool Calls: human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN) Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN Args: name: Assistant birthday: 2023-01-01
We’ve hit the interrupt in the human_assistance tool again.
4. 人間のアシスタンスを追加する
チャットボットは正しい日付を識別するのに失敗したので、以下の情報を提供します :
human_command = Command(
resume={
"name": "LangGraph",
"birthday": "Jan 17, 2024",
},
)
events = graph.stream(human_command, config, stream_mode="values")
for event in events:
if "messages" in event:
event["messages"][-1].pretty_print()
================================== Ai Message ================================== [{'text': "Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Platform was announced. However, the search results don't provide a specific release date for the original LangGraph. \n\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}] Tool Calls: human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN) Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN Args: name: Assistant birthday: 2023-01-01 ================================= Tool Message ================================= Name: human_assistance Made a correction: {'name': 'LangGraph', 'birthday': 'Jan 17, 2024'} ================================== Ai Message ================================== Thank you for the human assistance. I can now provide you with the correct information about LangGraph's release date. LangGraph was initially released on January 17, 2024. This information comes from the human assistance correction, which is more accurate than the search results I initially found. To summarize: 1. LangGraph's original release date: January 17, 2024 2. LangGraph Platform announcement: June 27, 2024 It's worth noting that LangGraph had been in development and use for some time before the LangGraph Platform announcement, but the official initial release of LangGraph itself was on January 17, 2024.
これらのフィールドが状態に反映されるようになったことに注意してください :
snapshot = graph.get_state(config)
{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")}
{'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}
これはそれらを下流ノード (e.g., 情報を更に処理したりストアするノード) に簡単にアクセス可能にします。
5. 状態を手動で更新する
LangGraph はアプリケーションの状態に対して高度な制御を与えます。例えば、(割り込まれたときを含む) 任意の時点で graph.update_state を使用してキーを手動で上書きできます :
graph.update_state(config, {"name": "LangGraph (library)"})
{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd4ec5-cf69-6352-8006-9278f1730162'}}
6. 新しい値を確認する
graph.get_state を呼び出せば、新しい値が反映されていることを確認できます :
snapshot = graph.get_state(config)
{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")}
{'name': 'LangGraph (library)', 'birthday': 'Jan 17, 2024'}
手動の状態更新は LangSmith で トレースを生成 します。必要なら、それらは human-in-the-loop ワークフローの制御にも使用できます。一般には interrupt 関数の使用が代わりに推奨されます、状態更新とは独立して human-in-the-loop インタラクションでデータが送信されることを可能にするからです。
Congratulations! より複雑なワークフローを容易にするために状態にカスタムキーを追加して、ツール内から状態更新を生成する方法を学習しました。
以下のコードスニペットを確認してこのチュートリアルからのグラフをレビューしてください :
OpenAI
pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model
os.environ["OPENAI_API_KEY"] = "sk-..."
llm = init_chat_model("openai:gpt-4.1")
Anthropic
pip install -U "langchain[anthropic]"
import os
from langchain.chat_models import init_chat_model
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
from typing import Annotated
from langchain_tavily import TavilySearch
from langchain_core.messages import ToolMessage
from langchain_core.tools import InjectedToolCallId, tool
from typing_extensions import TypedDict
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.types import Command, interrupt
class State(TypedDict):
messages: Annotated[list, add_messages]
name: str
birthday: str
@tool
def human_assistance(
name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]
) -> str:
"""Request assistance from a human."""
human_response = interrupt(
{
"question": "Is this correct?",
"name": name,
"birthday": birthday,
},
)
if human_response.get("correct", "").lower().startswith("y"):
verified_name = name
verified_birthday = birthday
response = "Correct"
else:
verified_name = human_response.get("name", name)
verified_birthday = human_response.get("birthday", birthday)
response = f"Made a correction: {human_response}"
state_update = {
"name": verified_name,
"birthday": verified_birthday,
"messages": [ToolMessage(response, tool_call_id=tool_call_id)],
}
return Command(update=state_update)
tool = TavilySearch(max_results=2)
tools = [tool, human_assistance]
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
message = llm_with_tools.invoke(state["messages"])
assert(len(message.tool_calls) <= 1)
return {"messages": [message]}
graph_builder = StateGraph(State)
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=tools)
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
)
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)
以上