---
title: "LangGraphのTool Callingとは｜仕組みとToolNodeでの実装・create_agentとの使い分け"
url: "https://www.issoh.co.jp/tech/details/5428/"
published: 2025-02-19
updated: 2026-09-27
categories: ["AIエージェント・MCP"]
publisher: "株式会社一創"
---

# LangGraphのTool Callingとは｜仕組みとToolNodeでの実装・create\_agentとの使い分け

Tool Callingでいちばん誤解されているのは、「LLMがツールを実行してくれる機能」だと思われている点です。実際にはLLMはツールを実行しません。返すのは「このツールを、この引数で呼んでほしい」という`tool_calls`という要求だけで、実行するのはアプリケーション側のコードです。LangGraphはこの往復をグラフの辺として組み立てるためのフレームワークで、実行役を担うのが`ToolNode`、往復を続けるか終えるかを判定するのが`tools_condition`にあたります。この記事では、その仕組みを動くコードで示したうえで、2025年10月のv1.0で`create_react_agent`が非推奨になった件と、自前グラフと`create_agent`のどちらを選ぶかの判断基準までを扱います。

## まとめ

- Tool CallingはLLMがツールを実行する機能ではない。LLMが返すのは`tool_calls`（ツール名・引数・IDの組）だけで、実行と結果の差し戻しはアプリ側の責務。
- Function Calling・Tool Use・Tool Callingは同じ仕組みの別名。OpenAIが「Function Calling」で広めた呼称が、複数ツールを前提とする「Tool Calling」に統一されつつある。
- LangGraphでの最小構成は4点セット。`@tool`でツールを定義し、`bind_tools()`でモデルに渡し、`ToolNode`で実行し、`tools_condition`でループを閉じる。
- `langgraph.prebuilt.create_react_agent`はv1.0で非推奨。移行先は`langchain.agents.create_agent`。ただし`langgraph.prebuilt`モジュール自体は現役で、`ToolNode`と`tools_condition`はそのまま使える。
- `ToolNode`の`handle_tool_errors`は既定で「引数が不正な呼び出し」を捕まえるが、ツール関数の中で起きた例外まで自動で握りつぶすわけではない。外部API連携では例外処理を自分で書く。

以下、モデルが実際に何を返すのかというところから順に見ていきます。

## Tool Callingの仕組み：モデルはツールを実行しない

LLMは学習済みの重みからテキストを生成するだけの存在なので、今日の為替レートを引いたり、社内DBを検索したり、メールを送ったりはできません。Tool Callingは、この制約を「モデルに実行させる」のではなく「モデルに指示を出させる」ことで回避する仕組みです。LangChainの公式ドキュメントも、モデル自身はツールを実行せず、いつ呼ぶかを決めるだけだと明記しています。

### モデルが返すのはtool\_callsという実行要求

あらかじめツールの名前・説明・引数スキーマをモデルに渡しておくと、モデルは「このユーザー入力にはこのツールが要る」と判断したときに、通常のテキストではなく構造化された呼び出し要求を返します。LangChainではこれが`AIMessage.tool_calls`に入り、中身は次の3フィールドです。

| フィールド | 型                       | 中身         |
| ----- | ----------------------- | ---------- |
| name  | str                     | 呼び出すツール名   |
| args  | dict                    | ツールに渡す引数   |
| id    | str \| None             | この呼び出しの識別子 |
| type  | Literal\[“tool\_call”\] | 判別用（省略可）   |

この`id`が結果の差し戻しに効いてきます。ツールを実行したら、結果は`ToolMessage`として会話履歴に積み直しますが、その際`tool_call_id`に同じIDを入れて「どの要求への答えか」を対応付ける必要があります（`tool_call_id`は`ToolMessage`の必須フィールドです）。複数のツールが同時に呼ばれたときに結果が取り違えられないのは、このIDのおかげです。`ToolMessage`には`status`フィールドもあり、既定は`"success"`、失敗を伝えるときは`"error"`を入れます。

つまり1ターンの実体は、モデル呼び出し → tool\_calls受領 → アプリ側で実行 → ToolMessageで差し戻し → 再びモデル呼び出し、という往復です。この往復を手で書くと煩雑になるため、LangGraphがグラフとして構造化します。

### Function Calling・Tool Useとの呼称の違い

「LangGraph function calling」で検索してたどり着いた方向けに整理すると、Function CallingとTool Callingは対立する別技術ではありません。同じ仕組みに付けられた別名です。OpenAIが2023年に`functions`パラメータで導入した際の名称が「Function Calling」で、その後、単一関数だけでなくコード実行や検索といった多様な「ツール」を扱う前提に広がり、API上も`tools`／`tool_calls`という語に置き換わりました。AnthropicはこれをTool Useと呼びます。LangChainは`bind_tools()`という統一インターフェースを提供し、どのプロバイダのモデルでも同じ書き方で扱えるようにしています。

OpenAI APIそのものでの実装（`tools`パラメータの書式やレスポンス構造）を追いたい場合は、[Function Callingとは｜仕組みとOpenAI APIでの実装をコードで解説](/tech/details/4631/)で個別に扱っています。本記事はその上に載るLangGraph側のグラフ構築に絞ります。

## LangGraphでのTool Calling実装：@tool・bind\_tools・ToolNode

ここからは実際に動くコードです。前提は Python 3.10以上（langgraph 1.2系・langchain 1.3系ともに`requires_python >=3.10`）です。バージョンは明示的に固定してください。

```
pip install "langgraph>=1.2" "langchain>=1.3" langchain-openai
```

Python 3.9以下の環境では、pipが要件を満たす最新版を選べずlanggraph 0.6系・langchain 0.3系まで落ちます。この0.x系には後述の`create_agent`が存在せず、本記事のコードは動きません。まず`python -V`で3.10以上であることを確認してください。

### ツールを定義する（@toolと型ヒント）

`@tool`デコレータを付けた関数が、そのままモデルに渡せるツールになります。ここで手を抜けないのが**型ヒントとdocstring**です。型ヒントが引数スキーマに変換され、docstringがツールの説明としてモデルに送られます。モデルはこの説明だけを手がかりに「どのツールを呼ぶか」を決めるため、docstringが曖昧だとツール選択そのものが外れます。

```
from langchain.tools import tool

@tool
def get_weather(city: str) -> str:
    """指定した都市の現在の天気を返す。cityは日本語の都市名で渡す。"""
    return f"{city}の天気は晴れ、気温は22度です。"

@tool
def get_exchange_rate(base: str, quote: str) -> str:
    """2通貨間の為替レートを返す。baseとquoteはISO 4217の3文字コード。"""
    return f"1 {base} = 155.2 {quote}"
```

「天気を調べる」のような漠然としたdocstringではなく、引数の形式まで書き切ります。上の`get_exchange_rate`で「ISO 4217の3文字コード」と指定しているのは、そう書かないとモデルが「日本円」「ドル」といった日本語を渡してくるためです。

### モデルにツールを渡す（bind\_tools）

`bind_tools()`でツール一覧をモデルに結び付けます。返ってくるのはツール付きの新しいモデルオブジェクトで、元のモデルは変わりません。

```
from langchain.chat_models import init_chat_model

tools = [get_weather, get_exchange_rate]
model = init_chat_model("openai:gpt-5.6").bind_tools(tools)

response = model.invoke("東京の天気は？")
print(response.tool_calls)
# [{'name': 'get_weather', 'args': {'city': '東京'}, 'id': 'call_abc123', 'type': 'tool_call'}]
print(response.content)
# '' （テキスト本文は空。モデルは要求を返しただけで実行はしていない）
```

この出力が、前章で説明した「モデルは実行しない」の実物です。`content`は空で、`tool_calls`だけが返ります。ここで処理を止めれば、天気は永遠に取得されません。

### StateGraphにToolNodeとtools\_conditionを組み込む

実行役と分岐役をグラフに載せて、往復を閉じます。`ToolNode`が`tool_calls`を受け取ってツールを実行し、結果を`ToolMessage`にして状態へ書き戻します。`tools_condition`は直前の`AIMessage`に`tool_calls`があれば`"tools"`を、なければ`"__end__"`を返す条件関数で、これがループの出口になります。

```
from langgraph.graph import StateGraph, START, END, MessagesState
from langgraph.prebuilt import ToolNode, tools_condition

def call_model(state: MessagesState):
    return {"messages": [model.invoke(state["messages"])]}

builder = StateGraph(MessagesState)
builder.add_node("llm", call_model)
builder.add_node("tools", ToolNode(tools))

builder.add_edge(START, "llm")
builder.add_conditional_edges("llm", tools_condition)
builder.add_edge("tools", "llm")

graph = builder.compile()

result = graph.invoke({"messages": [{"role": "user", "content": "東京の天気と、1ドル何円か教えて"}]})
print(result["messages"][-1].content)
```

`builder.add_edge("tools", "llm")`が要です。ツール実行後に必ずモデルへ戻すことで、モデルは`ToolMessage`を読んで「もう1本ツールが要る」か「答えを書ける」かを再判断します。この辺を張り忘れると、ツールを実行したところでグラフが終わり、ユーザーには何も返りません。`tools_condition`は`add_conditional_edges`の第2引数に直接渡すだけで、行き先の辞書を省略できます。ただしこれが成立するのは**ツールノードの名前が`"tools"`のときだけ**です。`tools_condition`の戻り値は`"tools"`か`"__end__"`という固定の文字列で、その値がそのままノード名として解決されるためです。別名を付けた場合は対応表を明示します。

```
builder.add_node("my_tools", ToolNode(tools))
builder.add_conditional_edges("llm", tools_condition, {"tools": "my_tools", "__end__": END})
```

## create\_react\_agentは非推奨：langchain.agents.create\_agentへ

ここが2026年時点でいちばん事故りやすい箇所です。日本語の解説記事の多くは、いまだに`from langgraph.prebuilt import create_react_agent`を載せています。2025年10月22日のLangChain 1.0／LangGraph 1.0で、この関数は非推奨になりました。公式リファレンスは「This function is deprecated in favor of `create_agent` from the langchain package」と明記し、`from langchain.agents import create_agent`へのimport変更を指示しています。

### 移行前後のコード

```
# 旧（非推奨）
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(model, tools)

# 新
from langchain.agents import create_agent
agent = create_agent("openai:gpt-5.6", tools)

result = agent.invoke({"messages": [{"role": "user", "content": "東京の天気は？"}]})
```

単なる改名ではありません。`create_agent`はミドルウェア機構を持ち、`before_model`／`wrap_tool_call`／`after_model`といったフックでエージェントの各段に処理を差し込めます。人間の承認を挟む、履歴を要約する、PIIをマスクする、といった要求は、以前ならグラフを自前で組み直す必要がありましたが、いまはミドルウェアで足ります。[LangChain v1.0の概要と新機能：v0.xからの刷新点・新要素を含むアップデート全体像](/tech/details/9663/)で刷新点の全体像を扱っています。

### langgraph.prebuiltは現役（ToolNodeとtools\_conditionは残る）

「`create_react_agent`が非推奨」を「`langgraph.prebuilt`が廃止」と読み違えないでください。非推奨になったのは`create_react_agent`という関数ひとつです。`langgraph.prebuilt`モジュール自体は現役で、`ToolNode`・`tools_condition`・`InjectedState`・`InjectedStore`・`ValidationNode`・`ToolRuntime`・`ToolCallTransformer`を引き続き提供します。前章の`StateGraph`実装はそのまま有効です。

依存の向き自体も、この1.0で読み替えが必要になりました。かつて「LangGraphはLangChainの上に構築された拡張」と説明されていましたが、現在は逆で、LangChainの`create_agent`がLangGraphランタイム上で動きます。両者の関係は[LangChainとLangGraphの違い｜v1.0で逆転した関係と使い分け](/tech/details/4059/)で整理しています。

## ToolNodeのエラー処理と並列実行

ここは本番投入時に効いてくる挙動で、公式リファレンスを読まないと気付きにくい部分です。

### handle\_tool\_errorsの既定は「引数不正」を拾うもの

`ToolNode`のシグネチャは以下です。

```
ToolNode(
    tools,
    *,
    name: str = "tools",
    tags: list[str] | None = None,
    handle_tool_errors=...,   # 既定は内部の _default_handle_tool_errors
    messages_key: str = "messages",
    wrap_tool_call=None,
    awrap_tool_call=None,
)
```

`handle_tool_errors`の既定が拾うのは、モデルが不正な引数を渡したこと（tool invocation errors）に起因する失敗です。エラー内容が`ToolMessage`としてモデルへ返され、モデルは引数を直して呼び直せます。ここを「ツール内で起きたあらゆる例外を自動で握ってくれる」と読むと危険です。実装のdocstringは、ツール実行時のエラーは無視して再送出する（Ignores tool execution errors — they will be re-raised）と明言しています。外部APIのタイムアウトや認証失敗といった実行時の例外は、ツール関数の側で処理するのが前提です。

```
import httpx
from langchain.tools import tool

API_ENDPOINT = "https://api.example.com/quote"

@tool
def get_stock_price(symbol: str) -> str:
    """銘柄コードから現在株価を返す。symbolはティッカーシンボル。"""
    try:
        resp = httpx.get(API_ENDPOINT, params={"symbol": symbol}, timeout=5.0)
        resp.raise_for_status()
    except httpx.HTTPError as e:
        return f"株価を取得できませんでした（{type(e).__name__}）。銘柄コードを確認してください。"
    return f"{symbol}: {resp.json()['price']}円"
```

例外を文字列で返しているのは、モデルに読ませて次の判断をさせるためです。例外を送出したままにすると、グラフ全体が落ちてユーザーには何も返りません。挙動を明示的に変えたいときは、`handle_tool_errors`に`True`（全捕捉）、`False`（無効化）、文字列（その文字列を固定のエラーメッセージとして返す）、例外クラスやそのタプル（捕捉する例外を限定）、コールバック関数（エラーから返却メッセージを組み立てる）のいずれかを渡します。

### 複数のtool\_callsは並列で実行される

1つの`AIMessage`に`tool_calls`が複数入っていた場合、`ToolNode`はそれらを並列に実行します。同期実行（`invoke`）ではThreadPoolExecutor、非同期実行（`ainvoke`）ではasyncioで走ります。冒頭のコード例で「東京の天気と、1ドル何円か教えて」と聞いたとき、`get_weather`と`get_exchange_rate`は逐次ではなく同時に走り、両方の`ToolMessage`が揃ってからモデルに戻ります。

この設計は速い代わりに、**ツール関数がスレッドセーフである必要がある**ことを意味します。モジュールレベルのグローバル変数を書き換える、スレッドセーフでないDBクライアントを共有する、といった実装は競合します。外部APIのレート制限も、想定より短時間に呼び出しが集中する前提で設計してください。

## 自前グラフとcreate\_agentのどちらを選ぶか

ここは立場を明確にします。**大半のケースでは、`StateGraph`を自前で組む必要はありません。** 前章までで示した`StateGraph`＋`ToolNode`＋`tools_condition`の構成は、`create_agent`が内部でやっていることとほぼ同じです。「LangGraphを使っている感」を出すために自前でグラフを書くのは、保守すべきコードを増やしているだけです。

自前グラフに倒すべき条件は、次のいずれかに当てはまるときに限られます。

- ツール実行の前後に、エージェントのループとは無関係なノード（バッチ処理、別モデルによる検証、外部ワークフローへの受け渡し）を挟む必要がある。
- ツール結果によってエージェント自体を分岐させ、複数の異なるエージェントへルーティングする（マルチエージェント構成）。
- 条件分岐が`tools_condition`の「tool\_callsがあるか否か」では表現できない（たとえば特定ツールの結果値でループを打ち切る）。

逆に、「ツールを呼んで答えを返す」だけのエージェントに自前グラフは不要です。人間の承認を挟みたい、履歴を要約したい、といった要求もミドルウェアで足りるため、それを理由にグラフを書き起こす判断は現在では古くなっています。検索と組み合わせて回答精度を上げたい場合の構成は[Agentic RAGのアーキテクチャと構成要素を詳しく解説](/tech/details/8079/)が近く、できあがったエージェントを運用環境に載せる段階では[LangGraph Platform（旧 LangGraph Cloud）とは？デプロイ手順・Studio・料金を実践解説【2026年版】](/tech/details/6175/)を参照してください。

## よくある質問

### Tool CallingとFunction Callingは何が違いますか？

仕組みは同じで、呼称の違いです。OpenAIが2023年に導入した`functions`パラメータの名称が「Function Calling」で、複数ツールを扱う前提へ拡張される過程でAPI上も`tools`／`tool_calls`に置き換わり、業界的にはTool Callingという呼び方が一般化しました。AnthropicはTool Useと呼びます。LangChainでは`bind_tools()`に統一されているため、モデルを差し替えてもコードは変わりません。

### create\_react\_agentはもう使えないのですか？

非推奨ですが、langgraph 1.2.9時点で削除はされておらず、まだ動きます。削除される版は公式に告知されていません（非推奨の分類は「v1.0以降」であることのみ示されています）。ただし公式は`from langchain.agents import create_agent`への移行を指示しているため、新規実装で使う理由はなく、2.0での削除に備えて早めに移行しておくのが安全です。既存コードは`create_agent`へ置き換えたうえで、承認フローや履歴要約はミドルウェアに寄せるのが移行の筋です。

### ToolNodeを使うとツールのエラーは自動で処理されますか？

されるのは、モデルが不正な引数で呼んだケースだけです。既定の`handle_tool_errors`はその失敗を`ToolMessage`としてモデルに差し戻し、呼び直させます。ツール関数の内部で起きたHTTPエラーやタイムアウトは対象外なので、ツール側で捕捉してエラー内容を文字列で返してください。

### ツールが同時に複数呼ばれたときの順序は制御できますか？

`ToolNode`は同一`AIMessage`内の`tool_calls`を並列に実行するため、実行順序は保証されません。順序に依存する処理（Aの結果を使ってBを呼ぶ）は、1つのツールにまとめるか、グラフのノードを分けて逐次のエッジで結びます。並列実行される以上、ツール関数はスレッドセーフに書く必要があります。

### LangGraphのTool Callingに対応しているモデルは？

`bind_tools()`を実装しているチャットモデルであれば使えます。OpenAI、Anthropic、Google、Amazon Bedrock経由の各モデルなど主要プロバイダは対応しています。ツール呼び出しに未対応のモデルではエラーになるため、ローカルLLMを使う場合は、そのモデルがツール呼び出し用にファインチューニングされているかを事前に確認してください。

## 関連記事

- [LangChainとLangGraphの違い｜v1.0で逆転した関係と使い分け](/tech/details/4059/)
- [Function Callingとは｜仕組みとOpenAI APIでの実装をコードで解説](/tech/details/4631/)
- [LangChain v1.0の概要と新機能：v0.xからの刷新点・新要素を含むアップデート全体像](/tech/details/9663/)
- [Agentic RAGのアーキテクチャと構成要素を詳しく解説](/tech/details/8079/)
- [LangGraph Platform（旧 LangGraph Cloud）とは？デプロイ手順・Studio・料金を実践解説【2026年版】](/tech/details/6175/)

---

出典: [LangGraphのTool Callingとは｜仕組みとToolNodeでの実装・create\_agentとの使い分け](<https://www.issoh.co.jp/tech/details/5428/>)（株式会社一創）
