- AI ⚙️
AIエージェントとは|仕組みとワークフローとの違い・作り方入門
AIエージェントとは、モデルが「このツールをこの引数で呼んでほしい」と返す限り、プログラムがそれを実行して結果を渡し、また次の応答を受け取る、という往復を繰り返すループです。 特別な仕掛けがあるわけではなく、中心は while 文ひとつ。モデルが次の一手を決め、プログラムが実行し、結果を見てモデルがまた決めます。
この記事では、その往復を Python のコードとシーケンス図で示し、ツール定義の書き方、ワークフロー5型の図、ワークフローとエージェントのどちらを選ぶかの判断基準、チャットボット・RAG・RPA との違いまでを、特定の製品に依らない基礎としてまとめます。
確認環境(確認日 2026-10-05):Python 3.11.15。掲載のコードは、モデルを呼び出さずに動く形(モデルの応答を順に返す代役を置き、ツール呼び出しの往復を再現したもの)で実行しました。図は Mermaid(@mermaid-js/mermaid-cli 12.0.0 と Chromium)で描画できることを確かめています。定義・手順・フィールド名は、Anthropic の公開文書「Building effective agents」(2024年12月19日公開)と Claude の公式ドキュメント(tool use)を今回開いて確認した範囲です。
この記事の結論
| 問い | 答え |
|---|---|
| エージェントとは | モデルが自分で手順とツールの使い方を決めながら進める仕組み。実体は「ツール呼び出しが返る限り繰り返す」ループ |
| ワークフローとは | モデルとツールを、あらかじめ書いたコードの道筋どおりに動かす仕組み |
| どちらを選ぶか | 手順を事前に決められるならワークフロー。手順の数が読めないときだけエージェント |
| 作るのに要るもの | ツール定義(名前・説明・入力のJSONスキーマ)、ループ、回数上限、ツールの実体 |
| 最初に決めること | 終了条件と回数上限、ツールがエラーを返したときの扱い |
用語の早見表
| 用語 | 意味 | この記事での例 |
|---|---|---|
| モデル | 文章を受け取り、文章やツール呼び出しを返す言語モデル | 次の一手を決める役 |
| ツール | モデルが呼び出しを依頼できる関数。実行するのは自分のプログラム | 備品の検索、備品の予約 |
| ツール定義 | ツールの名前・説明・入力の形をモデルに伝える情報 | name、description、input_schema |
| ツール呼び出し(tool_use) | モデルの応答に入る「このツールをこの引数で」という依頼 | search_equipment を keyword=プロジェクター で |
| ツール結果(tool_result) | 実行結果をモデルへ返すためのブロック | 在庫の一覧、エラーの内容 |
| stop_reason | モデルが応答を止めた理由 | tool_use なら続行、それ以外なら終了 |
| ワークフロー | 事前に決めたコードの道筋でモデルとツールを動かす仕組み | 連鎖、振り分け、並列 など5型 |
| エージェント | モデルが進め方とツールの使い方を自分で決める仕組み | 往復の回数が事前に決まらない |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AIエージェントとは|仕組みとワークフローとの違い・作り方入門」
AIエージェントの仕組み:ツール呼び出しの往復
Claude の公式ドキュメントでは、自分のプログラムで実行するツールについて「モデルは自分のコードを実行できないので、ツール呼び出しはすべて往復になる。モデルが依頼し、アプリケーションが実行して結果を報告し、モデルが続ける」という趣旨で説明されています。手順は次の5つです。
- ツール定義の一覧と利用者のメッセージを付けて、リクエストを送る。
- モデルが stop_reason に tool_use を入れ、1つ以上の tool_use ブロックを返す。
- 各ツールを実行し、出力を tool_result ブロックにする。
- 元のメッセージ、モデルの応答、tool_result を入れた user メッセージをまとめて、新しいリクエストを送る。
- stop_reason が tool_use である間、2 から繰り返す。
sequenceDiagram
participant U as 利用者
participant P as プログラム(ループ)
participant M as モデル
participant T as ツール(自分の関数)
U->>P: 依頼「10月8日にプロジェクターを予約して」
loop stop_reason が tool_use の間(回数上限まで)
P->>M: これまでのメッセージ + ツール定義
M-->>P: tool_use(ツール名・引数・id)
P->>T: 引数を渡して実行
T-->>P: 結果 または エラー
Note over P: tool_result(tool_use_id・content・is_error)を<br>1つの user メッセージにまとめて追加
end
P->>M: これまでのメッセージ + ツール定義
M-->>P: 最終回答(stop_reason は end_turn)
P-->>U: 回答を表示
ポイントは3つです。
- モデルはツールを実行しません。 返ってくるのは「呼んでほしい」という依頼で、実行するかどうかはプログラム側が決められます。確認を挟む、権限を確かめる、といった制御はここに入れます。
- モデルは前回のやり取りを覚えていません。 毎回、これまでのメッセージをすべて付けて送ります。往復が増えるほど、1回のリクエストは長くなります。
- ループを抜ける条件は stop_reason です。 公式ドキュメントでは、tool_use 以外(end_turn、max_tokens、stop_sequence、refusal)ではループを抜け、最終回答が出たか、アプリケーション側で扱うべき別の理由で止まったことを意味する、とされています。
ツール定義の書き方(JSONスキーマ記入例)
ツール定義は、公式ドキュメントで次の3項目が必須とされています。
| 項目 | 内容 | 書くときの目安 |
|---|---|---|
name |
ツールの名前。英数字・アンダースコア・ハイフンで1〜128文字(正規表現 ^[a-zA-Z0-9_-]{1,128}$) |
動詞から始めて、何をするかが分かる名前にする |
description |
何をするか、いつ使うか、どう動くかの説明文 | 公式は「単純なツールでも3〜4文以上」を勧めている。使う場面と使わない場面、返す情報と返さない情報を書く |
input_schema |
引数の形を表す JSON Schema のオブジェクト | 型、説明、必須項目(required)、選択肢(enum)を書く |
架空の「社内の備品予約システム」を題材にした記入例です。
[
{
"name": "search_equipment",
"description": "社内の備品を名前の一部で検索し、備品ID・名称・在庫数の一覧を返す。予約の前に在庫を確かめるときに使う。このツールは予約を行わない。該当が無いときは空の一覧を返す。",
"input_schema": {
"type": "object",
"properties": {
"keyword": {
"type": "string",
"description": "備品名の一部。例: プロジェクター"
}
},
"required": ["keyword"]
}
},
{
"name": "reserve_equipment",
"description": "備品IDと利用日を指定して1件予約し、予約内容を返す。備品IDは search_equipment の結果にあるものを使う。在庫が0のときは予約せず、エラーを返す。取り消しはこのツールではできない。",
"input_schema": {
"type": "object",
"properties": {
"item_id": {
"type": "string",
"description": "備品ID。例: EQ-002"
},
"date": {
"type": "string",
"description": "利用日。YYYY-MM-DD 形式。例: 2026-10-08"
},
"unit": {
"type": "string",
"enum": ["half_day", "full_day"],
"description": "利用の単位。半日なら half_day、終日なら full_day。省略時は full_day"
}
},
"required": ["item_id", "date"]
}
}
]
説明文を直す前と後
| 観点 | 直す前 | 直した後 |
|---|---|---|
| 何をするか | 備品を予約する | 備品IDと利用日を指定して1件予約し、予約内容を返す |
| いつ使うか | (記載なし) | 備品IDは search_equipment の結果にあるものを使う |
| うまくいかないとき | (記載なし) | 在庫が0のときは予約せず、エラーを返す |
| できないこと | (記載なし) | 取り消しはこのツールではできない |
| 引数の例 | date: 文字列 | 利用日。YYYY-MM-DD 形式。例: 2026-10-08 |
「Building effective agents」では、人が使う画面の設計に手間をかけるのと同じだけ、モデルが使うツールの説明と入出力の設計に手間をかけることが勧められています。使用例・境界となる入力・ほかのツールとの違いを説明に入れ、引数名を分かりやすくし、取り違えが起きにくい形にする、という内容です。
作り方:Pythonで書くエージェントループ
次のコードは、ツール定義・stop_reason の判定・結果の返し方・回数上限をひととおり入れた最小の形です。紙面を抑えるため、コード内のツール定義は前の節の記入例より説明を短くしています。モデルを呼び出す部分は、決まった応答を順に返す代役(call_model)にしてあります。 メッセージとブロックの形は公式ドキュメントのフィールド名(type、id、name、input、tool_use_id、content、is_error)に合わせているので、代役を本物の呼び出しに差し替えれば、ループの部分は同じ考え方で使えます。
# agent_loop.py モデルを呼び出さずに、ツール呼び出しの往復を再現する
import json
TOOLS = [{
"name": "search_equipment",
"description": "社内の備品を名前の一部で検索し、備品IDと在庫数を返す。"
"予約の前に在庫を確かめるときに使う。予約そのものは行わない。",
"input_schema": {"type": "object",
"properties": {"keyword": {"type": "string", "description": "備品名の一部。例: プロジェクター"}},
"required": ["keyword"]},
}, {
"name": "reserve_equipment",
"description": "備品IDと日付を指定して1件予約する。在庫が0のときはエラーを返す。",
"input_schema": {"type": "object",
"properties": {"item_id": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD"}},
"required": ["item_id", "date"]},
}]
STOCK = {"EQ-001": {"name": "プロジェクターA", "stock": 0}, "EQ-002": {"name": "プロジェクターB", "stock": 2}}
def run_tool(name, args): # ツールの実体(自分のコード)
if name == "search_equipment":
return json.dumps([{"item_id": k, **v} for k, v in STOCK.items() if args["keyword"] in v["name"]], ensure_ascii=False)
if name == "reserve_equipment":
if STOCK[args["item_id"]]["stock"] == 0:
raise RuntimeError(f"{args['item_id']} は在庫が0です。別の備品IDで試してください。")
STOCK[args["item_id"]]["stock"] -= 1
return json.dumps({"reserved": args["item_id"], "date": args["date"]})
raise RuntimeError(f"未定義のツール: {name}")
SCRIPT = [ # モデルの代役: 応答を順に返す(本物では client.messages.create(...) の戻り値にあたる)
{"stop_reason": "tool_use", "content": [{"type": "tool_use", "id": "toolu_01", "name": "search_equipment", "input": {"keyword": "プロジェクター"}}]},
{"stop_reason": "tool_use", "content": [{"type": "tool_use", "id": "toolu_02", "name": "reserve_equipment", "input": {"item_id": "EQ-001", "date": "2026-10-08"}}]},
{"stop_reason": "tool_use", "content": [{"type": "tool_use", "id": "toolu_03", "name": "reserve_equipment", "input": {"item_id": "EQ-002", "date": "2026-10-08"}}]},
{"stop_reason": "end_turn", "content": [{"type": "text", "text": "プロジェクターB(EQ-002)を 2026-10-08 に予約しました。"}]},
]
def call_model(messages, tools, _turn=[0]):
_turn[0] += 1
return SCRIPT[_turn[0] - 1]
def run_agent(user_text, max_turns=5):
messages = [{"role": "user", "content": user_text}]
for turn in range(1, max_turns + 1): # 回数上限
response = call_model(messages, TOOLS)
messages.append({"role": "assistant", "content": response["content"]})
print(f"[{turn}] stop_reason={response['stop_reason']}")
if response["stop_reason"] != "tool_use": # ツール呼び出しでなければ終了
return response["content"][0]["text"]
results = []
for block in response["content"]:
if block["type"] != "tool_use":
continue
try:
out, is_error = run_tool(block["name"], block["input"]), False
except Exception as e: # エラーも結果として返す
out, is_error = f"{type(e).__name__}: {e}", True
print(f" {block['name']}({json.dumps(block['input'], ensure_ascii=False)}) -> {out}")
results.append({"type": "tool_result", "tool_use_id": block["id"], "content": out, "is_error": is_error})
messages.append({"role": "user", "content": results}) # 結果は1つの user メッセージにまとめる
return "回数上限に達したため中断しました。"
if __name__ == "__main__":
print("最終回答:", run_agent("10月8日にプロジェクターを1台予約して"))
実行結果:
[1] stop_reason=tool_use
search_equipment({"keyword": "プロジェクター"}) -> [{"item_id": "EQ-001", "name": "プロジェクターA", "stock": 0}, {"item_id": "EQ-002", "name": "プロジェクターB", "stock": 2}]
[2] stop_reason=tool_use
reserve_equipment({"item_id": "EQ-001", "date": "2026-10-08"}) -> RuntimeError: EQ-001 は在庫が0です。別の備品IDで試してください。
[3] stop_reason=tool_use
reserve_equipment({"item_id": "EQ-002", "date": "2026-10-08"}) -> {"reserved": "EQ-002", "date": "2026-10-08"}
[4] stop_reason=end_turn
最終回答: プロジェクターB(EQ-002)を 2026-10-08 に予約しました。
2回目でツールが例外を出していますが、プログラムは止まっていません。エラーの内容を is_error つきの tool_result として返し、次の一手をモデルに任せているためです。代役の応答は、エラーを受けて別の備品IDで予約し直す流れにしてあります。
コードの読みどころ
| 行のまとまり | していること | 公式ドキュメントの対応 |
|---|---|---|
| TOOLS | ツール定義(name・description・input_schema) | ツール定義の必須3項目 |
| run_tool | ツールの実体。自分のコードで実行する | 「ツールを実行する」 |
for turn in range(...) |
回数上限つきのループ | 「Building effective agents」が挙げる停止条件(最大の繰り返し回数など) |
if response["stop_reason"] != "tool_use" |
ツール呼び出しでなければ終了 | tool_use の間だけ続ける |
messages.append({"role": "assistant", ...}) |
モデルの応答をそのまま履歴に足す | 次のリクエストにモデルの応答を含める |
tool_use_id: block["id"] |
どの依頼への結果かを結び付ける | tool_use ブロックの id を tool_use_id に入れる |
is_error |
実行できなかったことを伝える | 実行がうまくいかなかったとき true にする |
messages.append({"role": "user", "content": results}) |
結果を1つの user メッセージにまとめる | 並列のツール呼び出しの結果は1つの user メッセージに入れる |
回数上限が働く例
モデルが同じツールを呼び続ける場合を、代役の応答を差し替えて確かめます。
import agent_loop as a
a.SCRIPT = [a.SCRIPT[0]] * 10 # ツール呼び出しを返し続ける代役
print("最終回答:", a.run_agent("プロジェクターを探して", max_turns=3))
[1] stop_reason=tool_use
search_equipment({"keyword": "プロジェクター"}) -> [{"item_id": "EQ-001", ...(省略)...
[2] stop_reason=tool_use
search_equipment({"keyword": "プロジェクター"}) -> [{"item_id": "EQ-001", ...(省略)...
[3] stop_reason=tool_use
search_equipment({"keyword": "プロジェクター"}) -> [{"item_id": "EQ-001", ...(省略)...
最終回答: 回数上限に達したため中断しました。
本物のモデルにつなぐときに変える場所
変えるのは call_model の中だけです。公式ドキュメントの Python の例では、次の形でリクエストを送ります。
import anthropic
client = anthropic.Anthropic()
def call_model(messages, tools):
return client.messages.create(
model="(利用するモデル名)",
max_tokens=1024,
tools=tools,
messages=messages,
)
戻り値は辞書ではなくオブジェクトなので、ループ側の response["stop_reason"] は response.stop_reason、block["type"] は block.type のように属性で読みます。
tool_resultを返すときの決まり
公式ドキュメント「Handle tool calls」に書かれている決まりです。
| 決まり | 内容 |
|---|---|
| 直後に返す | tool_result は、対応する tool_use を含む assistant メッセージのすぐ次の user メッセージに入れる。間に別のメッセージを挟まない |
| 先頭に置く | user メッセージの content の中で、tool_result を先に置く。文章を足すなら、すべての tool_result のあと |
| 1つにまとめる | 同じ応答に複数の tool_use があるときは、結果をすべて1つの user メッセージに入れる |
| エラーも返す | 実行できなかったときは is_error を true にし、何が起きたか・どう試し直せるかが分かる文を content に入れる(「failed」だけにしない) |
| content の形 | 文字列のほか、text・image・document などのブロックの配列も渡せる |
順番を守らないと、公式ドキュメントに載っている「tool_use ids were found without tool_result blocks immediately after」という 400 エラーになります。
ワークフロー5型の図
「Building effective agents」は、モデルとツールを組み合わせた仕組みを大きく2つに分けています。ワークフローは「あらかじめ決めたコードの道筋でモデルとツールを動かすもの」、エージェントは「モデルが自分の進め方とツールの使い方を動的に決め、進め方の主導権を持ち続けるもの」です。ワークフローには次の5つの型が挙げられています。
1. 連鎖(prompt chaining)
仕事を順番の決まった段階に分け、前の出力を次の入力にします。段階の間にプログラムによる確認(ゲート)を挟めます。
flowchart LR
A[入力] --> B[モデル1: 骨子を作る]
B --> C{確認: 項目はそろったか}
C -- はい --> D[モデル2: 本文を書く]
C -- いいえ --> X[中断して知らせる]
D --> E[モデル3: 英語に訳す]
E --> F[出力]
向いている場面:決まった小さな作業にきれいに分けられるとき。1回ごとの作業をやさしくして、待ち時間と引き換えに正確さを上げます。
2. 振り分け(routing)
入力を分類し、種類ごとに専用の処理へ回します。
flowchart LR
A[問い合わせ] --> B[モデル: 種類を分類]
B -- 使い方 --> C[使い方の手順で回答]
B -- 不具合 --> D[不具合の聞き取り手順]
B -- 申請 --> E[申請の案内]
C --> F[出力]
D --> F
E --> F
向いている場面:はっきり分かれた種類があり、別々に扱ったほうがうまくいくとき。
3. 並列(parallelization)
同時に複数のモデル呼び出しを走らせ、プログラムで結果をまとめます。独立した部分に分ける形と、同じ作業を複数回行って見比べる形があります。
flowchart LR
A[設計書] --> B[モデル: 用語の揺れを確認]
A --> C[モデル: 数値の食い違いを確認]
A --> D[モデル: 記載もれを確認]
B --> E[プログラム: 結果をまとめる]
C --> E
D --> E
E --> F[指摘一覧]
向いている場面:分けた作業を同時に進めて速くしたいとき、複数の視点で確かさを上げたいとき。
4. 指揮役と作業役(orchestrator-workers)
中心のモデルが仕事を分解して作業役のモデルに割り振り、結果をまとめます。並列との違いは、分け方があらかじめ決まっておらず、入力を見て指揮役が決める点です。
flowchart TD
A[依頼: 仕様変更を反映して] --> B[指揮役のモデル: 作業を分解]
B --> C[作業役1: 画面の定義を直す]
B --> D[作業役2: 項目の説明を直す]
B --> E[作業役n: 必要に応じて増える]
C --> F[指揮役のモデル: 結果をまとめる]
D --> F
E --> F
F --> G[出力]
向いている場面:必要な作業の種類や数を前もって見積もれない、込み入った仕事。
5. 評価と改善(evaluator-optimizer)
1つのモデルが案を作り、別のモデルが基準に照らして評価し、合格するまで繰り返します。
flowchart LR
A[入力] --> B[作成役のモデル: 案を作る]
B --> C[評価役のモデル: 基準で採点]
C -- 直す点あり --> B
C -- 合格 または 回数上限 --> D[出力]
向いている場面:評価の基準がはっきりしていて、繰り返すと目に見えて良くなるとき。
5型とエージェントの早見表
| 型 | 道筋を決めるのは | モデルの呼び出し回数 | 向いている場面 |
|---|---|---|---|
| 連鎖 | コード(順番が固定) | 段階の数だけ | 決まった段階に分けられる |
| 振り分け | コード(分類の結果で分岐) | 分類1回 + 行き先の処理 | 種類がはっきり分かれる |
| 並列 | コード(分け方が固定) | 分けた数だけ(同時) | 独立した部分に分けられる、見比べたい |
| 指揮役と作業役 | 指揮役のモデル(分け方は入力次第) | 入力ごとに変わる | 作業の種類や数を見積もれない |
| 評価と改善 | コード(作成と評価の往復) | 合格するまで(上限つき) | 基準がはっきりしている |
| エージェント | モデル(次の一手を毎回決める) | 事前には決まらない | 手順の数が読めない、道筋を固定できない |
表計算ソフトに貼れるタブ区切り版です。
型 道筋を決めるのは モデルの呼び出し回数 向いている場面
連鎖 コード(順番が固定) 段階の数だけ 決まった段階に分けられる
振り分け コード(分類の結果で分岐) 分類1回+行き先の処理 種類がはっきり分かれる
並列 コード(分け方が固定) 分けた数だけ(同時) 独立した部分に分けられる、見比べたい
指揮役と作業役 指揮役のモデル(分け方は入力次第) 入力ごとに変わる 作業の種類や数を見積もれない
評価と改善 コード(作成と評価の往復) 合格するまで(上限つき) 基準がはっきりしている
エージェント モデル(次の一手を毎回決める) 事前には決まらない 手順の数が読めない、道筋を固定できない
ワークフローとエージェントの違いと選び方
「Building effective agents」は、まずできるだけ単純な方法を探し、必要なときだけ複雑さを足すことを勧めています。エージェント型の仕組みは、より良い結果と引き換えに待ち時間と費用が増えることが多く、多くの用途では、検索した資料や例を添えて1回のモデル呼び出しを磨けば足りる、という説明です。
| 比べる点 | 1回の呼び出し | ワークフロー | エージェント |
|---|---|---|---|
| 進め方を決めるのは | 人(プロンプト) | コード | モデル |
| 予測可能性 | 高い(入力と出力が1対1) | 高い(通る道筋をコードで追える) | 低め(同じ依頼でも手順が変わりうる) |
| 費用 | 1回ぶん | 段階の数に比例し、前もって見積もれる | 往復の回数に比例し、前もって決まらない。上限で抑える |
| 待ち時間 | 短い | 段階の数だけ延びる(並列で縮められる) | 往復の回数だけ延びる |
| 検証のしやすさ | 入力と出力の組で確かめる | 段階ごとに入力と出力を確かめられる | 道筋が毎回変わるため、最終結果と途中の記録の両方を見る |
| 誤りの広がり方 | その回だけ | 段階の間の確認で止められる | 前の誤りが次の判断に影響し、重なりやすい |
| 向いている仕事 | 1回で答えが出る | 手順を前もって書ける | 手順の数が読めず、道筋を固定できない |
誤りの重なりは、簡単な計算で感覚をつかめます。1回の手順が正しく進む割合を仮に 95% とした場合の計算例です(Python で検算。割合は説明のための仮の値)。
| 手順の数 | すべて正しく進む割合(0.95 の n 乗) |
|---|---|
| 5 | 約 77% |
| 10 | 約 60% |
| 20 | 約 36% |
手順が増えるほど、途中で結果を確かめる仕組み(テストの実行、人による確認、回数上限)が効いてきます。「Building effective agents」でも、エージェントは各手順で環境から得た事実(ツールの実行結果など)をもとに進み具合を確かめること、区切りで人の確認を挟めること、最大の繰り返し回数などの停止条件を入れることが挙げられています。
条件から選ぶ判断表
| 条件 | 選ぶもの |
|---|---|
| 1回の質問と回答で用が足りる | 1回の呼び出し(必要なら資料を添える) |
| 手順が毎回同じ順番で、数も決まっている | ワークフロー(連鎖) |
| 入力の種類で手順が分かれるが、種類は数えられる | ワークフロー(振り分け) |
| 互いに独立した確認を同時に行いたい | ワークフロー(並列) |
| 合格の基準を文章で書け、直せば良くなる | ワークフロー(評価と改善) |
| 作業の分け方が入力を見るまで分からない | ワークフロー(指揮役と作業役) |
| 手順の数が読めず、結果を見て次を決める必要がある | エージェント(回数上限と確認の区切りを入れる) |
| 結果を自動で確かめる手段がない、やり直しがきかない操作を含む | エージェントに任せる範囲を狭め、実行前に人の確認を挟む |
迷ったら、ワークフローで書けるところまで書き、書けなかった部分だけをエージェントにすると、費用と待ち時間の見通しを保ったまま柔軟さを足せます。
チャットボット・RAG・RPAとの違い
混同されやすい3つと並べます。違いは「次に何をするかを誰が決めるか」と「外の仕組みに働きかけるか」の2点に集まります。
| 比べる点 | チャットボット | RAG(検索して答える仕組み) | RPA(画面操作の自動化) | AIエージェント |
|---|---|---|---|---|
| ひとことで | 質問に文章で答える | 資料を検索し、その内容をもとに答える | 人が決めた手順どおりに操作を再生する | モデルが手順を決め、ツールを使って進める |
| 次の一手を決めるのは | 利用者(次の質問) | コード(検索 → 回答の順が固定) | 人が作った手順書(シナリオ) | モデル |
| 外への働きかけ | しない(文章を返す) | 読むだけ(検索) | する(決まった操作) | する(ツールを通じて読む・書く) |
| 手順の数 | 1往復 | 検索と回答で固定 | 手順書に書いた数 | 事前に決まらない |
| 想定外の入力 | 文章で応じる | 資料に無ければ答えられない | 手順書に無い画面では止まる | 結果を見て別の手を試せる |
| 得意なこと | 相談、文章の作成 | 社内資料にもとづく回答 | 同じ操作の繰り返し | 調べながら進める、込み入った作業 |
| 気をつける点 | 外の最新情報を持たない | 検索の質が回答の質を決める | 画面の変更に合わせて手順の手入れが要る | 費用・待ち時間・誤りの重なり。上限と確認が要る |
これらは置き換えの関係ではなく、組み合わせて使えます。RAG の検索は、エージェントから見れば「資料を検索するツール」の1つです。RPA のように手順が決まった操作は、エージェントに判断させるよりワークフローやスクリプトで書いたほうが、速く、結果も毎回同じになります。
作るときのチェックリスト
| 確認すること | 内容 |
|---|---|
| 終了条件 | stop_reason が tool_use 以外なら抜ける。max_tokens など途中で切れた場合の扱いも決める |
| 回数上限 | 繰り返しの最大回数を必ず入れる。達したときの返し方(途中経過を返す、人に引き継ぐ)を決める |
| ツールの数と説明 | 少ない数から始める。似たツールは、説明に「どちらをいつ使うか」を書く |
| エラーの返し方 | 例外でループを止めず、is_error つきで内容を返す。試し直しの手がかりを文に入れる |
| 書き込み系のツール | 予約・更新・送信・削除は、実行前の確認や取り消しの手段を用意する |
| 記録 | 各回の stop_reason、ツール名、引数、結果を残す。あとで道筋をたどれるようにする |
| 結果の確かめ方 | テストの実行、件数の照合など、ツールで事実を確かめられる形にする |
| 入力の検証 | モデルが渡す引数は、ツール側でも型と範囲を確かめる |
確かめて分かったこと
- ループの中心は十数行でした。 掲載コードのうち run_agent は20行ほどで、残りはツール定義とツールの実体です。行数の多くを占めるのは、ループではなくツールの側になります。
- ツールの例外をそのまま外へ出すと、往復は2回目で止まります。 try で受けて is_error つきの結果として返す形にしたところ、3回目で別の備品IDによる予約へ進む流れを再現できました。
- 回数上限は、終了条件とは別に要ります。 ツール呼び出しを返し続ける代役に差し替えると、stop_reason の判定だけでは抜けられず、上限(3回)で止まりました。
- 公式の定義では、ワークフローとエージェントの違いは「道筋を決めるのがコードかモデルか」の1点です。 使うモデルの種類やツールの数では分かれていません。
- 5型のうち「指揮役と作業役」だけは、分け方をモデルが決めます。 図にすると並列とよく似ますが、作業役の数が入力ごとに変わる点が違いです。
- tool_result には順番の決まりがあります。 user メッセージの先頭に置き、文章はそのあと。公式ドキュメントには、順番が違うときの 400 エラーの文言まで載っています。
よくある質問
Q. AIエージェントとは何ですか? A. モデルが自分で進め方とツールの使い方を決めながら仕事を進める仕組みです。実装としては、モデルがツール呼び出しを返す限り、プログラムが実行して結果を渡し、次の応答を受け取るループになります。
Q. AIエージェントとワークフローの違いは何ですか? A. 道筋を決めるのがコードならワークフロー、モデルならエージェントです。ワークフローは通る道筋が前もって決まっているので、費用と待ち時間を見積もりやすく、段階ごとに確かめられます。
Q. AIエージェントと生成AI(チャット)の違いは何ですか? A. チャットは1回の質問に文章で答えるところまで、エージェントはツールを使って外の仕組みを読み書きし、結果を見て次の手を決めるところまで行います。使っているモデルは同じでも、まわりにループとツールがあるかどうかが違いです。
Q. AIエージェントが止まらないときは? A. 繰り返しの回数上限を入れ、達したら途中経過を返して終える形にします。あわせて、同じツールを同じ引数で呼び続けていないかを記録から確かめ、ツールの説明やエラーの文に「次にどうすればよいか」を足します。
Q. エージェントを作るのにフレームワークは必要ですか? A. 必須ではありません。ツール定義・ループ・回数上限・ツールの実体があれば動きます。「Building effective agents」も、まずモデルのAPIを直接使って始め、フレームワークを使う場合は中で何が行われているかを理解しておくことを勧めています。
まとめ
- エージェントの実体は、ツール呼び出しが返る限り実行結果を渡して繰り返すループ。 抜ける条件は stop_reason。
- ツール定義は name・description・input_schema の3つ。 説明には、使う場面・使わない場面・返すもの・できないことを書く。
- 結果は tool_use の id と結び付け、1つの user メッセージの先頭にまとめて返す。 エラーも is_error つきで返す。
- 回数上限は必ず入れる。 終了条件だけでは、ツールを呼び続ける場合に止まらない。
- ワークフローは道筋をコードが決め、エージェントはモデルが決める。 ワークフローには連鎖・振り分け・並列・指揮役と作業役・評価と改善の5型がある。
- 手順を事前に決められるならワークフロー、手順の数が読めないときだけエージェント。 予測可能性・費用・待ち時間・検証のしやすさで比べて選ぶ。
- チャットボット・RAG・RPA とは組み合わせて使える。 検索はエージェントのツールの1つになり、決まった操作はスクリプトに任せる。
参考・出典
- Anthropic「Building effective agents」(2024年12月19日) https://www.anthropic.com/engineering/building-effective-agents
- Claude Docs「How tool use works」 https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works
- Claude Docs「Implement tool use(Define tools)」 https://platform.claude.com/docs/en/agents-and-tools/tool-use/implement-tool-use
- Claude Docs「Handle tool calls」 https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AIエージェントとは|仕組みとワークフローとの違い・作り方入門」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。