AI エージェントの図の多くは、LLM のロゴの横にロボットのアイコンを置き、「ツール」と書いた矢印を引いただけのものです。その絵は、エージェントを安全に動かせるかどうかを決める問いを隠してしまいます。次のステップを誰が選ぶのか、エージェントは何に触れてよいのか、信頼できないテキストはどこから入ってくるのか、そして行き詰まった実行を何が止めるのか、です。
この記事では、エージェントを構成要素に分解し、それを動かすループを順に追い、ツールと Model Context Protocol、メモリー、ガードレール、制限、トレースを扱い、注文を調べて返金を発行できるカスタマーサポートのエージェントを図にします。
ワークフローか、エージェントか
Anthropic の 効果的なエージェントの構築に関するガイド は、便利な線引きをしています。ワークフローでは、LLM とツールは事前に書いたコードの経路によってオーケストレーションされます。エージェントでは、モデルが自らのプロセスを方向付け、タスクが終わるまで、どのツールを使うかを 1 ステップずつ決めます。
同じガイドは、うまくいく最もシンプルな解決策を勧めています。タスクが常に同じ 3 つのステップをたどるなら、そのステップをコードで書き、その中でモデルを呼び出しましょう。エージェントを使うのは、途中で見つかったものによって道筋が変わる場合です。たとえば、次の照会が直前の答えに左右されるサポート案件や、編集とテストを何度も繰り返す必要があるコーディング作業です。
エージェントの構成要素
| 要素 | 役割 | 図の中では |
|---|---|---|
| モデル | コンテキストを読み、次のステップを決めるか、回答を書く | LLM API |
| エージェントループ | ステップを回し、ツール呼び出しを実行し、制限を適用する | Agent loop |
| ツール | モデルの外にあるものを読み、変更する | Web search, code sandbox, orders API |
| 作業メモリー | このステップでモデルが目にするもの | Working memory |
| 長期的な知識 | 必要なときに取り出す文書やポリシー | Knowledge index |
| ガードレール | 入力、出力、ツール呼び出しを確認する | Guardrails |
| 人による承認 | リスクのある操作を承認する | Approver |
| トレースと評価 | すべての実行を記録し、振る舞いを継続的に採点する | Traces and evals |
モデルは箱の 1 つにすぎません。エンジニアリングの大部分も、リスク管理の大部分も、その周りのコードにあります。
ループ
本質だけに絞ると、ランタイムは 1 つのループです。
def run(task, user):
messages = [system_prompt(user), task]
for step in range(MAX_STEPS):
reply = llm.generate(messages, tools=allowed_tools(user))
if not reply.tool_calls:
return check_output(reply.text)
for call in reply.tool_calls:
result = execute(call, user) # permission check, approval, timeout
messages.append(tool_result(call, result))
return stop("step limit reached", messages)
モデルが自分で何かを実行することはありません。モデルが返すのは、回答か、特定の引数でツールを呼び出す要求のどちらかで、それを実行するかどうか、どう実行するかはランタイムが決めます。制御はそこにあります。権限チェック、承認、タイムアウト、制限はすべて、プロンプトではなく execute とループの中にあります。
ツールと MCP の位置付け
ツールとは、モデルが要求できる関数のことで、名前、説明、引数の JSON スキーマを持ちます。説明はコードと同じくらい重要です。モデルがいつそのツールを使うべきかについて知っているのは、説明だけだからです。
Model Context Protocol は、AI アプリケーションを外部のシステムにつなぐためのオープンな標準です。MCP サーバーがツール、データ、プロンプトを公開し、エージェントのランタイムはクライアントとして動作します。すべての連携をエージェントのコードに組み込む代わりに、各システムがサーバーを提供し、MCP に対応したランタイムならどれでもそれを使えます。
良いツールにはいくつかの共通点があります。
- 少数で具体的。 汎用的な
call_api(url, body)よりも、refund_order(order_id, amount, reason)のほうが優れています。 - 読み取りと書き込みを分ける: ロールによって、書き込み用のツールなしで読み取り用のツールだけを与えられます。
- モデルが対処できる明確なエラー: たとえば「金額が注文合計を超えています」です。
- 書き込みに冪等キー: 再試行されたステップで二重に返金しないようにします。
メモリー
エージェントには 2 種類のメモリーがあり、図ではよく混同されます。
- 作業メモリー は、各ステップでモデルに送るコンテキストです。指示、会話、それまでのツールの結果が含まれます。モデルのコンテキストウィンドウとコストによって制限されるので、長い実行では古いステップを要約したり、使い終わったツールの生の出力を捨てたりします。
- 長期的な知識 はモデルの外にあります。文書、ポリシー、過去のチケットなどです。エージェントは関連する部分を、多くの場合ベクトルインデックスから取り出し、作業メモリーに加えます。検索のパイプラインの詳細は RAG のアーキテクチャ図 で扱っています。
どのステップがすでに実行されたか、どの承認が保留中かといった、クラッシュ後も残っている必要があるタスクの状態は、モデルのコンテキストではなく通常のデータベースに置くべきです。
ガードレールと権限
LLM アプリケーション向けの OWASP Top 10 は、プロンプトインジェクションを最初に挙げています。別の項目である過剰なエージェンシーは、LLM システムが必要以上の機能、権限、自律性を持っているために起こりうる有害な操作を扱っています。エージェントはその両方にさらされます。信頼できないテキスト(ユーザーの入力、Web ページ、取得した文書、ツールの結果)を読み、しかも行動できるからです。
実際に役立つルールは次のとおりです。
- ツールの結果と取得した文書はすべてデータとして扱う。 Web ページ内のテキストが権限を与えたり、タスクを変えたりすることはできません。
- ユーザーの権限で行動する: すべての顧客を見られるサービスアカウントでは行動しません。
- 書き込みを関門で守る。 読み取りは自由に実行し、しきい値を超える書き込みや取り消せない操作は人を待ちます。
- コードの実行をサンドボックス化する: デフォルトでは認証情報もネットワークも与えません。
- 出力を確認する: ユーザーやほかのシステムに届く前に、内部データの漏えいや安全でない内容がないかを確認します。
脅威モデリングのデータフロー図 は、信頼できないテキストが行動できるコンポーネントに入り込む場所を見つけるのに役立ちます。
制限とコスト
進展のないままループし続けるエージェントは、お金と忍耐を消費します。制限はプロンプトではなくランタイムに置きましょう。
- ステップ: タスクごとのモデル呼び出しの最大回数。
- 時間: タスクごとの実時間の上限と、ツール呼び出しごとのタイムアウト。
- お金: タスクごと、ユーザーごと・1 日ごとのトークンまたはドルの予算。
- レート: レートリミッターの設計 にあるような、API でのユーザーごとのリクエスト制限。
制限に達したら、きれいに停止します。そこまでに見つかったものを返し、どの制限で実行が止まったかを伝え、レビューのためにトレースを残します。
トレースと評価
すべてのステップを記録します。送ったコンテキスト、モデルとその設定、引数と結果を含む各ツール呼び出し、トークン、レイテンシー、コストです。OpenTelemetry には生成 AI 向けのセマンティック規約があるので、これらのトレースをシステムのほかの部分と同じバックエンドに流せます。そのパイプラインは オブザーバビリティのアーキテクチャ図 で紹介しています。
トレースは「この実行で何が起きたか」に答えます。評価は「エージェントは良くなっているのか、悪くなっているのか」に答えます。現実的なタスクを固定したセットを用意し、自動で採点して、プロンプト、ツール、モデルを変更するたびに実行します。
アーキテクチャ図
ダイアグラムの内容
- User
- Chat app / API
- Agent runtime
- Guardrails
- Agent loop
- Working memory
- LLM API
- Tools (MCP servers or functions)
- Web search
- Code sandbox
- Orders API
- Approver
- Knowledge index
- Traces and evals
- task
- task + identity
- checked
- context + tool list
- answer or tool call
- tool calls
- read / write
- retrieved docs
- refund waits for approval
- every step
図の読み方は次のとおりです。
- 左: ユーザーがチャットアプリからタスクを送ります。チャットアプリはサインインとセッションを扱い、ユーザーの ID とともにタスクをガードレールに渡します。
- 中央: エージェントループがコンテキストとツールの一覧を LLM に送り(実線)、回答かツール呼び出しを受け取ります(破線)。作業メモリーを読み書きし、Markdown ブロックには制限を並べています。
- 右: ツール呼び出しは、Web 検索、コードサンドボックス、注文 API に送られます。返金は承認者を待ちます(破線)。
- 下: ナレッジインデックスが取得した文書を作業メモリーに供給し、すべてのステップがトレースと評価に記録されます(点線)。
具体例:返金
顧客が次のように書き込みます。「注文 4411 が壊れた状態で届いたので、返金してほしい」
- ガードレールがメッセージを確認し、顧客の ID を付けます。
- モデルが
get_order(4411)を要求します。ランタイムは注文がこの顧客のものであることを確認し、「3 日前に配達済み、180 ドル」と返します。 - ランタイムがナレッジインデックスから返金ポリシーを取り出し、作業メモリーに加えます。「破損品は 30 日以内なら返金可能」です。
- モデルが
refund_order(4411, 180, "damaged")を要求します。金額が 100 ドルのしきい値を超えているので、ランタイムは実行を一時停止し、サポートのリーダーに承認依頼を送ります。 - リーダーが承認します。ランタイムは冪等キーを付けて返金を実行し、確認結果を返します。
- モデルが返信を書き、出力チェックを通過して、顧客に回答が届きます。
モデル呼び出しが 3 回、ツール呼び出しが 2 回、検索が 1 回、承認が 1 回、そしてすべてのステップを示すトレースが 1 つです。
エージェントの図に描くべきもの
- 次のステップを誰が決めるか: モデルなのか、自分たちが書いたコードなのか。
- 各ツール: 読み取りか書き込みかと、誰の権限で動くかを描きます。
- リスクのある操作の承認ポイント。
- 制限: ステップ、時間、予算。
- 信頼できないテキストが入ってくる場所: ユーザーの入力、Web ページ、文書、ツールの結果。
- トレース: 実行を後から調べられることがレビュアーに伝わるようにします。
Archboard で作る
- Google または GitHub でサインインし、図を作成します。
- C4 モデルパックから、ユーザーと承認者用に 人物 ノードを 2 つ、チャットアプリ用に コンテナ を追加します。
- 基本パックからエージェントランタイム用に フレーム を追加し、その中にエージェントループ用の コンテナ と、ガードレールと作業メモリー用の コンポーネント ノードを 2 つ置きます。
- ML パックから モデル と ベクトルインデックス を、ツール用に Stack パックの サービスカード ノードを 3 つ入れた 2 つ目の フレーム を、DevOps パックから トレース を追加します。
- モデルからの返答を破線で、トレースのエッジを点線で描き、制限を書いた基本パックの Markdown ブロックを追加します。エージェントに図を描かせたい場合は、MCP 経由で AI エージェントに図を作らせる方法 を参照してください。
この例で使うダイアグラムノードは 15 個で、Free プランの範囲に収まります。
よくある質問
AI エージェントとワークフローの違いは何ですか? ワークフローでは、コードがステップの順序を決め、その中でモデルを呼び出します。エージェントでは、コードが制御するループの中で、モデルが次のステップと使うツールを決めます。
エージェントのアーキテクチャにおける MCP とは何ですか? Model Context Protocol は、AI アプリケーションをツールやデータにつなぐためのオープンな標準です。各システムが MCP サーバーを公開し、エージェントのランタイムがクライアントとしてそれに接続します。
エージェントが有害な操作をしないようにするにはどうすればよいですか? 必要なツールだけを与え、ユーザーの権限で実行し、しきい値を超える書き込みには人の承認を必須にして、ツールの結果や文書はすべて信頼できないデータとして扱います。
エージェントはどうやって物事を覚えるのですか? 1 回の実行の中では、各ステップでモデルに送るコンテキストによって覚えます。実行をまたぐ場合は、必要なときに取り出す保存済みの知識と、データベースに保存したタスクの状態によって覚えます。
エージェントのコストを抑えるにはどうすればよいですか? ランタイムでタスクごとのステップ、時間、トークンの上限を設定し、ユーザーごとの予算を加え、すべての実行をトレースして、コストのかかるパターンがレビューで見つかるようにします。