powered by TechFeed
表示モード
Deep Dive

「プロンプトで何とかする」時代の終わり — 長時間稼働AIエージェントをLLMに頼らず決定論的に設計する方法

8月31日、n8n blogが「Long-running agents beyond prompt engineering」と題した記事を公開した。プロンプトエンジニアリングに頼りすぎたエージェント設計を脱し、長時間稼働するAIエージェントを堅牢に設計するための実践的手法を詳述した内容だ。なかでも耐久実行(Durable Execution)のパートは、障害後の復旧をLLMに「読んで判断させる」のではなく、イベントソーシングで決定論的に実装するという、既存のエージェント設計の盲点を突く内容であり、実務への影響が大きい。

8月31日、n8n blogが「Long-running agents beyond prompt engineering」と題した記事を公開した。プロンプトエンジニアリングに頼りすぎたエージェント設計を脱し、長時間稼働するAIエージェントを堅牢に設計するための実践的手法を詳述した内容だ。なかでも耐久実行(Durable Execution)のパートは、障害後の復旧をLLMに「読んで判断させる」のではなく、イベントソーシングで決定論的に実装するという、既存のエージェント設計の盲点を突く内容であり、実務への影響が大きい。


「プロンプトで何とかする」の限界

記事の冒頭はかなり直接的だ。「エージェント設計をプロンプトで乗り切ろうとしすぎている。コンテキストエンジニアリングと呼ぼうがループエンジニアリングと呼ぼうが、LLMに自分自身を評価させているのは変わらない」。

LLMに自己評価や分析をさせればさせるほど、ハルシネーションとドリフト(脈絡のズレ)の発生点が増える。この記事が主張するのは、LLMは「ツールとして呼び出される部品」であり、エージェントの制御ロジックは開発者が決定論的に設計すべき、という原則だ。

記事は3つのパートに分かれている。


Part 1: コンテキストとメモリの管理

「会話」はUIの幻想に過ぎない

LLMはステートレスだ。チャットのような体験はあくまでUI上の演出であり、毎回のプロンプト送信時には会話履歴の全体が送られている。長時間のセッションではコンテキストウィンドウが枯渇し、モデルが履歴を切り捨て始める。これがコンテキストロット(context rot=コンテキストの腐敗・劣化)とドリフト(モデルが本来のタスクからズレていく現象)の原因だ。

コンテキストの圧縮・保存・再利用

記事では、コンテキストのライフサイクルを「作成→圧縮→保存→想起」の4段階で整理している。

  • 圧縮: GoogleのADK Context Compactionは、古いイベント履歴をスライディングウィンドウで要約する。ただし「常に要約し続ければいい」は誤りで、ある時点でハーネス(エージェントを動かすフレームワーク側)がフルリセットを行い、永続ストレージから再構築する必要がある。
  • 保存: LLMはステートレスなので、コンテキストを永続ストレージに書き出す必要がある。記事が強調するのは、書き込み専用の追記型台帳(immutable ledger)として設計することだ。「LLMに『台帳を更新しないでください』と頼む」のはソフトウェアエンジニアリングではない、と断言している。
  • 想起: 新しいセッション開始時、エージェントは台帳から計画・進捗・完了済み作業を読み込み、「自分は今どこにいるか」を再構築できる。会話履歴を丸ごと再生する必要はない。

GoogleのAgent Memory Bankでは、記憶の抽出・統合・生成・検索が一体化して管理される。元記事では各機能の詳細な対応関係が図示されているため、正確な実装イメージは元記事の該当セクションを参照されたい(※編集部の考察:紹介記事内での再現には限界があるため、図表を含む原文との照合を推奨する)。特徴的なのはTTL(有効期限)による自動失効リビジョン履歴の自動保持だ。


Part 2: 耐久実行(Durable Execution)

「Claudeよ、これを読んで続きをやって」はダメ

永続ストレージができたからといって、障害後の復旧をLLMに「読んで判断させる」形にしてはいけない。記事はここでも決定論的な復旧を求める。

長時間稼働エージェントの本質は「長時間動き続けること」ではなく、必要なときだけ起動し、タスク・コンテキスト・履歴を追跡し続けることだ。エージェントは大半の時間を「待機」に費やす。

何を永続化すべきか

Cloudflareの事例を引用しつつ、記事は以下を整理している。

永続化が必要なもの:

  • エージェントの状態(セッション継続に必要なデータ)
  • SQLiteテーブル(スケジュールタスクを含む)
  • WebSocket接続状態

永続化不要なもの:

  • インメモリ変数
  • 実行中タイマー
  • オープン中のHTTPコール

エージェントは常時起動している必要はなく、イベントで起床→処理→スリープのサイクルで動く。起床トリガーはWebhookコールバックや、バックオフ付きポーリングで実装できる。

ジャーナルベースの復旧

記事が推奨するのは**イベントソーシング(event-sourcing)**パターンだ。

  • タスク台帳(immutable): 何をすべきか、順序は何か
  • 実行ログ(append-only): 実際に何が起きたか(ツール呼び出し、モデルレスポンス、状態遷移)

実行ログは決定論的に再生できるため、どのプロセスやコンテナが処理を引き継いでも状態を再構築できる。RestateDBOSはこの仕組みを実装したツールの例として紹介されている。Restateは各ステップをクラッシュ前の状態に決定論的に再現し、DBOSはPostgresにチェックポイントを書き込む。


Part 3: タスク進捗の評価

LLM-as-judgeへの警告

エージェントがタスクを脱線し始めたとき、多くのエンジニアが取る解決策は「別のLLMに評価させる」だ。記事はこれを最も手軽で最も信頼性の低い方法と位置付ける。同じクラスのモデルが同種のエラーを、一段階遠ざけて犯しているだけだ。

チェックリストと決定論的バリデーション

記事が推奨するのは、タスク実行前に完了条件を定義することだ。エージェントが実行中に「完了」の定義を書き換えることを防ぐ、最も効果的な手段だとしている。また、1回のパスで1エントリのみを処理することで、検証の対象が「その1回のパスでの状態遷移1つ」に絞られ、検証が現実的になる。

LLMを評価に使う場合も、「Yes/Noで答えられる狭い問い」に限定し、その出力を構造化して検証する、という使い方を推奨している。


設計原則の一貫性

この記事を貫く原則は「エージェントを普通のソフトウェアとして設計せよ」だ。コンテキスト管理、耐障害性、進捗評価のいずれにおいても、LLMに判断を委ねるポイントを最小化し、決定論的な制御をハーネス側で持つことを一貫して求めている。とりわけPart 2の耐久実行パートは、イベントソーシングというソフトウェアエンジニアリングの既存知見をエージェント設計に接続した点で、プロンプト改善の議論とは一線を画す内容だ。n8nでも同様のパターンをワークフローエンジンの機能(リトライ、スケジュール、Webhook)で実装できると紹介されている。

詳細はLong-running agents beyond prompt engineeringを参照していただきたい。