依存関係マップの作成
1つのAIワークフローは、出力を生成するまでに5〜6つの外部サービスを呼び出すことがある。LLM API、ベクターデータベース、CRMルックアップ、Webスクレイパー、サードパーティのエンリッチメントプロバイダー。それぞれに固有の稼働実績があり、100%のものは1つもない。
いずれかがダウンしたとき、デグラデーション計画のないシステムは完全に停止する。10分間の障害がパイプライン全体の停止につながる。キューが積み上がり、下流のステップがタイムアウトし、誰かがチケットを起票する。
解決策はベンダーからより良いSLAを得ることではない。最初から障害を前提に設計することだ。
依存関係マップの作成
グレースフルデグラデーションを実現するには、まず何に依存しているかを把握する必要がある。
ワークフローが行うすべての外部呼び出しをリストアップする。漏れなく列挙すること。以下を含める:
- LLM推論エンドポイント(OpenAI、Anthropic、セルフホスト)
- ベクターストアと検索レイヤー
- CRMの読み書き
- エンリッチメントAPI(LinkedInデータ、ファーモグラフィックプロバイダー)
- Webフェッチまたはスクレイピングサービス
- 別チームが所有する内部マイクロサービス
- 認証およびトークン検証エンドポイント
各依存サービスに対して、現実的な月次稼働率を割り当てる。ベンダーのマーケティング用SLAではなく、公開されているステータスページの履歴を使うこと。99.9%の稼働率を謳っていても、過去90日間に3件のインシデントがあったサービスは、実態として99.9%のサービスではない。
次に計算する。ワークフローが5つの依存サービスを必要とし、それぞれの稼働率が99.5%であれば、チェーン全体の複合可用性はおよそ97.5%になる。これは月間約18時間の潜在的なダウンタイムを意味する。過失ではなく、単純な算術の結果だ。
この演習は通常2つの反応を生む。1つ目は、外部呼び出しの多さへの驚き。2つ目は、どの依存サービスが最もリスクが高いかの明確化だ。
3つのデグラデーションモード
すべての障害が同じ対応を必要とするわけではない。3つのモードがある。どれを選ぶかは、ワークフローにおけるその依存サービスの役割による。
フルフォールバック(キャッシュ結果)
依存サービスが提供するデータの変化が緩やかで、わずかに古い回答がない回答よりも優れている場合に使用する。
例:企業規模と業種を返すファーモグラフィックエンリッチメント呼び出し。エンリッチメントAPIがダウンしている場合、タイムスタンプ付きで最後にキャッシュした結果を返す。48時間前の従業員数は、処理を継続するのにほぼ常に十分だ。
要件:定義されたTTLを持つキャッシュレイヤー、チームが合意した鮮度しきい値、そして結果がキャッシュから来たことを示す出力フラグ。
部分フォールバック(フラグ付き縮退出力)
依存サービスが出力品質に寄与するが、出力の存在自体には必須でない場合に使用する。
例:CRM履歴とライブWebデータの両方を使ってプロスペクトサマリーを生成するワークフロー。Webフェッチが失敗した場合、CRMデータのみからサマリーを生成する。下流のコンシューマーが低い信頼度で扱うべきと分かるよう、出力に enrichment_incomplete: true のマークを付ける。
これによりパイプラインは継続する。また明確な監査証跡も生まれる。依存サービスが回復したら、フラグ付きレコードを再処理できる。
グレースフルリジェクション(即時かつ明示的な失敗)
依存サービスが基幹的であり、部分的な結果が誤った結果よりも優れていない場合に使用する。
例:メッセージ送信前に実行しなければならないコンプライアンスチェック。コンプライアンスAPIに到達できない場合、メッセージを送信しない。推測もしない。ジョブを即座にリジェクトし、理由をログに記録し、バックオフスケジュール付きのリトライキューにルーティングする。
キーワードは高速だ。30秒後にタイムアウトするグレースフルリジェクションはグレースフルではない。積極的なタイムアウトを設定する。ほとんどのAPI呼び出しで2〜5秒。早期にリジェクトすること。これにより、パイプラインの残りの部分をカスケード遅延から保護できる。
セパレーションパターン
最も一般的な実装ミスは、フォールバックロジックをメインのワークフロー関数に直接埋め込むことだ。エラーをチェックし、キャッシュを試み、再チェックし、最終的に何かを返す長い条件分岐ブロックになる。2人のエンジニアが触れた後、誰も実際に何をしているか自信を持てなくなる。
セパレーションパターン:各依存サービスを生の呼び出しではなく、ラップされたクライアントとして扱う。
ラッパーは3つのことを担う:
- ライブ呼び出し
- その特定の依存サービスに対するフォールバック動作
- ログとフラグのコントラクト
メインのワークフローロジックはラッパーを呼び出し、結果または構造化された失敗オブジェクトを受け取る。結果がライブデータから来たのかキャッシュから来たのかを知らない。リトライロジックを含まない。受け取ったものを処理するだけだ。
これによりデグラデーションコードが分離され、テスト可能になる。各ラッパーのフォールバックを独立してユニットテストできる。ワークフローロジックに触れずにキャッシュ戦略を交換できる。新しい依存サービスが追加されたとき、パターンはすでに確立されている。
副次的なメリット:インシデント発生時、ラッパーのログがどの依存サービスがいつ失敗し、どのフォールバックモードが起動したかを正確に教えてくれる。本番障害のデバッグが数時間ではなく数分で済む。
実際の運用での見え方
1時間に200件のプロスペクトレコードを処理するワークフローは、依存サービスの障害に定期的に遭遇する。たまにではなく、定常的に。現実的な稼働率の数値では、適度に複雑なパイプラインで1日に少なくとも1件の部分障害イベントが発生すると見込むべきだ。
デグラデーションモードを備えて構築されたシステムは、人間の介入なしにこれらのイベントを処理する。パイプラインは継続する。フラグ付きレコードは依存サービスが回復したときに再処理される。オペレーターはサポートチケットではなく、ダッシュボードのメトリクスを見る。
デグラデーションモードのないシステムは停止し、アラートを発し、誰かが再起動するのを待つ。
違いはエンジニアリングの英雄的行為ではない。依存関係マップ、3つの定義されたモード、そして一貫して適用されるセパレーションパターンだ。
AIパイプラインを構築または監査していて、特定のワークフローの依存関係マップを一緒に検討したい場合は、会話を始める →