Claude APIを毎日運用して遭遇したエラーと対処(自動リトライが効かない罠)

Claude APIで記事を毎日自動生成しています。その運用中に実際に起きた障害と、その対処を記録します。公式ドキュメントに書かれていない挙動が中心です。

1. 「Grammar compilation timed out」でSDKのリトライが効かない

構造化出力(JSON Schema指定)を使っていると、まれにこのエラーが返ります。

Error code: 400 - 'Grammar compilation timed out.'

問題はこれが400番(クライアントエラー)で返ることです。AnthropicのSDKにはmax_retriesがありますが、400番は「リクエストが悪い」という扱いなので再試行されません。実際には一時的な混雑で起きるだけなので、もう一度投げれば通ります。

対処として、このメッセージのときだけ自前で再試行するようにしました。

for i in range(4):
    try:
        return client.messages.create(...)
    except Exception as e:
        if "Grammar compilation timed out" not in str(e):
            raise          # 他のエラーは再試行しない
        time.sleep(20 * (i + 1))

ポイントはこのエラーだけを対象にすることです。全部の400番を再試行すると、本当にリクエストが壊れているときに気づけなくなります。

2. 長い出力はストリーミングにしないとタイムアウトする

max_tokensを大きくした長文生成では、リクエスト全体のタイムアウトに引っかかることがあります。長い入力・長い出力・大きなmax_tokensのいずれかに当てはまるなら、最初からストリーミングを使うほうが安全です。

3. コストは「生成」より「探す」ほうが高いことがある

これはClaudeに限りませんが、外部APIと組み合わせるときに効いてきます。たとえばYouTube Data APIでは、動画を検索する操作が1回100ユニット、コメントを投稿する操作が50ユニットです。1日の上限は10,000ユニット。

つまり「何に返信するか探す」処理のほうが、実際に書く処理より高いという状態が起きます。自動化を設計するときは、生成コストだけでなく探索コストを数えてください。

4. エラー通知は「型」と「最後の1行」を必ず残す

運用初期、エラーログにstr(e)だけを記録していたところ、中身が空のまま失敗する例外に遭遇して原因が分からなくなりました。

[エラー] remove @xxx:            ← これだけ。手がかりゼロ

いまは例外の型名トレースバックの最後の1行を必ず添えています。この2つがあるだけで、調査時間が大幅に変わります。

まとめ

  • 400番でも一時的なエラーがある。SDK任せにせず、メッセージを見て自前で再試行する
  • 長文生成はストリーミングを既定にする
  • 生成コストより探索コストのほうが高い場合がある
  • ログには例外の型を残す。str(e)だけでは空になることがある