🔁
エージェントループ — 実行ループの解剖
whileループ1つがエージェントの全て
エージェントフレームワークは数十個あるが、全て結局同じ構造だ。
基本ループ
messages = [system_prompt]
while True:
response = llm.call(messages, tools=available_tools)
if response.stop_reason == 'tool_use':
for tool_call in response.tool_calls:
result = execute(tool_call)
messages.append(tool_result(result))
else:
break
これが全てだ。LangChainだろうがCrewAIだろうがAutoGenだろうが、コアはこのループ。
ループの構成要素
メッセージ履歴: すべての会話とツール結果が蓄積される場所。エージェントの「記憶」だ。コンテキストウィンドウの制限があるので、履歴が長くなると要約やカットが必要。
ツール定義: LLMに「こういうツールが使えるよ」と伝えるスキーマ。ツール名、説明、パラメータをJSON Schemaで定義。ツールの説明が良いほどLLMが適切なツールを選ぶ。
終了条件: ループがいつ終わるか。通常、LLMがツールを呼ばずテキストだけ返せば終了。追加で最大反復回数、タイムアウト、コスト上限などの安全装置が必要。
実践的考慮事項
エラーハンドリング: ツール実行が失敗したら?エラーメッセージをLLMに返せば、LLMが別のアプローチを試みる。クラッシュさせてはいけない。
コンテキスト管理: 100回ツールを呼ぶとメッセージ履歴が巨大になる。トークン上限を超える前に古いメッセージを要約・削除する戦略が必要。
並列ツール呼び出し: Claudeは1回の応答で複数のツールを同時に呼べる。独立したツール呼び出しを並列実行すれば速度が上がる。
観測可能性: ループが回るたびに何をしているかロギング。デバッグ時にログがないと地獄だ。
動作フロー
1
システムプロンプト + ユーザーメッセージで初期メッセージ履歴を構成
2
LLM呼び出し → 応答にtool_useがあればツール実行
3
ツール結果をメッセージ履歴に追加 → LLM再呼び出し
4
tool_useがなければループ終了 → 最終応答を返す
ユースケース
シンプルなCLIエージェントの自作
既存エージェントフレームワークの内部動作の理解