AI開発のエラーハンドリング - Retry戦略と特有の落とし穴
AI APIを使った開発では、通常のWeb APIとは異なる信頼性の問題に直面します。Rate LimitやTimeoutといった一般的なエラーに加え、AI特有の「見えないエラー」への対策が必要です。これらを適切に処理しないと、表面上は動作しているように見えても、実際には誤ったデータを処理し続けることになります。
結論
通常のRetry戦略に加え、AI特有のエラーパターンへの対策が必須です。レスポンス検証とFallback設計を組み合わせることで、実用レベルの信頼性を確保できます。
AI APIではどんなエラーが発生するのか?
AI APIでは以下のようなエラーが発生します。
- Rate Limit(429): API呼び出し回数の上限超過
- Timeout(504): レスポンスまでの時間切れ
- JSON Parse失敗: 不正なJSON形式での応答
これらは通常のWeb APIでも発生するエラーです。エラーハンドリングとは、try-catchなどで例外を捕捉し、適切に処理する仕組みを指します。
AI特有の「見えないエラー」とは何か?
AI APIには、HTTPステータスコードでは検知できない厄介な問題があります。
プロンプトで指定した構造を無視する
JSON構造を明確に指定しても、フォーマット違反で返すケースがあります。必須フィールドが欠落したり、データ型が異なったりすることも珍しくありません。
エラー時にダミーデータを返す
エラーが発生した際、AIが親切心で「N/A」「不明」「データなし」といったダミーデータを埋め込むことがあります。空文字やnullで埋める場合もあります。HTTPステータスは200で返ってくるため、一見成功したように見えます。
失敗を成功と誤認させる出力
「データが見つかりませんでした」という文章を、正常なレスポンスとして返すケースです。エラーメッセージを通常の出力フィールドに混入させるため、後続処理で問題が発生します。
Retry戦略の基本
指数バックオフ
Retryの待機時間を1秒→2秒→4秒と指数的に増やす手法です。Rate Limit対策として有効で、サーバー側の負荷が回復するまで適切に待機できます。
最大試行回数の設定
無限ループを防ぐため、最大試行回数を設定します。試行回数3〜5回が現実的なラインです。これはAPI料金とのバランスを考慮した数字ですね。
Retryすべきエラーの判別
すべてのエラーをRetryするのは非効率です。
- Retry推奨: 429(Rate Limit)、503(Service Unavailable)、504(Gateway Timeout)
- 即座に失敗: 400(Bad Request)、401(Unauthorized)、403(Forbidden)
認証エラーや不正なリクエストは、何度試しても成功しません。
AIのハードコーディング問題をどう防ぐか?
レスポンス検証の徹底
AIの出力を信頼せず、必ず検証を入れます。
def validate_response(response):
# 必須フィールドの存在確認
if not response.get("data"):
raise ValueError("Missing required field: data")
# ダミーデータの検出
if response["data"] in ["N/A", "不明", "unknown", ""]:
raise ValueError("Invalid placeholder value detected")
# データ型の検証
if not isinstance(response["data"], dict):
raise ValueError("Invalid data type")
return response
この検証を通過したレスポンスのみを正常とみなします。
プロンプト設計での対策
プロンプトに以下を明記します。
「エラー時は決してダミーデータを返さず、処理を失敗させること。N/A、不明、データなし等のプレースホルダーは使用禁止。」
出力例には正常ケースのみを示します。エラーパターンを例示すると、AIがそれを模倣する可能性があります。
Fallback設計
Primary API→Fallback API→デフォルト値という3段構えで設計します。
async function callWithFallback() {
try {
return await primaryAPI();
} catch (error) {
console.warn("Primary API failed, trying fallback");
try {
return await fallbackAPI();
} catch (fallbackError) {
console.error("All APIs failed, using default");
return getDefaultValue();
}
}
}
どの段階で成功したかをログに記録しておくと、障害分析に役立ちます。
構造化出力の活用
OpenAIのStructured OutputsやAnthropicのPrompt Caching等を使うことで、JSON Schemaによる厳密な制約を課せます。これにより、フォーマット違反を大幅に減らせます。詳しくは各APIの公式ドキュメントを参照してください。
実装例
PythonとTypeScriptそれぞれでシンプルな実装例を示します。
import time
def call_ai_with_retry(prompt, max_retries=3):
for attempt in range(max_retries):
try:
response = call_ai_api(prompt)
validated = validate_response(response)
return validated
except Exception as e:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt # 指数バックオフ
time.sleep(wait_time)
async function callAIWithRetry(prompt: string, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await callAIAPI(prompt);
const validated = validateResponse(response);
return validated;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
const waitTime = Math.pow(2, attempt) * 1000; // 指数バックオフ
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
コストと信頼性のバランス
Retry回数はAPI料金との兼ね合いで決めます。試行回数3〜5回が現実的なラインです。それ以上増やしても成功率はあまり上がらず、コストだけが増大します。
タイムアウト設定も重要です。1リクエストあたり30〜60秒程度に設定し、長時間待ち続けないようにします。
まとめ
AI APIの信頼性を上げるには、通常のRetry戦略だけでは不十分です。レスポンス検証を徹底し、プロンプト設計で問題を未然に防ぎ、Fallback設計で冗長性を持たせることが重要ですね。
コスト意識を持ちつつ、適切な設計を行えば、実用レベルの信頼性に到達できます。導入コストと得られる利益が見合うのであれば、これらの対策は必須です。