Agent のツール呼び出しが無限ループに陥る:ツール定義の明確化・最大イテレーション数・フォールバック設計
はじめに
Dify の Agent が同じツールを何度も繰り返し呼び出す、あるいは「情報が見つからない → 再検索 → また見つからない」のループに入って止まらなくなる――この問題はトークンコストの浪費だけでなく、ユーザー体験を著しく損なう。
Agent の無限ループは一見「モデルが賢くない」ように見えるが、実際にはシステム設計の問題であることが大半だ。Dify の公式ドキュメントでは、Agent ノードに Maximum Iterations 設定が存在すること、環境変数 MAX_ITERATIONS_NUM でプラットフォームレベルの上限を設定できることが明示されている。つまり、この問題は「プラットフォームの上限設定 + ツール定義の品質 + プロンプトの退出条件」の三要素を適切に設計することで、大幅に軽減できる。
症状
| 症状 | 内部で起きていること |
|---|---|
| 同じツールが5回以上連続で呼び出される | ツールの戻り値を正しく解釈できていない |
| Agent が「もう少し調べます」と言い続ける | 退出条件がプロンプトに定義されていない |
| 異なるパラメータで同じツールを繰り返す | ツールの使用条件が曖昧で、パラメータ変更で解決しようとする |
| レスポンスが返るまで数分かかる | イテレーション数の上限が未設定で、コスト制限に到達するまで実行される |
| 回答が「ツールの結果を確認中です…」で止まる | ツールがエラーを返しているが、Agent がエラーを理解できていない |
原因分析
Agent の意思決定ループを理解する
Dify の Agent(ReAct方式)は、以下のループを繰り返すことで問題を解決する。
flowchart TD
A[ユーザーの質問] --> B[思考 Thought]
B --> C{ツール呼び出しが必要?}
C -->|Yes| D[行動 Action: ツール呼び出し]
D --> E[観察 Observation: ツールの結果]
E --> F{回答できる?}
F -->|No| B
F -->|Yes| G[最終回答 Final Answer]
C -->|No| G
無限ループは、「回答できる?」のステップで常に「No」と判断される 場合に発生する。
原因1:ツール定義(Description)が曖昧
ツールの description はモデルがツールを「いつ使うか」「何を期待できるか」を判断する最も重要な入力である。
悪い例:
tool:
name: search_database
description: "データベースを検索します"
この定義では以下が不明:
- どんなデータベースか
- どんなクエリに対応しているか
- 結果が見つからない場合はどうなるか
- どんな形式で結果が返るか
良い例:
tool:
name: search_employee_database
description: |
社員情報データベースを検索します。
入力: 社員名(姓名)または社員番号
出力: 社員名、部署、内線番号、メールアドレスを含むJSON
制約:
- 部分一致検索に対応
- 結果が見つからない場合は空の配列 [] を返す
- 一度に最大10件まで返す
注意: 退職者の情報は含まれません
原因2:ツールのエラーハンドリングが不十分
ツールがエラーを返した場合や結果が空の場合に、Agent がそれを「もう一度試せば結果が変わるかもしれない」と解釈するケースが多い。
ループの例:
1. Agent: search_database("田中太郎") → 結果なし
2. Agent: "もう少し調べてみます"
3. Agent: search_database("田中 太郎") → 結果なし
4. Agent: "別の方法で検索します"
5. Agent: search_database("タナカタロウ") → 結果なし
6. Agent: "さらに調べます..." → 以後繰り返し
原因3:Maximum Iterations が未設定
Dify の Agent ノードには Maximum Iterations パラメータがあるが、デフォルト値が十分に制限的でない場合、コストが膨張してから初めて停止する。
| 設定 | 値 | 説明 |
|---|---|---|
| Agent ノードの Maximum Iterations | デフォルト値 | ノード単位のイテレーション上限 |
MAX_ITERATIONS_NUM 環境変数 | プラットフォームレベル | 全 Agent に適用されるグローバル上限 |
原因4:プロンプトに退出条件がない
多くのシステムプロンプトが「ユーザーの質問に答えてください」という前向きな指示だけで、「どういう場合に諦めるか」を明示していない。
典型的な問題のあるプロンプト:
あなたは社内ヘルプデスクアシスタントです。
ユーザーの質問に対して、利用可能なツールを活用して
正確な回答を提供してください。
この指示だけでは、Agent は「正確な回答を提供する」ことを最優先し、見つからない場合でも諦めずに試行を続ける。
原因5:ツール間の役割分担が不明確
複数のツールが似た機能を持つ場合、Agent がどちらを使うべきか判断できず、交互に呼び出すループに入ることがある。
1. Agent: search_knowledge_base("VPN設定方法") → 部分的な結果
2. Agent: search_faq("VPN設定方法") → 別の部分的な結果
3. Agent: "もう少し調べます"
4. Agent: search_knowledge_base("VPN 設定 手順") → 似た結果
5. Agent: search_faq("VPN接続できない") → 別の結果
6. → 繰り返し
解決策
解決策1:Maximum Iterations を適切に設定する
Agent ノードレベル:
Dify の Workflow エディタで Agent ノードを選択し、Maximum Iterations を設定する。
| ユースケース | 推奨イテレーション数 | 理由 |
|---|---|---|
| 単純な情報検索(FAQ応答) | 3〜5 | 1〜2回の検索で十分 |
| 複合的なタスク(調査・分析) | 5〜8 | 複数ツールの組み合わせが必要 |
| マルチステップ処理 | 8〜12 | 段階的な処理が前提 |
| 最大でもこれ以上は不要 | 15 | これ以上はほぼ確実に無限ループ |
プラットフォームレベル(セルフホスト環境):
# .env ファイル
MAX_ITERATIONS_NUM=15 # 全Agent共通の最大イテレーション数
解決策2:ツール定義を改善する
各ツールに以下の情報を含める:
tools:
- name: search_employee
description: |
社員情報を検索します。
【用途】社員の連絡先、所属部署を調べるとき
【入力】社員名(姓または名)、または社員番号(E+数字5桁)
【出力形式】
- 見つかった場合: {"found": true, "employees": [...]}
- 見つからなかった場合: {"found": false, "message": "該当なし"}
【制限事項】
- 退職者は検索対象外
- 一度に10件まで
【注意】結果が見つからなかった場合、パラメータを変えて
再度呼び出しても結果は変わりません。
parameters:
query:
type: string
description: "社員名または社員番号"
required: true
- name: search_knowledge_base
description: |
社内ナレッジベースを検索します。
【用途】社内規程、手順書、マニュアルの内容を調べるとき
【入力】自然言語のクエリ(日本語)
【出力形式】
- 関連チャンクのリスト(最大5件、relevance_score付き)
- 関連情報がない場合: 空リスト []
【このツールで検索できないもの】
- 社員の個人情報 → search_employee を使用
- リアルタイムのシステム障害情報 → check_system_status を使用
【注意】同じクエリで2回以上呼び出しても結果は同じです。
結果が不十分な場合はクエリの表現を変えてください。
解決策3:システムプロンプトに退出条件を明記する
# System Prompt
あなたは株式会社ABCの社内ヘルプデスクAIアシスタントです。
## 基本ルール
- 利用可能なツールを活用して、ユーザーの質問に正確に回答してください
- 回答の根拠は必ずツールの検索結果に基づくこと
## 退出条件(重要)
以下の条件に該当する場合は、ツール呼び出しを停止し、
適切な回答を返してください:
1. **同じツールを2回呼び出しても有効な結果が得られない場合**
→ 「申し訳ございませんが、現在のナレッジベースにはこの質問に
該当する情報が見つかりませんでした。IT部門(内線: 1234)に
お問い合わせください。」
2. **ツールがエラーを返した場合**
→ エラー内容をユーザーに伝え、別の問い合わせ方法を案内してください
3. **ユーザーの質問が対応範囲外の場合**
→ 対応範囲外であることを伝え、適切な問い合わせ先を案内してください
4. **すでに十分な情報が得られている場合**
→ 追加のツール呼び出しは不要です。得られた情報で回答してください
## 禁止事項
- 同じツールを同じパラメータで2回以上呼び出さないこと
- 3回連続でツール呼び出しが空結果だった場合、それ以上の試行を行わないこと
- 「もう少し調べます」「別の方法で検索します」と言って呼び出しを続けないこと
解決策4:フォールバックパスを設計する
Agent が行き詰まった場合の段階的なフォールバックを設計する。
flowchart TD
A[ユーザー質問] --> B[ツール呼び出し 1回目]
B --> C{有効な結果?}
C -->|Yes| D[回答生成]
C -->|No| E[ツール呼び出し 2回目 クエリ変更]
E --> F{有効な結果?}
F -->|Yes| D
F -->|No| G[フォールバック: ナレッジベース直接検索]
G --> H{有効な結果?}
H -->|Yes| I[ナレッジベースの情報で回答]
H -->|No| J[人間への引き継ぎメッセージ]
Workflow での実装: Agent ノードの後に IF/ELSE ノードを配置し、Agent 出力に「見つかりませんでした」が含まれる場合はナレッジベース直接検索ノードへ、それでも結果がなければ人間引き継ぎ用の LLM ノードへ分岐させる。
解決策5:ツール間の役割境界を明確にする
## ツール使用ガイドライン(System Prompt に含める)
利用可能なツールと使い分け:
| 質問の種類 | 使用するツール | 使わないツール |
|-----------|--------------|--------------|
| 社員の連絡先・部署 | search_employee | search_knowledge_base |
| 社内規程・手順 | search_knowledge_base | search_employee |
| システム障害の状況 | check_system_status | search_knowledge_base |
| 会議室の予約状況 | check_room_availability | search_employee |
重要: 上記の対応表に従ってツールを選択してください。
対応表にないタイプの質問には、ツール呼び出しを行わず
「この種類のお問い合わせには対応しておりません」と回答してください。
解決策6:Agent ログによるデバッグ
無限ループが発生した場合、まず Agent のログを確認する。
確認すべきポイント:
| 確認項目 | 判断基準 |
|---|---|
| 繰り返し呼ばれているツール | ツール定義の改善が必要 |
| パラメータが毎回同じか | 同じならモデルが結果を解釈できていない |
| Thought の内容 | 「もう少し調べます」→ 退出条件不足 |
| Maximum Iterations 到達で停止か | 到達していなければ上限未設定の可能性 |
Dify コンソールの「ログと注釈」タブから、問題の会話を選択し、各イテレーションの Thought / Action / Observation を順に確認してループの開始点を特定する。
予防策
1. Agent 設計チェックリスト
新しい Agent を構築する際に以下を確認する:
- Maximum Iterations が設定されているか(推奨: 5〜10)
- 各ツールの description に「結果がない場合」の挙動が明記されているか
- システムプロンプトに退出条件が含まれているか
- 複数ツールの役割境界が明確か
- フォールバックパス(人間への引き継ぎ等)が設計されているか
- ツールのエラーレスポンスが Agent にとって理解可能な形式か
2. テストシナリオ
本番投入前に、以下の「失敗シナリオ」を必ずテストする:
| テストケース | 期待する挙動 |
|---|---|
| 存在しない社員名で検索 | 2回以内に「見つかりません」と回答 |
| ナレッジベースにない質問 | 3回以内にフォールバックメッセージ |
| ツールがエラーを返す場合 | エラーメッセージとともに代替案を提示 |
| 対応範囲外の質問 | ツール呼び出しなしで範囲外を案内 |
| 曖昧な質問 | 1回の検索後、ユーザーに確認を求める |
3. コスト監視
Agent の無限ループは直接的にトークンコストに反映される。
# 環境変数でコスト関連の上限を設定
MAX_ITERATIONS_NUM=15 # イテレーション上限
WORKFLOW_MAX_EXECUTION_TIME=300 # 5分でタイムアウト
監視すべき指標:
| 指標 | 警告閾値 | 対応 |
|---|---|---|
| 1会話あたりの平均イテレーション数 | 5回超 | ツール定義・プロンプト見直し |
| 1会話あたりのトークン消費量 | 10,000超 | Agent の設計見直し |
| 同一ツールの連続呼び出し回数 | 3回超 | 退出条件の強化 |
| Maximum Iterations 到達率 | 10%超 | 上限値と退出条件の見直し |
4. 段階的な Agent 複雑化
最初からすべてのツールを持たせず、Phase 1(ナレッジベース検索のみ)→ Phase 2(+ 社員検索)→ Phase 3(+ システム状態確認)→ Phase 4(+ 予約・申請系)と段階的にツールを追加し、各段階で退出条件とルーティングを検証する。
まとめ
Agent の無限ループは「モデルの能力不足」ではなく、「いつ停止すべきかをシステムが教えていない」ことが根本原因である。効果的な対策は以下の三要素を同時に設計することで実現できる:
- プラットフォーム上限:
Maximum IterationsとMAX_ITERATIONS_NUMで物理的な停止条件を設定する - ツール定義の明確化:各ツールの description に、用途・入出力・制限事項・結果が空の場合の挙動を明記する
- プロンプトの退出条件:「何回試しても結果がない場合は停止する」「同じツールを同じパラメータで再呼び出ししない」といった明示的なルールをシステムプロンプトに含める
これら三要素のうち一つでも欠けていると、無限ループのリスクは残り続ける。Agent の設計は「何ができるか」だけでなく、「いつ諦めるか」まで含めて完成となる。