AgenticWorkerz
記事一覧に戻る
アーキテクチャ8 min read2026-04-01

AIエージェントのエラーハンドリングとリトライ設計のベストプラクティス完全版

本番環境のAIエージェントで発生するエラーの種類と対処法を体系的に解説。APIレートリミット・タイムアウト・LLM出力エラーへの対応設計と、安全なリトライ戦略を紹介します。

A
AgenticWorkerz編集部
AI × Work Research

本番稼働させた瞬間に気づく——エラーは必ず来る、問題はその後だ

AIエージェントを開発環境でテストしているとき、エラーはほとんど発生しない。APIは安定していて、LLMは期待通りのJSONを返して、処理は順調に完了する。問題は本番稼働させた瞬間から始まる。深夜にAPIのレートリミットに引っかかる。ネットワーク障害でタイムアウトが連発する。LLMが突然フォーマット外の出力を返してJSONパースが失敗する——これらは例外ではなく、本番環境の日常だ。

正直に言うと、エラーハンドリングの設計をサボったシステムは、本番稼働から2週間以内に必ず問題が起きる。そして「なぜ止まったのか」の原因追跡に深夜まで費やすはめになる。逆に、最初からエラーハンドリングを丁寧に設計したシステムは、問題が起きても自動でリカバリーし、翌朝のログを見て初めて「ああ、昨晩APIが落ちたんだな」と気づける——そんな安心感がある。

AIエージェントが本番環境で直面するエラーは大きく4種類に分類できる。第1はインフラエラー(ネットワーク障害・APIダウン・タイムアウト)、第2はLLMエラー(レートリミット・コンテキスト長超過・安全フィルターによる拒否)、第3は出力エラー(期待するフォーマットと異なる出力・不完全な応答・途中で切れた文章)、第4はロジックエラー(ツール呼び出しの失敗・依存するAPIが返すデータ構造の変化)だ。この4分類を頭に入れておくことが、適切な対処設計の出発点になる。

重要なのは「エラーの種類によって対処法が全く違う」という事実だ。インフラエラーは時間を置いてリトライすれば解決することが多いが、LLMの安全フィルターによる拒否をリトライしても同じ結果が返ってくるだけでAPIコストが無駄に消える。エラーの性質を正しく判断してから対処法を選ぶ——この「診断してから治療する」設計が、エラーハンドリングの本質だ。

指数バックオフとジッター——リトライの「正しいやり方」を知っているか

APIのレートリミットやタイムアウトに対して「失敗したら即座にリトライ」という実装をしている人は多い。実はこれがアンチパターンだ。失敗した直後に即リトライすると、APIがダウン中またはレートリミット中の場合は同じエラーが連続して返ってくるだけで、状況を悪化させることがある。特に複数のエージェントが同時に同じAPIを叩いているとき、全員が同じタイミングでリトライすると「thundering herd問題」が発生してAPIへの負荷が一気に跳ね上がる。

正しいリトライ戦略は「指数バックオフ+ジッター」だ。最初の失敗後は1秒待って再試行、次は2秒、4秒、8秒、16秒と倍増させ、最大リトライ回数(例:5回)に達したらフォールバック処理に移る。さらにジッター(ランダムな遅延)を各リトライに加えることで、複数のエージェントがバラバラのタイミングでリトライするようになり、APIへの集中負荷を防げる。実際にthundering herd問題を経験したチームのほとんどが、ジッターを追加しただけで問題が解決したと報告している。

Pythonのtenacityライブラリを使えば、デコレーターで簡潔にリトライロジックを実装できる。@retry(wait=wait_exponential(multiplier=1, min=1, max=60) + wait_random(0, 2), stop=stop_after_attempt(5))のような記述で、指数バックオフにジッターを加えたリトライが設定できる。自前でリトライロジックを実装するより、テスト済みのライブラリを使う方が実装コストが低くバグが混入しにくい。

リトライの最大回数と最大待機時間は、ユースケースに応じて慎重に設定する必要がある。リアルタイムで結果を返す必要があるユースケースなら最大2回・最大5秒、バッチ処理なら最大5回・最大60秒というように、SLAに合わせて判断する。「とりあえず5回リトライ」という設定ではなく、「なぜその回数・その時間なのか」を考えて設定することが、後のトラブルシューティングを楽にする。

LLMが「変なJSONを返した」——出力エラーへの現実的な対処法

本番運用で最も頻繁に遭遇するエラーの一つが、LLMが期待するJSONフォーマットと異なる出力を返すケースだ。多くの開発者が「JSONで返して」と指示すればいつでも正しいJSONが返ってくると思っているが、現実はそうではない。コードブロックでラップされたjsonブロックが返ってきたり、JSONの前に説明文が付いていたり、途中で文章が切れてJSONが不完全だったりするケースが、本番ではそれなりの頻度で発生する。

対処の手順は3段階で設計するのが現実的だ。まず正規表現でJSON部分を抽出する試みをする(コードブロックで囲まれたブロックや波かっこから始まる部分を抽出)。それでも失敗した場合は「前回の出力がJSONとして解析できませんでした。以下のスキーマに厳密に従い、余分な説明なしにJSONのみを出力してください」というメッセージとスキーマを再送信してリトライする。このパターンで大半の出力エラーは解決できる。実際、あるチームでのデータでは、この2段階処理でJSON解析エラーの92%が自動解決していた。

3回リトライしても正しい出力が得られない場合は、人間確認キューに移す。この閾値の設計がコストと品質のバランスを決める。リトライするたびにAPIコストがかかるため、「何回まで自動リトライして、それ以降は人間に回すか」を明確に決めておくことが、コスト管理の観点でも重要だ。また「どの割合のケースが人間確認キューに回っているか」をモニタリングしておくことで、プロンプトの品質改善の優先度判断に使える。この比率が5割を超えてきたら、プロンプトの見直しサインだと考えるといい。

止まらないシステムを作る——グレースフルデグラデーションの設計思想

エラーハンドリングの最終目標は「エラーが発生してもシステム全体が止まらない」状態を作ることだ。これを「グレースフルデグラデーション」と呼ぶ。一部が壊れても全体は動き続け、壊れた部分は記録して後から対処する——この設計思想が、本番運用における信頼性の土台になる。

グレースフルデグラデーションの実装パターンは3種類ある。「部分的な結果を返す」——10件処理するうちの2件がエラーになった場合、8件の結果を返してエラーの2件はログに記録する。「キャッシュされた前回の結果を返す」——リアルタイム取得に失敗した場合、1時間前のキャッシュ結果を返して「最終更新: 1時間前」と付記する。「デフォルト値で続行する」——特定の属性の取得に失敗した場合、デフォルト値(空文字列・0・N/Aなど)で埋めて処理を継続する。どれを選ぶかはユースケースのビジネスルールによって判断する。

重要なのは「全てのエラーを致命的エラーとして扱わない」ことだ。多くのシステムは設計上、エラーが発生すると全体が停止するように作られている。これは開発時のデバッグには便利だが、本番運用には向かない。エラーを「致命的(処理を停止すべき)」「重大(人間に通知すべき)」「軽微(ログに記録して続行)」の3レベルに分類し、それぞれの対処を明確に定義しておくことが、止まらないシステムの設計の出発点だ。最初の設計に時間をかけた分は、必ず本番運用の安定性として返ってくる。

#エラーハンドリング#リトライ設計#本番運用#信頼性

関連記事