Skip to Content
Docs01. 基礎概念Agent ループ
27:05

AI 合成音声 · VOICEVOX Nemo(女声1・男声1)

音声の一覧・再生リストへ

Agent ループ

この記事の目的

Agent ループの 1 周で何が起きているかを説明でき、停止条件・エラーの返し方・履歴の増加という 3 つの設計ポイントを、自分のシステムに当てはめて判断できるようになります。

対象読者

  • 初めて Agent ループを実装するアプリケーションエンジニア
  • フレームワークを使っているが、その抽象の下で何が起きているかを理解したいエンジニア

前提知識

  • AI Agent とは何か — Agent の定義と構成要素
  • LLM API の基本(チャット履歴を渡して応答を得る流れ)

本文

概要: ループが Agent を作る

LLM API の 1 回の呼び出しは、入力に対して 1 つの応答を返すだけの、状態を持たない関数に近いものです。Agent らしい振る舞い — 状況を見て、行動し、結果を確かめて次を決める — は、この呼び出しを「観測 → 思考 → 行動」のサイクルで繰り返すことで生まれます。この繰り返しの制御構造が Agent ループ(agent loop) です。

Agent ループ: 概要: ループが Agent を作るの図Agent ループ: 概要: ループが Agent を作るの図
Agent ループ: 概要: ループが Agent を作るの図
図を元の大きさで表示

図の中をスクロールして読めます。キーボードでは図の領域へ Tab で移動し、矢印キーを使います。読み終わったら、この見出しをもう一度選ぶと閉じます。

Agent ループ: 概要: ループが Agent を作るの図Agent ループ: 概要: ループが Agent を作るの図

詳細: 1 イテレーションの分解

ループの 1 周は次の 5 段階で構成されます。

  1. コンテキスト組み立て — システムプロンプト・会話履歴・これまでのツール結果をまとめて入力を作ります。何を入れ、何を削るかが品質とコストを左右します
  2. LLM 呼び出し — モデルが状況を解釈し、次の一手を決めます
  3. 応答の解釈 — 本文と停止理由を合わせて調べます。ツール要求、正常終了の最終応答、生成上限による打ち切り、拒否、継続可能な停止を区別します。ツール要求がないことだけでは正常完了と判定できません
  4. ツール実行と結果の追記 — アプリケーション側でツールを実行し、結果(成功でも失敗でも)を履歴に追記します。これが次の周の「観測」になります
  5. 停止判定 — 正常完了以外に、上限やエラーによる強制終了を判定します

詳細: 停止条件は「正常完了」以外に必ず用意する

モデルが最終応答を返すことだけを終了条件にすると、判断を誤ったときに止まりません。停止条件は最低でも次の 4 系統を設計します。

停止条件トリガー終了時にやること
正常完了API の正常終了理由と有効な最終応答を確認できる成果物を返す。業務上の成功条件は別途検証する
上限到達最大ステップ数 / タイムアウト / コスト上限 / 出力・コンテキスト上限途中経過と未完了理由を報告する。不完全なツール要求は実行しない
エラー確定回復不能なエラー(認証失敗、対象消失など)エラー内容と実行済みの操作を報告する
人間の介入ユーザーのキャンセル / 承認拒否状態を保存し、再開可能にする

強制終了時に途中経過を捨てないことが重要です。20 ステップ分の作業結果は、未完了でもユーザーにとって価値があります。

拒否応答も、HTTP リクエスト自体は成功していてもタスクの正常完了とは区別します。継続可能な停止は履歴を維持して再開できますが、再開回数にも上限を適用します。停止理由の値と継続方法は採用 API の契約へ対応づけます。

詳細: ツールの失敗はループに返す

ツール実行の失敗を例外としてループの外に投げると、モデルは何が起きたかを知る機会を失います。エラーメッセージはモデルへの観測データです。「引数の形式が違う」「対象が見つからない」といった情報を履歴に返せば、モデルは引数を直す・別の手段を試すといった回復行動を取れます。リトライをコード側で行うかモデルに任せるかの使い分けは エラー処理・リトライ・フォールバック設計 で扱います。

詳細: 履歴は単調増加する

ループが回るたびに、履歴にはモデルの応答とツール結果が追記され続けます。長いタスクではコンテキストウィンドウの上限・入力トークンのコスト・重要情報の埋没という 3 つの問題に必ず突き当たります。対処(刈り込み・要約・外部化)は メモリと状態管理 を参照してください。

設計判断: ループを自前で書くか、フレームワークに任せるか

選択向いている状況注意点
自前実装制御・ログ・権限チェックを細かく握りたい。仕組みを学びたいループ自体は数十行。周辺(リトライ・監視)の作り込みは必要
フレームワーク標準的な構成で早く作りたい。周辺機能(履歴管理・トレース)込みで欲しい抽象の下の挙動(停止条件のデフォルト等)を把握しないとデバッグできない

どちらを選ぶ場合でも、一度は最小のループを自分で書いてみることを推奨します。以下のとおり、本質は短いコードです。

実装例: 最小の Agent ループ

ベンダー中立の擬似コードです(実際の API 呼び出し部分は各 SDK に読み替えてください)。

MAX_STEPS = 20 def run_agent(task: str) -> str: history = [user_message(task)] for step in range(MAX_STEPS): response = llm_call(SYSTEM_PROMPT, history, TOOLS) history.append(response) state = classify_stop_reason(response) # API 固有の停止理由を共通の状態へ変換 if state == "complete" and valid_final_response(response): return response.text if state == "continue": continue # 再開も MAX_STEPS の範囲内 if state != "tool_calls" or not response.tool_calls: raise AgentIncomplete(state, response.text) # 途中出力を保持。成功として返さない for call in response.tool_calls: # 行動 try: result = execute_tool(call) # 実行はアプリ側の責務 except ToolError as e: result = f"ツールエラー: {e}" # 失敗も観測としてモデルに返す history.append(tool_result_message(call, result)) raise StepLimitExceeded("最大ステップ数に達しました") # 上限による強制終了

この擬似コードを実際の SDK で動く形にした完全版が examples/python/tool-use/ にあります。

実務での注意点

アンチパターン

  • 停止条件がモデル任せだけ → モデルが「完了」を出し損ねると無限に回り、コストが暴走する → 最大ステップ数・タイムアウト・コスト上限を必ずコード側に置く
  • ツール要求がない応答をすべて成功とする → トークン上限による途中出力や拒否を完成品として返す → 停止理由と最終応答の妥当性を確認する
  • ツールエラーで例外を投げてループごと落とす → モデルに回復のチャンスがなく、1 回の一時的な失敗でタスク全体が失敗する → エラーを観測として履歴に返す
  • ループの中身を記録しない → 「たまに変な動きをする」を再現も分析もできない → 各イテレーションの入出力・ツール結果を記録する(可観測性とトレーシング)

チェックリスト

関連トピック

参考資料

TODO・未確認事項