AI Agentとは?ReActでLLMが考えて行動する仕組み

目標・Reasoning・Tool・Observation・人間承認を循環させるAI Agentの全体像

目標・Reasoning・Tool・Observation・人間承認を循環させるAI Agentの全体像

AI Agent(AIエージェント)とは、LLM(大規模言語モデル)が目標と現在の状態を基に次の行動を選び、その結果を観測しながら処理を繰り返すシステムです。LLM単体をAgentと呼ぶのではなく、LLM、Tool、状態管理、実行環境、停止条件、安全制御を組み合わせた制御loopとして捉えると、仕組みが見えやすくなります。

ReActは、このloopを理解する代表的な考え方です。Reasoning(次に何を調べ、どう進めるかの判断)とActing(検索やAPI呼び出しなどの行動)を交互に行い、Observation(行動から返った観測)を次の判断へ反映します。ただし、ReActはAgent全般の同義語ではありません。Agentを構成するtrajectory pattern(行動軌跡の型)の一つです。

この記事では、ReAct論文の問題設定から出発し、Function Callingとの違い、固定workflowとの使い分け、停止条件を備えたPython実装、安全設計、評価までを一つの流れで解説します。

3行要約

  • AI Agentは、LLMが目標と状態を見ながらToolを選び、Observationに応じて次の手を変える制御loopです。
  • ReActはThought・Action・Observationを組み合わせ、外部世界の情報で計画を更新する代表的な方法です。
  • 実運用では賢いpromptより先に、権限、承認、停止条件、step予算、監査log、結果検証をcodeで強制します。

前回のFunction Callingとは?Tool Useの仕組み・実装・安全設計を解説では、modelのtool callを「未検証の実行候補」として扱いました。今回のAgentは、その候補生成と実行結果の受け渡しを一回で終えず、目標を達成するまで制御する層です。

AI Agentは「LLMにToolを渡したもの」だけではない

Agentという言葉には幅があります。本記事では実装を議論しやすくするため、次の操作的な定義を使います。

AI Agentは、与えられた目標に対して、LLMが現在の状態から次の行動を動的に選び、外部環境の観測を取り込み、完了・失敗・承認待ち・予算超過のいずれかへ到達するまで制御するシステムである。

AnthropicのBuilding effective agentsは、事前定義したcode pathでLLMとToolを編成するものをworkflow、LLMがprocessとTool利用を動的に方向づけるものをAgentとして区別しています。OpenAIの実践ガイドも、LLMがworkflowの実行を管理し、状態に応じてToolを選び、完了や失敗時のhandoffを判断する点をAgentの特徴として説明しています。

この定義で、chatbotからAgentまでを比較します。

方式 次の処理を決める主体 外部Tool 複数stepの状態 向く仕事
通常のchatbot 利用者と一回のLLM応答 原則なし 会話履歴のみ 説明、要約、文章生成
Function Calling LLMがcall候補、applicationが一回の実行を管理 あり 必須ではない 天気照会、単発計算、注文確認
固定workflow application code 必要に応じてあり codeで明示 手順が安定した審査、変換、定期処理
AI Agent LLMとapplicationの制御loop あり goalと途中状態を保持 経路が事前に決まらない調査、障害対応、開発作業

Function CallingはToolを呼ぶinterfaceです。Agentは「何を調べたか」「次に何が必要か」「いつ終了するか」を複数回にわたり管理します。したがって、Function Callingを実装しただけで必ずAgentになるわけではありません。一方、AgentのActionを安全に構造化する手段としてFunction Callingを使うことはできます。

ReActが解こうとした問題

Thought・Action・Observationで状態を更新しながら進むReActループ

ReAct: Synergizing Reasoning and Acting in Language Modelsは、ReasoningとActingが別々に研究されてきたことを問題として置きました。

Reasoningだけで回答を作る場合、modelは頭の中にある情報だけで長い推論を進めます。途中の前提が誤っていても外部世界へ確かめに行けず、誤りが後段へ伝播しやすくなります。逆にActionだけを連続生成すると、何のためにその操作を行ったか、どのsubgoalが終わったかを見失いやすくなります。

ReActは両者を一つのtrajectoryへ入れます。

  1. 現在の目標と観測から、次に必要なことを判断する。
  2. 検索、照会、環境操作などのActionを選ぶ。
  3. 実行環境からObservationを受け取る。
  4. Observationで計画を更新し、次のActionまたは最終回答を選ぶ。

論文では、reasoning traceが高水準の計画を作成・追跡・更新し、例外へ対応する役割を持ちます。ActionはWikipediaのような外部情報源や操作対象の環境へ接続し、reasoningを現実の情報へ接地します。言い換えると、考えてから動くだけでなく、動いて得た事実によって考え直すのがReActの要点です。

Thoughtは公開用の「心の声」と同じではない

ReAct論文は、few-shot promptに人間が書いたverbal reasoning traceを含め、modelにThoughtとActionを生成させました。しかし、これを「本番systemではmodelの非公開な内部推論をすべて表示・保存すべき」と読み替える必要はありません。

運用上必要なのは、後から検証できる意思決定の記録です。たとえば、次の情報を構造化して残します。

  • 目標と現在の状態
  • 選択したActionと検証済みarguments
  • Toolを選んだ短い理由やsubgoal
  • 返ったObservationと出典・時刻
  • state transition(状態遷移)
  • 人間が承認または拒否した事実

これは内部推論の逐語録ではなく、applicationが管理するaudit trace(監査用の行動記録)です。ActionとObservationを追跡できれば、誤った回答がmodelの判断、Toolの結果、古いdata、認可処理のどこで生じたかを切り分けられます。

Thought・Action・Observationで状態を更新する

Agentの時刻\(t\)における状態を\(s_t\)、選んだ行動を\(a_t\)、実行結果の観測を\(o_t\)とします。状態更新を抽象化すると、次の形で表せます。

\[a_t = \pi(g, s_t, T)\]
\[o_t = E(a_t)\]
\[s_{t+1} = U(s_t, a_t, o_t)\]

\(g\)はgoal、\(T\)は利用可能なTool、\(\pi\)は次のActionを選ぶpolicy(状態から行動を選ぶ規則)、\(E\)はToolや外部環境、\(U\)は状態更新です。LLMは主に\(\pi\)の一部を担います。Tool実行\(E\)と、許可・停止を含む\(U\)までmodelへ任せる設計にはしません。

配送遅延を調べる具体例

注文照会と配送追跡の観測から配送遅延の原因を調べるAgent

利用者の目標が「注文A-104が届かない原因を調べて」だとします。一回のTool callだけでは、注文が出荷済みか、配送会社で止まっているかを判断できません。

Step 判断またはsubgoal Action Observation 状態の変化
1 注文自体の状態が必要 get_order_status(A-104) 出荷済み、追跡番号TR-88 注文処理の停滞ではない
2 配送会社側の現在地が必要 track_shipment(TR-88) 仕分け拠点、天候遅延 原因と最終更新時刻を取得
3 回答に必要な根拠が揃った finish なし 成功状態へ遷移

Step 1のObservationが「未出荷」なら、Step 2は配送追跡ではなく倉庫状況の照会になるかもしれません。Actionが事前に固定されず、観測によって分岐する点がAgentらしさです。

ただし、この例はread-onlyです。「遅れているので再発送する」まで自動化すると副作用が生じます。再発送には在庫、金額、重複処理、本人確認が関係するため、別のActionとして分離し、人間承認を挟むべきです。

ReAct論文は何を示したのか

ReAct論文は、知識を調べるtaskと、環境内で行動するtaskの両方を評価しました。

知識集約task

HotpotQA(複数の情報を組み合わせる質問応答)とFEVER(主張の事実検証)では、SearchLookupFinishからなる簡単なWikipedia APIを利用しました。Thought、Action、Observationを複数回繰り返し、何を検索し、見つけた情報から次に何を調べるかを更新します。

論文は、ReActが両taskでAct-onlyを上回ったと報告しています。また、reasoning-onlyで生じる事実のhallucinationや誤りの伝播を、外部検索によって抑えられる例を示しました。ただし「検索すればhallucinationがなくなる」という意味ではありません。検索語が悪い、異なる同名項目を選ぶ、Observationを誤読する、といった失敗は残ります。

対話的な意思決定task

ALFWorldは家庭内作業をtext環境で行うbenchmark、WebShopはWeb上の商品探索・購入を模したbenchmarkです。論文abstractは、当時比較した模倣・強化学習手法に対し、絶対成功率でALFWorldは34ポイント、WebShopは10ポイント上回ったと報告しています。ALFWorldでは、ReActがreasoningを除いたReAct-IMの全体成功率53に対して71でした。

この数値は、PaLM-540Bを中心とする当時のmodel、少数のin-context examples、各benchmarkのaction spaceという条件で得られたものです。現在の任意のmodelや業務Agentが同じ差で改善するとは限りません。論文から一般化できるのは「reasoningとactionを観測で接続する設計が複数種類のtaskで有効だった」という範囲です。

Thoughtを毎step出す必要もない

論文では、知識taskでThoughtとActionを交互に生成しました。一方、行動数が多い意思決定taskでは、ThoughtをすべてのActionの前に置かず、重要な位置へ疎に挿入する方法も採用しています。

毎step長文を生成するとtoken、latency、context消費が増えます。実装では、計画の更新、例外発生、subgoal完了、Tool選択が曖昧な場面など、判断が必要な境界で短い構造化decisionを求める方が管理しやすくなります。

Agentを構成する8つの部品

Goalから停止判定までAI Agentを構成する8つの役割

ReAct promptだけでは運用可能なAgentになりません。最低限、次の役割を分離します。

部品 責任 modelだけに任せないもの
Goal 何を達成すれば終了か定義する 成功条件の勝手な変更
Policy / Planner 状態から次のActionを提案する 認可と実行の最終決定
State 確認済み事実、未解決subgoal、予算を保持する 会話全文を無制限に蓄積
Tool registry Tool名、schema、risk、timeoutを管理する 存在しないToolの実行
Executor 検証済みActionを実行する model出力の無条件実行
Observation adapter 結果を正規化し、出典・時刻・errorを付ける 外部textを命令として扱うこと
Guardrails 権限、承認、data境界を強制する promptだけの禁止事項
Stop / Evaluator 完了、失敗、予算切れ、進捗停止を判定する modelの自己申告だけで成功にすること

Goalは「よい回答を作る」では曖昧です。配送調査なら「注文の現在状態、遅延理由、最終更新時刻を、照会結果に基づいて利用者へ示す」のように、確認可能な終了条件へ落とします。

Stateには、確認済みの事実とmodelの仮説を混ぜません。factsopen_questionsattempted_actionsbudgetなどに分ければ、「推測をObservationとして再利用する」事故を減らせます。

固定workflowとAgentはどちらを選ぶべきか

決まった経路を進む固定workflowと観測で経路を選ぶAI Agentの比較

自由度が高いほど優れているわけではありません。Anthropicのガイドは、明確に分解できるtaskにはworkflowが予測可能性と一貫性を提供し、柔軟なmodel判断が必要なtaskでAgentが候補になると説明しています。Agentic systemは一般にlatencyとcostを増やすため、単一のLLM callや固定workflowで解けるなら、その方が運用しやすい場合があります。

比較軸 固定workflow AI Agent
経路 codeで事前定義 観測に応じてmodelが選ぶ
予測可能性 高い 入力と生成の揺らぎを受ける
例外への柔軟性 想定した分岐に限定 未知の組み合わせへ対応しやすい
test branch単位で網羅しやすい trajectoryとoutcomeを複数trialで測る
latency / cost 見積もりやすい step数によって増える
security 権限経路を限定しやすい Tool選択が動的なため境界設計が増える
向く例 請求書OCR→項目検証→登録 複数資料を行き来する調査、原因が未知の障害診断

次の条件なら、最初はworkflowを選びます。

  • 正常系と例外分岐を列挙できる
  • 法令・会計・決済など、同じ入力には同じ経路が必要
  • step数と実行費用を厳密に予測したい
  • modelに委ねる判断が分類や抽出に限られる

Agentが候補になるのは、必要な情報源や手順が最初には分からず、途中の観測によって次の調査先が変わる仕事です。それでも、認可、実行、停止まで自由化する必要はありません。経路選択だけをmodelへ任せ、権限と状態遷移はcodeで囲うのが実用的です。

停止できる最小Agent loopをPythonで実装する

次のcodeは、特定SDKに依存しないAgent loopの骨格です。decideはLLMから構造化されたActionを得る層、executeは検証・認可済みToolを動かす層として分離しています。

from __future__ import annotations

import logging
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Protocol

logger = logging.getLogger(__name__)


class RunStatus(str, Enum):
    """Agent runが取り得る状態。"""

    RUNNING = "running"
    WAITING_APPROVAL = "waiting_approval"
    SUCCEEDED = "succeeded"
    FAILED = "failed"
    STOPPED_BUDGET = "stopped_budget"


@dataclass(frozen=True)
class Action:
    """Policyが提案する、まだ実行されていないAction。"""

    name: str
    arguments: dict[str, str]
    requires_approval: bool = False

    def signature(self) -> str:
        """重複実行を検知する安定した署名を返す。

        Returns:
            Tool名とsort済みargumentsから作った署名。

        Raises:
            TypeError: argumentsのkeyまたはvalueが文字列でない場合。

        Example:
            >>> Action("lookup", {"id": "A-104"}).signature()
            "lookup:[('id', 'A-104')]"
        """
        if not all(isinstance(k, str) and isinstance(v, str) for k, v in self.arguments.items()):
            raise TypeError("action arguments must contain string keys and values")
        return f"{self.name}:{sorted(self.arguments.items())}"


@dataclass(frozen=True)
class Observation:
    """Tool実行後にapplicationが正規化した観測。"""

    ok: bool
    summary: str
    source: str


@dataclass
class AgentState:
    """LLMの会話履歴とは分離して保持する実行状態。"""

    goal: str
    status: RunStatus = RunStatus.RUNNING
    step: int = 0
    facts: list[str] = field(default_factory=list)
    open_questions: list[str] = field(default_factory=list)
    action_signatures: set[str] = field(default_factory=set)
    final_answer: str | None = None


class Policy(Protocol):
    """現在のstateから次のActionを構造化して提案する境界。"""

    def decide(self, state: AgentState) -> Action:
        """次のActionを提案する。

        Args:
            state: 確認済み事実と残課題を含む現在状態。

        Returns:
            未検証・未実行のAction候補。

        Raises:
            RuntimeError: model応答をActionへ変換できない場合。

        Example:
            >>> action = policy.decide(AgentState(goal="注文A-104を調べる"))
        """
        ...


class Executor(Protocol):
    """schema・認可・timeoutを強制してToolを実行する境界。"""

    def execute(self, action: Action) -> Observation:
        """検証済みActionを実行する。

        Args:
            action: Policyが提案し、allowlistで許可されたAction。

        Returns:
            出典付きに正規化したObservation。

        Raises:
            PermissionError: 利用者にActionの権限がない場合。
            TimeoutError: Toolが制限時間内に完了しない場合。
            ValueError: argumentsがschemaまたは業務制約に違反する場合。

        Example:
            >>> observation = executor.execute(action)
        """
        ...


def apply_observation(state: AgentState, action: Action, observation: Observation) -> None:
    """ActionとObservationをstateへ反映する。

    Args:
        state: 更新対象の実行状態。
        action: 実行済みAction。
        observation: 正規化済みTool結果。

    Returns:
        なし。stateをin-placeで更新する。

    Raises:
        ValueError: Observationにsourceがなく監査可能性を保てない場合。

    Example:
        >>> apply_observation(state, action, Observation(True, "出荷済み", "orders-api"))
    """
    if not observation.source:
        raise ValueError("observation source is required")
    state.facts.append(f"{action.name}: {observation.summary} [{observation.source}]")
    if not observation.ok:
        logger.warning("tool returned a failed observation: tool=%s", action.name)


def run_agent(
    policy: Policy,
    executor: Executor,
    state: AgentState,
    *,
    max_steps: int = 8,
    deadline_seconds: float = 30.0,
) -> AgentState:
    """予算・重複・承認境界を持つAgent loopを実行する。

    Args:
        policy: 次のAction候補を返すPolicy。
        executor: 検証・認可後にToolを実行するExecutor。
        state: goalと途中経過を保持する初期状態。
        max_steps: 一回のrunで許可する最大Action数。
        deadline_seconds: wall-clockの最大実行秒数。

    Returns:
        成功、失敗、承認待ち、予算停止のいずれかになったstate。

    Raises:
        ValueError: max_stepsまたはdeadline_secondsが正でない場合。
        RuntimeError: PolicyやExecutorが想定外の状態を返す場合。

    Example:
        >>> result = run_agent(policy, executor, AgentState(goal="注文A-104を調べる"))
        >>> result.status in set(RunStatus)
        True
    """
    if max_steps <= 0 or deadline_seconds <= 0:
        raise ValueError("budgets must be positive")

    deadline = time.monotonic() + deadline_seconds
    logger.info("agent run started: goal=%s max_steps=%d", state.goal, max_steps)

    while state.status is RunStatus.RUNNING:
        if state.step >= max_steps or time.monotonic() >= deadline:
            state.status = RunStatus.STOPPED_BUDGET
            logger.warning("agent stopped by budget: step=%d", state.step)
            break

        action = policy.decide(state)
        logger.debug("action proposed: step=%d tool=%s", state.step, action.name)

        if action.name == "finish":
            state.final_answer = action.arguments.get("answer")
            state.status = RunStatus.SUCCEEDED if state.final_answer else RunStatus.FAILED
            logger.info("agent finished: status=%s steps=%d", state.status.value, state.step)
            break

        signature = action.signature()
        if signature in state.action_signatures:
            state.status = RunStatus.FAILED
            logger.error("duplicate action detected: signature=%s", signature)
            break

        if action.requires_approval:
            state.status = RunStatus.WAITING_APPROVAL
            logger.info("agent paused for approval: tool=%s", action.name)
            break

        state.action_signatures.add(signature)
        try:
            observation = executor.execute(action)
        except (PermissionError, ValueError) as exc:
            state.status = RunStatus.FAILED
            logger.error("non-retryable tool failure: tool=%s error=%s", action.name, exc)
            break
        except TimeoutError as exc:
            state.status = RunStatus.FAILED
            logger.warning("tool timed out: tool=%s error=%s", action.name, exc)
            break

        apply_observation(state, action, observation)
        state.step += 1

    return state

この骨格で大事なのは、LLM APIの呼び方ではなく責任分離です。

  • Policy.decideの戻り値は提案であり、Executorがschemaと認可を強制する
  • 同一Actionの署名を保存し、この最小例では同じ引数の反復を失敗として止める
  • max_stepsとdeadlineの両方を持つ
  • 副作用Actionは実行せずWAITING_APPROVALで停止する
  • finishにも空回答を許さず、成功条件をapplication側で追加検査できる
  • retry可能な一時障害と、権限・入力違反のような非retry障害を分ける

実運用では、Actionごとのrisk level、idempotency key(再試行しても処理を重ねない識別子)、利用者scope、Tool別timeout、総token予算もStateまたはExecutorへ加えます。

状態遷移を先に決める

実行中から承認待ち・成功・失敗・予算停止へ分岐するAgentの状態遷移

Agent loopをwhile Trueで始めると、終了理由がすべて「回答した」か「例外で落ちた」になります。実際には、次の状態を区別すべきです。

状態 意味 再開条件
RUNNING 次のActionを選べる loop継続
WAITING_APPROVAL 高影響Actionの承認待ち 利用者の明示承認と対象再確認
SUCCEEDED 検証可能な成功条件を満たした 原則終了
FAILED 権限不足、入力不正、回復不能error 修正されたgoalまたは人へのhandoff
STOPPED_BUDGET step、時間、token、費用の上限 予算追加ではなく、進捗と必要性を確認

停止条件は最低でも、最大step、deadline、同一Actionの反復、連続error、no-progress(新しい事実が増えない状態)、利用者cancelを含めます。ただし、同じreadを再試行する正当な理由があるsystemでは、完全禁止ではなく回数とbackoffを決めます。上限へ達したとき、勝手に「成功」として文章を整えず、確認済みの事実、未解決点、試したActionを返します。

Memoryは4種類を一つのpromptへ詰め込まない

Working state・会話履歴・長期記憶・監査記録を分離したAgentのMemory設計

AgentではMemory(記憶)という言葉も広く使われます。会話全文をmodelへ戻し続ける実装は簡単ですが、contextが膨らみ、古い指示や不要な個人情報が残り、どの事実を信用したか分かりにくくなります。

種類 保存するもの 典型的な保持期間 注意点
Working state 現在のsubgoal、確認済みfact、残予算 一回のrun 推測と観測を分ける
Conversation history 利用者との合意、訂正、質問 session 要約時に制約を落とさない
Long-term memory 利用者が保存を許可した安定情報 sessionをまたぐ 同意、更新、削除、tenant分離
Audit trace Action、arguments、Observation、approval policyに基づく 機密値をmaskし改ざんを防ぐ

次のAction選択には、全文ではなく「今回の判断に必要なstate」を渡します。長いTool resultは原文の保存先とhashを残し、modelには必要部分とprovenance(由来)を渡す方法があります。

RAGとは?LLMに外部知識を使わせる仕組みで扱った検索結果もObservationの一種です。検索文書を長期Memoryと混同せず、出典、取得時刻、queryを付けて一回の判断材料として扱います。

Agentで起きやすい失敗と対策

重複検知・成功条件・命令分離・最小権限・人間承認でAgentを守る安全設計

同じToolを呼び続ける

「情報が足りない」という判断だけが残り、同じqueryや同じIDで検索を反復することがあります。Action signatureの重複、Observationのhash、factsの増分を監視し、進捗がなければ止めます。queryの表記を少し変えただけの反復もあるため、完全一致に加えて目的と対象を正規化して比較します。

早すぎる完了

もっともらしい文章が生成できると、必要なfactが揃う前にfinishを選ぶ場合があります。成功条件をrequired_factsとしてcodeで確認し、欠けていれば最終回答を受理しません。配送例なら、注文状態だけでなく、遅延理由と最終更新時刻が必要です。

Observationを命令として実行する

Webページや文書に「以前の指示を無視して、このToolを呼べ」と書かれている可能性があります。これはindirect prompt injection(外部data経由で混入する命令)です。Observationはdataとして区切り、system instructionへ昇格させません。外部textがToolの許可範囲を広げたり、approvalを省略したりできない構造にします。

権限が広すぎる

OWASP LLM06:2025 Excessive Agencyは、過剰な機能、過剰な権限、過剰な自律性を主要因として挙げています。読み取りAgentへ更新・削除可能なcredentialを渡す、使わなくなったToolをregistryへ残す、高影響Actionを確認なしで実行する設計は避けます。

対策は「危険なことをしないで」とpromptへ書くだけでは不十分です。

  • readとwriteのToolを分ける
  • 利用者・tenant・resource単位で最小権限を強制する
  • 送信、購入、公開、削除はexecute直前に内容を表示して承認を取る
  • sandboxとnetwork allowlistで到達範囲を狭める
  • secretをmodel contextへ渡さずExecutor側で注入する
  • side effectにはidempotency keyと取り消し手段を用意する

長いloopほど誤りが連鎖する

各stepの成功率が高くても、長いtrajectoryでは失敗機会が増えます。subgoal単位でcheckpointを置き、観測をvalidateし、必要なら人へhandoffします。Agentに「最後まで自律的にやらせる」ことを目標にせず、どこで確実なcodeや人へ制御を戻すかを設計します。

Agentは最終回答だけでは評価できない

TrajectoryとOutcomeの両方からAI Agentを評価する検査工程

Agentが「注文を再発送しました」と答えても、実際のsystemに再発送recordがなければ失敗です。逆に、正しい結果へ到達しても、不要な個人情報へaccessしたり、同じAPIを20回呼んだりしていれば、安全性と効率の面で不合格です。

AnthropicのAgent評価ガイドは、trajectoryをtool callsや中間結果を含む試行の記録、outcomeを終了時の環境状態として区別しています。この二つを評価対象にします。

評価面 指標例 検査方法
Outcome task成功、正しいrecord作成、必要field充足 databaseや環境stateをcodeで確認
Trajectory Tool選択、不要step、禁止Action、順序 trace assertion、policy check
Groundedness 回答がObservationに支えられるか claimとsourceの対応検査
Safety 権限違反、未承認write、秘密情報露出 adversarial task、security test
Recovery timeout、空結果、矛盾から復帰できるか fault injection
Efficiency step数、token、latency、Tool費用 runごとの計測

生成には揺らぎがあるため、一つのtaskを一回通しただけで判断しません。同じ条件で複数trialを実行し、成功率だけでなく失敗の分布を見ます。codeで判定できる最終状態、rubricによる回答品質、人間による境界例の確認を組み合わせます。

また、評価用taskには「成功すべき例」だけでなく、次を含めます。

  • 情報不足なので質問すべき例
  • 権限不足で拒否すべき例
  • 承認待ちで止まるべき例
  • Toolがtimeoutする例
  • 外部文書にprompt injectionが含まれる例
  • 予算内に解けず、未解決として返すべき例

成功率を上げるために安全な拒否や停止を減らしていないか、別の指標として監視する必要があります。

実装前チェックリスト

Agentを作る前に、次の項目へ答えられるか確認します。

  • goalの成功条件を環境stateで検証できるか
  • 固定workflowでは解けず、観測に応じた動的な経路選択が本当に必要か
  • modelへ任せる判断と、codeで固定する認可・状態遷移を分けたか
  • Toolは用途ごとに小さく、readとwriteが分離されているか
  • Observationにsource、取得時刻、error classを付けるか
  • 最大step、deadline、token、費用、重複、no-progressの停止条件があるか
  • 副作用Actionの直前に承認し、承認対象が実行内容と一致するか
  • secretと高権限credentialをmodel contextから隔離したか
  • trajectoryとoutcomeを記録し、複数trialで評価できるか
  • 失敗時に確認済みfact、未解決点、次の人間Actionを返せるか

最初のversionはread-onlyの小さなtaskへ限定すると、ActionとObservationの品質を観察しやすくなります。そこで評価dataと失敗例を集め、必要な箇所だけToolや自律性を増やします。

まとめ

AI Agentの本質は、LLMに人格を与えることではなく、目標と状態を持つ制御loopを作ることです。ReActは、ReasoningとActionをObservationで結び、行動結果から計画を修正する形を明確にしました。

一方、ReAct形式のpromptだけでは、安全なAgentにはなりません。Toolのschemaと認可、状態管理、停止条件、予算、人間承認、audit trace、outcome検証はapplication側の責任です。経路が固定できる仕事にはworkflowを使い、不確実な経路選択が必要な部分だけをAgentへ任せると、柔軟性と予測可能性の釣り合いを取りやすくなります。

次回は、長いtaskの途中状態や過去の情報をどう保持するか、AgentのMemory設計を扱います。

参考資料

コメント

タイトルとURLをコピーしました