Chuyển đến nội dung chính
友田 陽大
本番LLMアプリ実装(信頼できるAI)
生成AI
LLM
信頼性
回復性
冪等性
AIエージェント
TypeScript
SRE
アーキテクチャ設計
コスト最適化

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

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

Published
Reading time
10 min read
Author
友田 陽大
Chia sẻ

「開発中は完璧だったのに、本番でトラフィックが乗った瞬間に落ちた」——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は「速く作れて、安全で、壊れず、信頼でき、そして止まらない」本番システムになります。作る速さと、止めない堅さは、正しく設計すれば両立します。

Câu hỏi thường gặp

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件を保つ設計と同じ発想です。

Tài liệu tham khảo

友田

友田 陽大

Người phát triển sản phẩm đoạt Giải thưởng Bộ trưởng (METI). Với TypeScript + Python + AWS, tôi một mình triển khai trọn gói SaaS, chuyển đổi số công nghiệp và AI tạo sinh (RAG) sẵn sàng cho production — từ phân tích yêu cầu đến hạ tầng và vận hành.

I can take on the implementation from this article as an engagement

Security engineering, from design to implementation and operations

Design reviews via threat modeling, correct implementation of crypto and authn/authz, log design and detection (detection engineering), and building an incident-response capability. With experience building — solo × generative AI — a METI Minister's Award B2B SaaS and a payments platform with zero double charges in production, I help get your product to a state where it ships fast and can be defended. Vertical risks that only design can address, I also take on as an audit.

Nhận cả dự án trọn gói lẫn vai trò cố vấn kỹ thuật. Hãy bắt đầu bằng buổi tư vấn miễn phí 30 phút.

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

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

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

Cũng đáng đọc