テーマを切り替える

AI Agent の状態機械設計:複雑なワークフローを Prompt だけに任せられない理由

Easton editorial illustration: large Agent state recorder, coral failure beacon, checkpoint rewind handle, recovery status strip
8
中核状態フィールド
state、event、guard、action、checkpoint、retry、compensation、terminal。
4
記録オブジェクト
state snapshot、event log、trace、audit log。
3
復旧 action
resume、retry、compensate。
数据来源: このエンジニアリングチェックリストは、LangGraph、Temporal、OpenAI Agents SDK、AWS Step Functions、Stately の公式ドキュメントをもとに整理しています。API 名や製品挙動は、公開後も公式ドキュメントで確認してください。

"LangGraph Persistence のドキュメントは、checkpoint を thread-scoped な graph state snapshot として説明し、conversation continuity、human-in-the-loop、time travel、fault tolerance を支えるものとしています。"

レポート Agent が第 5 ステップのメール送信直前で失敗しました。運用担当者がタスクを再実行すると、Agent は第 1 ステップからやり直し、新しいレポートを生成して、前回承認済みだった版を上書きしました。承認状態は失われ、承認者の署名記録は新しい結果に置き換わり、最初のレポートが承認済みだったことを証明できるログも残っていません。

これはデータベースのトランザクション rollback でも、メッセージキューの retry でもありません。Prompt には「続けて処理する」という 1 文しか残っておらず、モデルはワークフロー全体をもう一度推論しました。第 1〜4 ステップで副作用がすでに発生していたことを、モデルは知りません。承認 API を呼び、レポートを生成し、一時ファイルを書き込んでいたのです。失敗点は第 5 ステップでしたが、副作用は第 2 ステップから始まっていました。

本当の問題は「モデルの能力が足りない」ことではありません。タスク進捗が prompt の自然言語に隠れていて、復旧可能な状態 snapshot がなかったことです。Prompt が持つ messages はモデルのコンテキストであり、実行事実ではありません。

この種の事故を直すには、prompt に「続行前に進捗を確認する」と 1 文足すだけでは足りません。現在ノード、発生済みの副作用、次の action、失敗時の補償を、復旧可能な状態表に落とすほうが安定します。

事故の要点

レポート Agent の実行フロー:

ステップ操作副作用幂等性
第 1 ステップデータ照会データベースを呼び出し、ユーザーデータを照会幂等(読み取り操作)
第 2 ステップレポート生成レポート生成ツールを呼び出し、PDF を生成幂等ではない(ファイルを上書き)
第 3 ステップ承認待ち承認リクエストを送信し、人間の承認を待つ幂等(API が対応)
第 4 ステップ承認完了approve event を受信幂等(状態照会)
第 5 ステップメール送信メール API を呼び出し、レポートを送信失敗(timeout)

失敗原因:第 5 ステップのメール送信が外部 API の rate limit で timeout し、タスクが FAILED とマークされました。

再実行ロジック:prompt から「現在の進捗」を読み取ります。Prompt には「承認済み、処理を続ける」という文しかありません。実際の実行:第 1 ステップから再開 -> 第 2 ステップでレポートを再生成(承認済み版を上書き)-> 第 3 ステップで再度承認 -> 第 5 ステップで送信成功。

業務影響:承認済みレポートが差し替わり、承認記録と実際に届いたレポートが一致しなくなりました。ユーザーは「承認した内容と受け取った内容が違う」と苦情を出し、承認フローは 2 つの版を承認したのに、実際に送られたのは 1 つだけという無駄を生みました。

アンチパターン識別表

あなたの Agent が次のアンチパターンに当てはまるか確認してください:

アンチパターン表れ方隠れたリスク修正案
進捗を Prompt に書く「現在第 3 ステップ」などの自然言語要約再起動後に失われ、復旧できないState フィールドで現在ノードを記録する
Trace を State とみなす完全な Trace があるので状態もあると思い込むTrace は次の判断を記録しないState に次に行うべきことを記録する
幂等チェックなしの Retry失敗したら最初から再実行副作用が重複実行される幂等キー + 実行済みチェック
承認後 Resume の検証なしそのまま続行する正しい実行点に戻れないcheckpoint + thread_id

1. 状態機械の基礎:State、Event、Transition、Guard、Action

状態機械はすべての Agent に必要な構成ではありません。単純なカスタマーサポート Q&A なら messages 配列で十分です。しかし、多段階、承認、外部システム呼び出し、失敗後の復旧を含む複雑なタスクでは、タスク進捗を明示する必要があります。

1.1 中核用語の定義表

状態機械の基本用語は Stately の公式ドキュメントに基づきます:

用語定義Agent の例出典
State(状態)機械が置かれているモードで、単一の意味的意図に対応INIT、PLAN_READY、TOOL_RUNNING、APPROVAL_PENDING、FAILED、COMPLETEDStately state machines
Event(イベント)状態変化を引き起こす外部信号timeout、approve、reject、retry、resume、task_receivedStately state machines
Transition(遷移)状態間で許可された経路。決定的な mappingINIT -> PLAN_READY(event: task_received)Stately state machines
Guard/Condition(ガード)ある状態へ入るための前提チェック「予算が十分」のときだけ TOOL_RUNNING に入るStately state machines
Action(動作)遷移時に実行される操作TOOL_RUNNING に入るときにツールを呼び出すStately state machines
Checkpoint(snapshot)復旧に使う状態 snapshotLangGraph checkpointer が graph state を保存LangGraph Persistence

決定性の原則:同じ State + Event の組み合わせは、曖昧さを避けるために 1 つの next state だけを指すべきです。有限状態集合:状態機械は無限のフローチャートではなく、有限の到達可能状態と明確な遷移ルールです。

1.2 Trace vs State vs Audit の比較表

Trace、Audit Log、State Snapshot は、それぞれ別の問題を解きます:

概念解く問題業務状態か次の一手を決めるかAgent の例
Trace(追跡)観測と診断の骨格いいえ決めないOpenAI Agents SDK trace(workflow_name、trace_id)
Audit Log(監査ログ)コンプライアンス記録、監査追跡いいえ決めない権限モデルの監査フィールド(actor、traceId、action、result)
State Snapshot(状態 snapshot)次の一手を決める現在状態はい決めるLangGraph checkpoint(現在ノード、完了済みステップ、次に行うべきこと)

重要な区別はここです。Trace は「何が起きたか」を観測するためのものですが、業務状態そのものではありません。Audit Log はコンプライアンス履歴を残し、監査追跡に使います。State Snapshot は「次に何をすべきか」を決めるためのもので、復旧の中核です。3 つは互いに代替できません。Trace があることは State があることではなく、Audit があることは復旧可能であることではありません。

2. LangGraph は状態永続化をどう扱うか

Checkpoint は prompt 内の自然言語要約ではありません。復旧でき、検査でき、replay できる状態 snapshot です。LangGraph persistence のドキュメントでは、checkpoint は graph state snapshot と定義され、完全な状態と次に実行するノードを含みます。

2.1 Checkpointer と Thread State

中核メカニズム(LangGraph Persistence 公式ドキュメントより):

  • Checkpointer:thread-scoped な状態 snapshot(graph state snapshot)を保存する
  • Store:thread をまたぐ長期データ(application-defined store)を保存する
  • Thread_id:特定 thread state を復旧する唯一の入口
  • 4 つの用途:conversation continuity、human-in-the-loop、time travel、fault tolerance

LangGraph persistence は、短期の thread-scoped state を checkpointers に任せ、thread をまたぐ長期データを stores に任せます。Checkpoint には state snapshot と application-defined store が含まれます。Thread_id は復旧入口であり、同じ thread_id なら停止点から続行できます。

LangGraph checkpoint には graph state、次に実行するノード一覧、checkpoint_id、timestamp、version が含まれます。機密データは checkpoint に入れない方がよい場合があります。graph state の一部フィールドに機密情報が含まれるなら、保存しないための明示的な設定が必要です。

2.2 Interrupts と復旧メカニズム

中核メカニズム(LangGraph Interrupts 公式ドキュメントより):

  • interrupt():graph node 内で実行を動的に一時停止し、graph state を保存して外部入力を待つ
  • 復旧方法:同じ thread_id と Command(resume=…) を使う
  • よくあるパターン:承認、review/edit、tool call review、human input validation
  • 幂等副作用の警告:interrupt 前の副作用は幂等でなければならない。復旧時、node は interrupt を呼んだ node の先頭から再実行されるため

承認待ちは、モデルに「承認を待っていることを覚えていて」と期待するのではなく、状態機械上の一時停止状態にするべきです。復旧には同じ thread cursor が必要です。

復旧時は同じ thread_id と Command(resume=…) を使います。幂等な副作用は復旧の前提条件です。承認前に外部 API 呼び出しなどの副作用がある場合、それを幂等にしておかないと、復旧時に node が再実行され、API が重複呼び出しされます。

3. エンジニアリング上の類比:Temporal Durable Execution

長時間タスクの信頼性は新しい問題ではありません。Temporal durable execution は成熟した比較対象になります。

3.1 Durable Execution の定義

中核概念(Temporal Durable Execution 公式ドキュメントより):

  • Durable Execution の定義:workflow execution が失敗、クラッシュ、サービス中断時にも state/progress を保持する
  • Event History:各ステップの状態を記録し、失敗後に最後の記録イベントから復旧できるようにする
  • 3 つの特性:Resumable(再開可能)、Recoverable(復旧可能)、Reactive(反応可能)

長時間タスクの信頼性は event history と復旧可能な実行から生まれます。単一プロセスのメモリや prompt コンテキストからではありません。Agent 状態機械にも同じ発想が必要です。checkpoint/event log + 業務状態であり、モデルによる再推論だけでは足りません。

Temporal の Event History と LangGraph の checkpoint は概念的に近いものです。どちらも実行履歴を記録し、失敗点からの復旧を支えます。違いは、Temporal が完全な workflow engine で、LangGraph が Agent の状態管理フレームワークであることです。Agent 開発者が Temporal から学べるのは、durable execution には構造化された状態履歴が必要であり、プロセスメモリやモデルコンテキストに依存してはいけない、という点です。

4. 状態表設計テンプレート:コピーして使える Agent State Table

状態機械の概念は抽象的です。実装に落とすには、具体的な状態モデルが必要です。ここでは状態表、イベント表、事故駆動の状態表例の 3 つを用意します。

4.1 状態表テンプレート(実行可能なステップブロック)

テンプレート構造:

State(状態)Event(トリガーイベント)Guard(ガード条件)Action(必須動作)Next(次状態)
INITtask_receivedなしコンテキストを初期化し、開始時刻を記録PLAN_READY
PLAN_READYplan_generatedplan_valid実行計画を生成し、ツール列を記録TOOL_RUNNING
TOOL_RUNNINGtool_completedbudget_sufficientツールを呼び出し、結果を記録し、予算を更新APPROVAL_PENDING または COMPLETED
APPROVAL_PENDINGapproveapproval_required承認リクエストを送信し、承認者を記録COMPLETED
APPROVAL_PENDINGrejectなし拒否理由を記録し、ユーザーへ通知FAILED
FAILEDretryretry_count < max幂等性を確認し、前の checkpoint へ戻すTOOL_RUNNING または APPROVAL_PENDING
COMPLETEDなしなし完了時刻を記録し、リソースをクリーンアップTerminal

テンプレート説明:State 列は到達可能な状態(INIT、PLAN_READY、TOOL_RUNNING、APPROVAL_PENDING、FAILED、COMPLETED)を定義します。Event 列は遷移を引き起こす event(task_received、approve、reject、retry)を定義します。Guard 列は状態に入る前提条件(budget_sufficient、retry_count < max)を定義します。Action 列は遷移時の必須動作(ツール呼び出し、結果記録、承認送信)を定義します。Next 列は決定的な遷移先を定義します。

4.2 イベント表テンプレート(状態表の補足)

テンプレート構造:

Event(イベント名)トリガー条件前置状態要件後置状態副作用を生むか
task_receivedユーザーがタスクを送信INITPLAN_READY生まない
plan_generatedLLM が実行計画を生成PLAN_READYTOOL_RUNNING生まない
tool_completedツール実行が完了TOOL_RUNNINGAPPROVAL_PENDING または COMPLETED生む(外部 API 呼び出し)
approve承認者が承認APPROVAL_PENDINGCOMPLETED生む(メール送信、予算扣減)
reject承認者が拒否APPROVAL_PENDINGFAILED生まない
retry失敗後の再試行リクエストFAILEDTOOL_RUNNING または APPROVAL_PENDING幂等チェックが必要
timeout実行 timeoutTOOL_RUNNINGFAILED生まない

イベント表の説明:前置状態要件により、どの状態でどの event を受け取れるかを明確にします。副作用の有無を示すことで、どの event に幂等性や補償が必要かが分かります。

4.3 事故駆動の状態表例(レポート上書き事故から導く)

完全な例:レポート Agent 状態表(冒頭の事故から導出)

StateEventGuardActionNext幂等/補償チェック
INITtask_receivedなしthread_id を初期化し、開始時刻を記録QUERY_RUNNING不要
QUERY_RUNNINGquery_completedなしデータを照会し、結果を state に保存REPORT_GENERATING不要
REPORT_GENERATINGreport_generatedなしレポートを生成し、report ID を state に保存APPROVAL_PENDING幂等チェック:レポートが既に存在するなら生成をスキップ
APPROVAL_PENDINGapproveなし承認者と承認時刻を記録EMAIL_SENDING不要
APPROVAL_PENDINGrejectなし拒否理由を記録FAILED不要
EMAIL_SENDINGemail_sentなしメールを送信し、email ID を記録COMPLETED幂等チェック:メール送信済みならスキップ
EMAIL_SENDINGtimeoutretry_count < 3失敗を記録し、幂等性を確認EMAIL_SENDING(retry)または FAILED幂等キー:email_id + thread_id
FAILEDretryretry_count < max幂等性を確認し、前の checkpoint から復旧QUERY_RUNNING または REPORT_GENERATING または EMAIL_SENDINGcheckpoint に基づき復旧点を決定
COMPLETEDなしなし完了時刻を記録し、リソースをクリーンアップTerminal不要

事故復旧の修正:第 5 ステップの失敗(EMAIL_SENDING -> timeout)では、QUERY_RUNNING ではなく EMAIL_SENDING から復旧すべきです。checkpoint には現在ノード(EMAIL_SENDING)、完了済みステップ(QUERY、REPORT_GENERATED、APPROVAL_APPROVED)、次に行うべきこと(EMAIL_SENDING)を記録します。レポート生成とメール送信には幂等キーが必要で、重複実行を避けます。

5. 幂等性と補償:復旧は checkpoint だけではない

Checkpoint があるからといって、すべての副作用を安全に復旧できるわけではありません。復旧には幂等性、トランザクション、補償、外部システム状態チェックも必要です。

5.1 幂等性と補償の概念

定義:

  • 幂等(Idempotent):複数回実行しても結果が同じで、重複副作用を生まないこと
  • 補償(Compensation):すでに起きた副作用を取り消し、一貫性を回復すること
  • トランザクション rollback:原子的な操作が失敗時に自動 rollback されること
  • 外部システム状態チェック:復旧前に外部システム状態を確認し、重複操作を避けること

状態一貫性の 3 本柱:幂等性識別子(action_id + schema_hash)、状態 snapshot チェーン(snapshot + prev_hash + delta)、補償 action 登録(undo_op)。

5.2 幂等性と補償の判断チェックリスト

どの操作に幂等性が必要で、どの操作に補償が必要かを判断します:

操作タイプ幂等性が必要か補償が必要か幂等キー設計補償案
データ照会(副作用なし)不要不要--
レポート生成(ファイル上書き)必要必要report_id + thread_id新しいレポートを削除し、承認済み版を復元
メール送信(外部 API)必要難しいemail_id + thread_id一部シナリオで訂正メールや取消メールを送る
在庫扣減(データベース)必要必要inventory_id + order_id在庫を戻す(扣減の補償)
チケット作成(外部システム)必要必要ticket_id + thread_idチケットをクローズする(作成の補償)
予算扣減(内部状態)必要必要budget_id + thread_id予算を戻す(扣減の補償)
承認リクエスト送信(永続副作用なし)不要不要--

判断ロジック:外部副作用を生むかどうかが、幂等性の必要性を決めます。取り消せる操作には補償が必要です。システムをまたぐ呼び出しでは、幂等キーに外部システム識別子を含めるべきです。原子的な操作は transaction rollback を使えます。

復旧は checkpoint だけではありません。幂等性、トランザクション、補償、外部システム状態チェックが必要です。checkpoint さえあればすべての副作用を安全に復旧できる、という言い方は正確ではありません。

6. Agent タスク状態チェックリスト:復旧可能 vs 復旧不能

すべての checkpoint が復旧できるわけではありません。Terminal state は workflow execution の終端状態です。完了、失敗、timeout、cancelled などが該当します。Terminal state は復旧できず、再実行または補償しかありません。

6.1 状態分類表

状態タイプ復旧可能か復旧条件復旧方法
Failed(失敗)可能retry_count < max前の checkpoint から復旧ツール呼び出し timeout
Retry(再試行)可能幂等チェック通過失敗ノードから再実行メール送信失敗
Compensation(補償)部分的に可能補償案があるundo_op を実行在庫扣減失敗
Approval Pause(承認停止)可能approve/reject eventCommand(resume=…)承認待ち
Terminal(終端)不可なし復旧経路なしCOMPLETED、FAILED(retry_count = max)

状態チェックリストの説明:Failed 状態は retry_count < max なら retry で復旧できます。Retry 状態は幂等チェックが必要で、失敗ノードから再実行します。Compensation 状態は補償案があれば部分的に復旧できます。Approval Pause 状態は approve/reject event で復旧します。Terminal State は復旧できません。COMPLETED、または最大 retry 回数に達した FAILED が該当します。

7. 次に読むもの

状態機械設計は出発点にすぎません。状態モデリングは具体的な業務シナリオと結びつける必要があり、タスクごとに状態粒度も復旧戦略も変わります。

シリーズ上下流ナビゲーション

記事関係リンク
Human-in-the-loop Agent 設計:どのステップに人間の承認が必要か承認停止の詳細/blog/ja/posts/ai/20260707-human-in-the-loop-agent-approval-design/
Agent コスト制御:モデルルーティング、ツール予算、失敗 retry の設計予算、retry 戦略/blog/ja/posts/ai/20260707-agent-cost-control-model-routing-tool-budget-cache-retry/
LangGraph 状態管理実践:2026 年の Agent アーキテクチャベストプラクティスLangGraph 状態管理/blog/ja/posts/ai/20260424-langgraph-agent-architecture/
AI Agent の監視・アラート・失敗復旧:ログから状態機械まで監視、復旧/blog/ja/posts/ai/20260527-ai-agent-monitoring-recovery/
LangGraph vs AutoGen の状態追跡フレームワーク比較/blog/ja/posts/ai/20260526-langgraph-autogen-state-tracking/
Agent 評価データセットと回帰テスト:「1 箇所の変更で全体を壊す」を避ける方法評価、回帰テスト予告、同シリーズ次回

外部参考資料

信頼度の高い情報源:

出典信頼度テーマリンク
LangGraph Persistence 公式ドキュメントhighCheckpointer、Store、Thread State、Checkpointhttps://docs.langchain.com/oss/python/langgraph/persistence
LangGraph Interrupts 公式ドキュメントhighinterrupt()、Command(resume=…)、thread_idhttps://docs.langchain.com/oss/python/langgraph/interrupts
Temporal Durable Execution 公式ドキュメントhighEvent History、Durable Execution、Resumable/Recoverablehttps://docs.temporal.io/temporal
OpenAI Agents SDK Tracing 公式ドキュメントhighTrace、Span、workflow_name、trace_idhttps://openai.github.io/openai-agents-python/tracing/
AWS Step Functions State Machines 公式ドキュメントhighState Machine、Flow State、Task State、StartAt、Nexthttps://docs.aws.amazon.com/step-functions/latest/dg/concepts-statemachines.html
Stately: State machines and statechartsmediumState、Event、Transition、Guard、Action、Hierarchyhttps://stately.ai/docs/state-machines-and-statecharts

状態機械はすべての Agent に必要な構成ではありません。しかし、複雑なタスクでは進捗を明示する必要があります。次にやるべきことは、さらに多くのフレームワークを導入することではありません。業務シナリオに合う State、Event、Transition、Guard、Action を設計し、タスク進捗を prompt の自然言語から構造化状態へ移すことです。

複雑な AI Agent の状態機械を設計する

複雑な AI Agent タスクを state、event、guard、action、checkpoint、retry、compensation、terminal state に分解し、進捗を prompt だけに隠さないようにします。

⏱️ 目安時間: 45 分

  1. 1

    ステップ 1: リスク箇所を洗い出す

    タスクの外部副作用、人間による停止点、失敗点、終了条件を列挙します。
  2. 2

    ステップ 2: 最小限の状態集合を定義する

    pending、running、waiting_approval、retrying、compensating、succeeded、failed、cancelled など、最小限の state 集合を定義します。
  3. 3

    ステップ 3: イベントと次状態を結びつける

    各 state が受け取れる event と、その event 後に遷移する next state を明記します。
  4. 4

    ステップ 4: ガード条件を追加する

    危険な transition には、権限、予算、承認、幂等キー、外部リソース状態の guard を追加します。
  5. 5

    ステップ 5: ツール action を分離する

    ツール呼び出しを action 層に置き、input 要約、output 要約、traceId、副作用の結果を記録します。
  6. 6

    ステップ 6: 失敗ポリシーを定義する

    各失敗経路について retry policy、terminal state、compensation policy を定義します。
  7. 7

    ステップ 7: 復旧根拠を永続化する

    復旧のための checkpoint または event log を定義し、prompt は一時コンテキストとして扱い、唯一の真実の情報源にはしません。

FAQ

Agent が第 5 ステップで失敗したら、第 1 ステップから再実行すべきですか、それとも checkpoint から続行すべきですか?
副作用が幂等か、checkpoint が十分かによります。副作用がないタスクは最初から再実行できます。副作用があり幂等なら checkpoint から続行します。副作用が幂等でないなら、まず補償してから復旧します。checkpoint がなければ最初からやり直すしかなく、重複副作用のリスクを受け入れることになります。
タスク状態は prompt、データベース、LangGraph checkpoint、キュー job のどこに置くべきですか?
単純なタスクでは prompt を一時コンテキストとして使えます。複雑なタスクには checkpoint または event log と業務状態が必要です。本番 Agent では、thread state を LangGraph checkpoint に置き、注文、承認、権限、課金などの業務事実は業務データベースに置く設計がよく使われます。キュー job は非同期スケジューリングに向きますが、別途状態管理が必要です。
状態機械と workflow/フローチャートは何が違いますか?
状態機械は有限の到達可能状態、決定的な遷移、ガード条件、action を重視します。Workflow は実行ステップの並びを重視します。Agent には状態機械の中核概念が必要ですが、階層や並行性を含む完全な statechart が常に必要なわけではありません。
承認後、Agent が同じ実行点に戻ることをどう保証しますか?
同じ thread_id と checkpoint を使って復旧します。たとえば LangGraph Interrupts 文書にある Command(resume=...) のパターンです。checkpoint には現在ノード、完了済みステップ、次に行う action を記録し、interrupt 前の副作用は幂等にしておく必要があります。
retry と compensation は prompt に書くべきですか、それとも状態遷移ルールに書くべきですか?
Prompt ではなく、サーバー側の状態遷移ルールに書きます。retry_count、max retry、幂等キー、undo_op、terminal state は、テスト可能で、監査可能で、復旧可能であるべきです。Prompt は判断に参加できますが、信頼性ルールの唯一の置き場にはできません。
単純なカスタマーサポート Agent にも状態機械は必要ですか?
単発の FAQ bot なら重い状態機械は通常不要です。注文照会、チケット作成、返金承認、決済、外部 API を扱い始めた時点で、明示的な状態、checkpoint、幂等性、補償が必要になります。

10分で読めます · 公開日: 2026年9月17日

コメント

GitHubアカウントでログインしてコメントできます

Easton BlogEaston Blog