メインコンテンツへスキップ
友田 陽大
本番LLMアプリ実装(信頼できるAI)
生成AI
LLM
信頼性
回復性
冪等性
AIエージェント
TypeScript
SRE
アーキテクチャ設計
コスト最適化

本番LLMアプリの信頼性・回復性設計 2026|多プロバイダ・フォールバック・リトライ・サーキットブレーカ・冪等性

生成AI/LLMアプリを本番で落とさないための信頼性・回復性の設計ガイド。タイムアウト、指数バックオフ+ジッター付きリトライ(一時障害のみ)、サーキットブレーカ、多プロバイダ・フォールバック(AI SDK / Vercel AI Gateway)、冪等性、レート制限まで、一次情報準拠のTypeScript実コードで解説します。

公開日
読了時間
10分
著者
友田 陽大
シェア

「開発中は完璧だったのに、本番でトラフィックが乗った瞬間に落ちた」——LLMアプリで頻発する事故です。理由はシンプルで、LLMアプリは、非決定的な外部APIに依存する分散システムだからです。プロバイダ側の一時障害、レート制限(429)、レイテンシスパイク、そしてコスト暴走。これらは「起きるか」ではなく「いつ起きるか」の問題です。

結論から言えば、本番LLMアプリの回復性(resilience)は、モデルではなくアーキテクチャで作ります。柱は6つ。

  1. タイムアウト — 返らない呼び出しで止まらない。
  2. リトライ(一時障害のみ・指数バックオフ+ジッター) — 一過性の失敗を吸収する。
  3. サーキットブレーカ — 落ちているプロバイダへの攻撃を止め、カスケード障害を防ぐ。
  4. 多プロバイダ・フォールバック — 1社の障害でサービスを止めない。
  5. 冪等性 — リトライや二重呼び出しで副作用を二重に起こさない。
  6. レート制限・コスト上限 — 濫用と暴走を封じる。

この記事は、決済基盤で本番二重課金0件を実現してきた信頼性・冪等性の設計の知見を、生成AIに持ち込みます。AI SDK / Vercel AI Gateway の現行APIと、AWS・Google SRE の一次情報に準拠し、実コードで示します。これは、セキュリティMCP評価プライバシーに続く「信頼できる本番AI」の第5の柱です。

LLM呼び出しは「失敗する前提」で設計する

まず、どんな失敗が起きるかを分類します。対応が変わるからです。

失敗対応
一時障害429(レート制限)、500/502/503/504、接続断、タイムアウトリトライ(バックオフ+ジッター)→ ダメならフォールバック
恒久エラー400(不正)、401/403(認可)、422リトライしない(成功しない・コストの無駄)
部分的劣化応答は返るが遅い/品質が低いタイムアウト評価で検知

HTTPの意味論は明確です。429(Too Many Requests)は RFC 6585Retry-After ヘッダと 503 は RFC 9110 が定義します。Retry-Afterが返ってきたら、独自のバックオフよりそれを優先します。

タイムアウトとリトライ:一時障害だけを、ジッター付きで

リトライの鉄則は2つ。「一時障害だけ」「冪等な呼び出しだけ」。Google SREも「恒久エラーや不正なリクエストはリトライしない——決して成功しないから」と述べています。

そしてジッター(ゆらぎ)。全クライアントが同じ間隔で再試行すると、再試行の山が同期して群集雪崩(thundering herd)を起こし、復旧しかけたプロバイダを再び潰します。AWSの推奨は、指数バックオフにフルジッター(0〜backoffの一様乱数)を加えて山を平準化することです。

まず良い知らせ:Vercel AI SDK は一時障害を既定でリトライしますmaxRetries、既定=2)。多くのケースはこれで足ります。

import { generateText } from "ai";

// AI SDK は一時障害を既定で2回リトライ(maxRetries=2)。timeout は AbortSignal で。
// Vercel AI Gateway なら「モデル・フォールバック」を宣言的に書ける:
// primary が失敗したら順にバックアップを試し、最初に成功した応答を返す。
const { text } = await generateText({
  model: "anthropic/claude-opus-4-8",
  prompt,
  maxRetries: 2,                              // 既定値。多層でリトライを重ねない
  abortSignal: AbortSignal.timeout(15_000),   // 15秒で打ち切り
  providerOptions: {
    gateway: {
      models: ["anthropic/claude-opus-4-8", "openai/gpt-5"], // 順にフォールバック
    },
  },
});

自前でリトライを制御したい場合(ゲートウェイを使わない、独自のバックオフが要る)は、一時障害だけを、指数バックオフ+フルジッターで再試行します。

// 自前リトライ:一時障害(429/5xx/timeout)だけを、指数バックオフ+フルジッターで。
const RETRYABLE = new Set([429, 500, 502, 503, 504]);

async function withRetry<T>(fn: () => Promise<T>, retries = 2, baseMs = 500): Promise<T> {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err) {
      const status = (err as { statusCode?: number }).statusCode;
      // 恒久エラー(4xx)はリトライしない。上限に達したら諦める(無限リトライ=コスト暴走)。
      if (attempt >= retries || status === undefined || !RETRYABLE.has(status)) throw err;
      const backoff = Math.min(baseMs * 2 ** attempt, 20_000);
      const wait = retryAfterMs(err) ?? Math.random() * backoff; // Retry-After優先、無ければfull jitter
      await new Promise((resolve) => setTimeout(resolve, wait));
    }
  }
}

サーキットブレーカ:落ちた相手を叩き続けない

一時障害が続くとき、リトライは逆効果になります。落ちているプロバイダを叩き続ければ、カスケード障害とコスト浪費を招くだけ。そこでサーキットブレーカ——連続失敗が閾値を超えたら回路を open(即失敗)にし、cooldown後に half-open で1回だけ試して復旧を確認します(Martin Fowler)。

テスト容易性のため、時刻を引数で注入します(Date.now()に依存させない=決定的に単体テストできる)。

// サーキットブレーカ:連続失敗が閾値超で一定時間 open(即失敗)。
// now を注入してテスト可能に(closed → open → half-open)。
class CircuitBreaker {
  private failures = 0;
  private openedAt: number | null = null;
  constructor(
    private readonly threshold = 5,
    private readonly cooldownMs = 30_000,
  ) {}

  allow(now: number): boolean {
    if (this.openedAt === null) return true;                 // closed:通常通り
    if (now - this.openedAt >= this.cooldownMs) return true; // half-open:試行を1回許可
    return false;                                            // open:即失敗(叩かない)
  }
  onSuccess(): void {
    this.failures = 0;
    this.openedAt = null;
  }
  onFailure(now: number): void {
    if (++this.failures >= this.threshold) this.openedAt = now;
  }
}

多プロバイダ・フォールバック:1社の障害で止めない

回復性の本丸です。primaryプロバイダが落ちたら、secondaryに切り替える。Vercel AI Gateway なら前述の providerOptions.gateway.models(モデル順)や order(プロバイダ順)で宣言的に書けます。自前で管理するなら、サーキットブレーカとリトライを組み合わせたフォールバック連鎖にします。

// 多プロバイダ・フォールバック:primary が落ちたら次へ。open 中のプロバイダはスキップ。
const CHAIN = ["anthropic/claude-opus-4-8", "openai/gpt-5"] as const;
const breakers = new Map(CHAIN.map((model) => [model, new CircuitBreaker()]));

async function generateResilient(prompt: string, now: () => number): Promise<string> {
  let lastErr: unknown;
  for (const model of CHAIN) {
    const breaker = breakers.get(model)!;
    if (!breaker.allow(now())) continue; // サーキットが open ならこのプロバイダは飛ばす
    try {
      // withRetry が再試行を担うので、SDK側は maxRetries:0(多層リトライを避ける)
      const { text } = await withRetry(() =>
        generateText({ model, prompt, maxRetries: 0, abortSignal: AbortSignal.timeout(15_000) }),
      );
      breaker.onSuccess();
      return text;
    } catch (err) {
      lastErr = err;
      breaker.onFailure(now());
    }
  }
  throw new Error(`all providers failed: ${String(lastErr)}`);
}

注意点は品質の一貫性です。フォールバック先はモデルが変わるため、出力の質・形式がぶれます。切替時も品質を保つには、structured output の信頼性設計でスキーマ検証し、評価(eval)で継続的に品質を測ります。

retry amplification に注意。 SDK・自前リトライ・ゲートウェイ・上流サービス——各層がリトライを持つと、再試行回数が掛け算になり、障害時に負荷を爆発させます。Google SREの原則は明快で、「リクエストあたりのリトライを制限する」。リトライは1つの層に集約し、他は0にします。

冪等性:リトライで副作用を二重に起こさない

リトライとフォールバックは、副作用のある操作では諸刃の剣です。1回目が実は成功していた(応答だけ失われた)場合、リトライは二重実行になります。LLMエージェントは同じ意図でツールを複数回呼ぶこともあり、リスクはさらに高い。

対策は冪等キー。同じキーの操作は1回だけ実行されることを、下流で保証します(MCPのツール実行設計や決済基盤と同じ)。

// 副作用のある操作は冪等キーで保護。リトライ/二重呼び出しでも一度きり。
async function chargeIdempotent(orderId: string, amountJpy: number): Promise<Receipt> {
  const key = `charge:${orderId}:${amountJpy}`; // 意図が同じなら同じキー
  const existing = await receipts.get(key);
  if (existing) return existing;                // 既に処理済みなら再実行しない
  const receipt = await paymentApi.charge(orderId, amountJpy, { idempotencyKey: key });
  await receipts.put(key, receipt);
  return receipt;
}

レート制限とコスト回復性

信頼性はコストの問題でもあります。リトライやループが暴走すれば、可用性ではなく請求書が壊れます。対策はセキュリティ記事のOWASP LLM10「Unbounded Consumption」と同じ——出力トークン上限(maxOutputTokens)、per-userレート制限、タイムアウト、そしてリトライ回数の上限。Google SREの「過負荷時は劣化した応答を返す(load shedding / graceful degradation)」も有効な選択肢です。

可観測性で回復性を運用する

これらの仕組みは、測って初めて機能します。失敗率・フォールバック率・サーキットのopen時間・p95レイテンシ・リトライ回数・コストを記録し、異常を検知します。「フォールバックが常時発火している=primaryが慢性的に不調」のように、指標が設計の穴を教えてくれます。土台は OpenTelemetryによる本番可観測性 を参照してください。

導入チェックリスト(本番投入前)

  • タイムアウト — すべてのLLM呼び出しに abortSignalAbortSignal.timeout)を設定したか。
  • リトライ範囲 — 429/5xx/タイムアウトの一時障害だけ、かつ冪等な呼び出しだけをリトライしているか。
  • バックオフ+ジッター — 指数バックオフにフルジッター、Retry-After優先になっているか。
  • retry amplification — リトライを1層に集約し、多層で重ねていないか(上限も設定)。
  • サーキットブレーカ — 連続失敗で落ちたプロバイダを一時遮断しているか。
  • 多プロバイダ・フォールバック — 1社障害で止まらないか。フォールバック時の品質を評価で担保しているか。
  • 冪等性 — 副作用のある操作を冪等キーで保護し、二重実行を防いでいるか。
  • コスト回復性 — トークン上限・レート制限・リトライ上限で暴走を封じているか。
  • 可観測性 — 失敗率・フォールバック率・レイテンシ・コストを監視し、劣化を検知できるか。

まとめ

本番LLMアプリの信頼性は、特別な魔法ではなく、分散システムの回復性設計をLLMに適用することです。「LLMは失敗する外部依存」と割り切り、タイムアウト・(一時障害限定の)リトライ・サーキットブレーカ・多プロバイダ・フォールバック・冪等性で被害を封じ込める

  • リトライは一時障害だけ・冪等だけ・ジッター付き。 多層で重ねない(retry amplification)。
  • サーキットブレーカで落ちた相手を叩かない。 多プロバイダ・フォールバックで1社障害に耐える。
  • 冪等キーで二重実行を防ぎ、レート制限とコスト上限で暴走を封じる。

セキュリティ・MCP・評価・プライバシー・信頼性——この5本柱が揃って、生成AIは「速く作れて、安全で、壊れず、信頼でき、そして止まらない」本番システムになります。作る速さと、止めない堅さは、正しく設計すれば両立します。

よくある質問

LLM呼び出しは何をリトライすべきですか?
一時障害だけです。429(レート制限)・5xx(一時的なサーバー障害)・タイムアウトに限り、かつ冪等な呼び出しに限ります。400/401/403のような恒久的エラーはリトライしても成功せず、コストとレイテンシを増やすだけです(Google SRE『恒久エラーや不正なリクエストはリトライしない』)。
リトライにジッター(ゆらぎ)は必要ですか?
必要です。全クライアントが同じ間隔で再試行すると『群集雪崩(thundering herd)』でプロバイダをさらに圧迫します。指数バックオフにフルジッター(0〜backoffの乱数)を加えて、再試行の山を平準化するのがAWSの推奨です。Retry-Afterヘッダがあればそれを優先します。
AI SDKを使うなら自前のリトライは要りますか?
AI SDKは既定で maxRetries=2 として一時障害を自動リトライします。自前で必要なのは、それを超える制御(多プロバイダ・フォールバック、サーキットブレーカ、独自のバックオフ)です。フォールバックは Vercel AI Gateway の providerOptions.gateway.models で宣言的にも書けます。重要なのは多層でリトライを重ねないこと(retry amplification でリトライ回数が掛け算になり、障害を増幅します)。
多プロバイダ・フォールバックの注意点は?
フォールバック先で出力の品質・形式が変わることです。切替時も品質を保つため、構造化出力(スキーマ検証)とプロンプト設計でモデル差を吸収し、評価(eval)で継続的に品質を担保します。
サーキットブレーカは何のためですか?
落ちているプロバイダを叩き続けてカスケード障害やコスト浪費を起こさないためです。連続失敗が閾値を超えたら一定時間 open(即失敗)にし、cooldown後に half-open で1回だけ試して復旧を確認します(Martin Fowler の Circuit Breaker)。
LLMアプリでも冪等性は必要ですか?
必要です。LLMは同じ意図でツールを複数回呼ぶことがあり、リトライも二重実行を招きます。副作用のある操作(返金・送信・発注)は冪等キーで保護し、二重課金・二重発送を構造的に防ぎます。決済基盤で本番二重課金0件を保つ設計と同じ発想です。

参考文献

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事の実装を、案件として承ります

セキュリティエンジニアリングを、設計から実装・運用まで承ります

脅威モデリングによる設計レビュー、暗号・認証認可の正しい実装、ログ設計と検知(検知エンジニアリング)、インシデント対応の体制づくりまで。一人 × 生成AIで経済産業大臣賞のB2B SaaSや本番二重課金0件の決済基盤を作ってきた知見で、御社のプロダクトを“速く作り、かつ守れる”状態に伴走します。設計でしか守れない縦のリスクは監査としても承ります。

プロジェクト単位(請負)・技術顧問のどちらにも対応可能です。まずは30分の無料技術相談から。

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

あわせて読みたい