実世界の入力に耐えるエージェントワークフロー

ほとんどのエージェントデモが機能するのは、デモ入力がクリーンだからです。実際の入力はそうではありません。未完成の形で到着し、欠落したフィールド、矛盾したコンテキスト、実際には画像であるPDF、そしてスレッドの途中で気が変わるユーザーが含まれます。デモが機能するものと、6ヶ月間無人で稼働するワークフローの間のギャップは、ほぼ完全に問題の分解方法とガードレールの配置方法にあります。

私はBizFlowAIで日常的にマルチエージェントワークフローを設計しており、以下のパターンは私が繰り返し使用しているものです。派手なものではありません。これが私のコンテンツパイプラインが私を監視せずに24/7稼働する理由であり、私のサーバーレスAWS統合がSLAを達成し、午前2時に私にページングしない理由です。

まずワークフローを決定論的パイプラインとして記述し、その後エージェントが価値を発揮する場所を決定する

LLM SDKに触れる前に、私はエージェントが存在しないかのようにワークフローを記述します。型付きの入出力を持つ退屈な関数のシーケンスです。これはエージェント設計において最も有用な演習であり、ほとんどのチームがスキップするものです。

以下は私がすべての新しいワークフローで実行する分解です:

  1. トリガーは何ですか? Webhook、cron、キューメッセージ、ファイルをアップロードする人間。ペイロードの正確な形状を記述します。
  2. 最終成果物は何ですか? JSONオブジェクト、公開された投稿、Zendeskチケットの更新、データベース行。スキーマを正確に記述します。
  3. 中間成果物は何ですか? トリガーと最終成果物の間に存在する必要があるすべてのオブジェクトをリストします。各オブジェクトに名前とスキーマを付けます。
  4. 各成果物間の遷移について、判断が必要か、ルールかを問いかけます。 ルールはコードに、判断はLLMに委ねます。これが全体のヒューリスティックです。

私のContentStudioパイプラインでは、フローは次のようになります:

trigger (topic gap detected)
  -> ResearchBrief        [LLM: judgment on angle + gap]
  -> OutlineDraft         [LLM: judgment on structure]
  -> DraftPost            [LLM: generation]
  -> SEOAuditReport       [code: deterministic checks]
  -> RevisedPost          [LLM: targeted rewrites only]
  -> PublishPayload       [code: schema validation]
  -> published (WordPress API)

Enter fullscreen mode Exit fullscreen mode

4つのステップがコード、3つがLLMであることに注意してください。以前のバージョンでは、LLMがSEO監査と公開ペイロードのアセンブリを行っていました。スラッグを幻覚し、標準URLを発明し、一度存在しないサイトに公開しようとしたことがあります。それらを決定論的コードに移動することで、エラー率をほぼゼロに削減し、パイプライン全体をデバッグ可能にしました。

私が従うルール:エージェントは決定に責任を持つべきであり、決定の周りの配管には責任を持つべきではありません。

ツールは購入ではなく採用のように選ぶ

ツールの選択は、ほとんどのエージェントプロジェクトが静かに失敗する場所です。チームは「ツールが多い=能力が高い」からエージェントに15個のツールを与え、その後30%の確率で間違ったツールを選ぶ理由を不思議がります。

実際の本番エージェントからの私の作業数値:

利用可能なツール 正しいツール選択率
3-5ツール、厳密にスコープされた 96-99%
6-10ツール 88-93%
11-20ツール 70-82%
20+ツール 70%以下であることが多く、プロンプトに大きく依存

これらは私のパイプラインからの方向性のある数値であり、ベンチマークではありません。しかし、パターンは実在し、モデルファミリー全体で成立します。緩和策はよりスマートなモデルではありません。ツールルーティングです:サブエージェントを選択する小さなディスパッチャーエージェントで、各サブエージェントは3-5個のツールを持ちます。

ツール仕様を書く際、私はそれを職務記述書のように扱います:

  • 名前:動詞から始まり、曖昧さのないもの。search_customer_by_emailであって、customer_lookupではありません。
  • 説明:何をするかの1文、使用しない場合の1文。「使用しない場合」の行が自信過剰な誤った呼び出しを防ぎます。
  • 入力スキーマ:厳密な型、必須フィールドのマーク。文字列として隠れているオプション付きのデフォルトフィールドはありません。
  • 出力スキーマ:毎回同じ形状、エラー形状を含む。エージェントに自由形式のエラー文字列を解析させません。

「使用しない場合」の文を書けない場合、ツールは広すぎます。分割してください。

ガードレールはプロンプト内ではなく境界に属する

プロンプトレベルのガードレール(「顧客名をでっち上げない」、「常にメールを検証する」)はせいぜい参考程度です。本番ではバックアップとして扱い、主要な防御策とはしません。主要な防御策は各ステップの境界にあります。

常にガードレールを配置する4つの境界タイプがあります:

1. ツール呼び出しの入力検証。 すべてのツールは、何かをする前に厳密なスキーマ(TypeScriptではZod、PythonではPydanticを使用)で入力を検証します。エージェントがフィールドを幻覚した場合、ツールは構造化されたエラーを返し、エージェントはフィードバックを受けて再試行できます。例外なく、サイレントな強制はありません。

2. LLMレスポンスの出力検証。 構造化された出力を生成するすべてのLLM呼び出しはバリデーターを通過します。構造化された出力が必要な場合は、プロバイダーの構造化出力モード(Claudeツール使用、OpenAI response_format)を使用し、その後再検証します。ベルトとサスペンダー。この方法でモデルの回帰を捉えています。

3. コストとループの上限。 すべてのワークフローにはハード予算があります:最大トークン数、最大ツール呼び出し数、最大ウォールクロック時間。これらのいずれかを超えると、大声で失敗し、デッドレターキューに書き込み、私にページングします。40分間サイレントにループし、$80を費やすエージェントは、請求書でのみ見つかるバグです。

4. 副作用ゲート。 実世界に書き込むツール(メール送信、投稿公開、チケット作成、カード課金)は、LLMプロンプトの一部ではない別個の認可チェックを持ちます。設定またはフィーチャーフラグから読み取ります。これがエージェントに書き込みアクセスを与える際に夜眠れる理由です。

以下は私が使用する最小限の副作用ゲートパターンです:

async function publishPost(input: PublishInput, ctx: AgentContext) {
  // 1. Schema validation
  const parsed = PublishSchema.parse(input);

  // 2. Authorization check (NOT in prompt)
  if (!ctx.permissions.canPublishTo(parsed.siteId)) {
    return { ok: false, error: "unauthorized_site" };
  }

  // 3. Idempotency: has this artifact already been published?
  const existing = await db.publishedPosts.findOne({
    contentHash: parsed.contentHash
  });
  if (existing) {
    return { ok: true, alreadyPublished: existing.url };
  }

  // 4. Actual side effect, wrapped in retry with backoff
  const result = await wpClient.publish(parsed);
  await db.publishedPosts.insert({ ...parsed, url: result.url });
  return { ok: true, url: result.url };
}

Enter fullscreen mode Exit fullscreen mode

WordPress APIに到達する前に4つのことが起こります。そのすべてが本番で実際のバグを捉えています。

可観測性は「動作する」と「動作することを証明できる」の違いです

事前に計装しなければ、後からログを読んでエージェントワークフローをデバッグすることはできません。そして実際の入力は予測しなかったことをするので、デバッグする必要があります。

すべてのワークフローで提供する最小限のもの:

  • ワークフロー実行ごとのトレースID、すべてのツール呼び出し、LLM呼び出し、DB書き込みを通じて伝播。一つのIDでgrepできます。
  • 構造化ログ、print文ではありません。trace_id、step_name、duration_ms、token_in、token_out、cost_estimate、outcomeを含むJSON。
  • すべてのLLM呼び出しの永続化:プロンプト、レスポンス、モデル、温度、トークン、レイテンシ。ストレージは安価ですが、悪い実行を再現できないことは高価です。
  • すべてのツール呼び出しの永続化:入力、出力、期間、エラー。
  • ワークフローごとの実行サマリーレコード:トリガー、最終ステータス、総コスト、総時間、生成された成果物。

これにはシンプルなPostgresスキーマを使用します。派手だからではなく、何か問題が発生したときにSQLを書けるからです。実行が失敗したとき、一つのクエリで全履歴を取得し、リプレイできます。

実際に監視している指標、すべてのワークフローで:

シグナル なぜ重要か
ワークフローバージョンごとの成功率 プロンプト変更後の回帰
ステップごとのp50 / p95レイテンシ どのステップがボトルネックか
実行ごとのコスト(トークン + ツール) 単位経済、予算アラート
ツールごとのツール呼び出しエラー率 どのツール仕様がエージェントを混乱させているか
ステップごとの再試行率 サイレントな不安定さ
人間介入率 自律性の正直な尺度

最後のものは誰も見たくないものです。ワークフローが15%の時間人間を必要とする場合、それは自律的ではなく、支援型です。構いませんが、そう呼んでROIをそれに応じて価格設定してください。

既に見たことのある障害モードのために設計する

これらを十分に構築した後、障害モードは韻を踏みます。最初からそれらに対抗して設計します。

自信過剰な誤った出力。 エージェントは妥当だが間違ったものを生成します。緩和策:出力をグラウンドトゥルース(DBルックアップ、ルールチェック、高リスク出力のためのセカンドモデル批評)と照合する検証ステップ。私のコンテンツパイプラインでは、すべてのドラフトが公開前に決定論的なSEO/AEO監査を通過します。失敗した場合、特定の失敗がリストされたターゲット修正エージェントに戻されます。

サイレントなツール障害。 ツールは空のボディで200を返すか、問題なさそうに見える部分的な成功を返します。緩和策:ツールは明示的な{ ok: boolean, ... }形状を返し、エージェントのツール使用ループはok: falseを第一級ケースとして扱い、解釈する文字列としては扱いません。

暴走ループ。 エージェントはわずかに異なる入力で同じツールを呼び続けます。緩和策:ループ内の最近のツール呼び出しを追跡し、同じツール+入力ハッシュが繰り返されたときにシステムメッセージを注入します。また:前述のウォールクロック上限。

コンテキスト腐敗。 エージェントが以前の決定を忘れたり矛盾したりする長い会話。緩和策:1つの長い会話を走らせません。ワークフローを新鮮なコンテキストウィンドウを持つステップに分割し、各ステップが必要とする成果物のみを前方に渡します。これはマルチステップエージェント設計における最大の信頼性向上です。

モデルドリフト。 ベンダーがモデルを更新し、プロンプトが微妙に破損します。緩和策:コードでモデルバージョンを固定し、すべてのデプロイで小さな評価セットを実行します。20の代表的なケースでもほとんどの回帰を捉えられます。

明日新しいエージェントワークフローを開始する場合の私のやり方

順序が重要です。これが実際に私がすることです:

  1. LLM呼び出しなしで、プレーンなパイプラインとしてワークフローを記述します。スキーマを正しくします。
  2. 本当に判断が必要な2-4ステップを特定します。それ以外はすべてコードのままにします。
  3. 職務記述書のようにツール仕様を書きます。エージェントごとに5つ以上ある場合は、ルーターを持つサブエージェントに分割します。
  4. すべてのツールとすべての構造化LLM呼び出しに厳密な入出力検証を追加します。
  5. 書き込むものに接続する前に、コスト上限、ループ上限、副作用ゲートを追加します。
  6. トレースIDで各呼び出しを計装し、完全な履歴を永続化します。
  7. 出荷前に20-50の実際の入力(合成ではない)の評価セットを構築します。
  8. フィーチャーフラグの背後にデプロイします。1週間本番トラフィックに対してシャドーモードで実行します。
  9. 人間介入率を監視します。最初に率が最も高いステップで反復します。
  10. その後初めて、スコープを拡大します。

ステップ1-6は総構築時間の約60%を占め、インシデントの約90%を防ぎます。それらをスキップすることは、2週目にクラッシュするデモに至る方法です。

繰り返し見るトレンドの間違い:チームはパイプラインを退屈な関数として記述する前にフレームワーク(LangGraph、CrewAI、今四半期流行のもの)を選びます。フレームワークがそれを機能させるのではありません。分解です。

実本番入力に対して実行する必要があるエージェントワークフローを構築していて、分解やガードレールについて第二の目が必要な場合は、今四半期にいくつかのコンサルティング契約をお受けします。lazar-milicevic.com/#contactまでご連絡いただくか、RAG評価、エージェントコンテキスト、ユーザーの接触に耐えるエージェントの出荷に関する関連記事についてはブログをご覧ください。