Skip to content
··2分で読めます

1つのAIパラメータ変更で月$54のコスト

Cloud Run移行は完璧だと思っていました。しかし、たった1つのAIパラメータ — temperatureが0ではなく0.7に設定されていたこと — が30%のAPI呼び出し失敗と月$54の無駄なトークンを引き起こしました。

ClaudeにAWS LambdaからGoogle Cloud Runへの移行を手伝ってもらいました。移行は完璧に進みました — サービスはデプロイされ、ワークフローは実行され、ユーザーは満足していました。そしてAPIの請求書を確認したとき、椅子から落ちそうになりました。

*これはDIALOGUEエンジニアリングシリーズのパート3です。見逃した方はこちら:[パート1: DIALOGUEの紹介]と[パート2: 広告からエンジニアリングへ]が基礎をカバーしています。*

これは、本番環境の制約を明示せずにAIに本番コードを書かせたときに何が起こるかの物語です。ネタバレ:「動かして」と「本番対応にして」はまったく異なるリクエストです。

うまくいきすぎた移行

AWS Lambdaと何ヶ月も格闘した後(コールドスタート、レイヤー制限、諸々)、すべてをGoogle Cloud Runに移行することにしました。プラグマティックな開発者として(つまり:怠け者)、Claudeをペアプログラマーとして起用しました。

「これらのLambda関数をCloud Runに移行するのを手伝って」と言いました。「既存のコードはこちら。」

Claudeは見事に仕上げてくれました。クリーンなDockerfile、適切なサービス設定、動作するCloud Workflows。移行は予想した数週間ではなく、たった1日で完了しました。感激でした!

すべてスムーズにデプロイされました。サービスは素早く起動しました。ユーザーは問題なくポッドキャストを作成していました。成功、でしょう?

そしてログで奇妙なことに気づきました:

```
[ERROR] Segment generation failed: Unexpected token in JSON
[RETRY] Attempting segment generation again...
[SUCCESS] Segment generated successfully
```

AI呼び出しの約30%が最初の試行で失敗していましたが、リトライで成功していました。世界の終わりではありません — リトライロジックは機能していました!ユーザーは問題に気づいていませんでした。しかし、余分なAPI呼び出しは積み上がっていました。

調査:移行のせい?

最初の考えは、移行中に何かがおかしくなったということでした。新しいCloud Run環境が違うのか?コンテナネットワーキングの問題?何時間もAWSとGCPの設定を比較しました。

すべて同一でした。同じプロンプト、同じリトライロジック、同じエラーハンドリング。なぜ突然、不正なJSONレスポンスが発生するのか?

そして実際のコードを比較し始めました。見つけたのはこちらです:

AWS Lambdaバージョン(何ヶ月も問題なく動作):

```python
response = anthropic.messages.create(
      model="claude-3-7-sonnet-20250219",
      temperature=0,  # Deterministic for JSON
      response_format=\{"type": "json_object"\},  # JSON mode
      system="You are a JSON generation assistant. Output only valid JSON.",
      messages=[\{"role": "user", "content": prompt\}]
)
```

GCP Cloud Runバージョン(Claudeの移行):

```python
response = anthropic.messages.create(
    model="claude-3-7-sonnet-20250219",
    temperature=0.7,  # <-- Wait, what?
    messages=[\{"role": "user", "content": prompt\}]
)
```

ありました。Temperature 0.7。

「でもそれは妥当なデフォルトでしょ!」と思うかもしれません。その通りです。クリエイティブライティング、探求、ブレインストーミングには0.7は完全に合理的です。しかし構造化されたJSON生成には?災害です。

犯人:クリエイティブなJSON

実際のAIレスポンスをキャプチャするための詳細なロギングを追加した後、何が起きていたかを正確に見つけました。Temperature 0.7でClaudeが返していた内容はこちらです:

```
Here's the podcast segment you requested:

\{
  "title": "The Rise of AI Podcasting",
  "content": "Welcome back, listeners! Today we're diving into something really fascinating...",
  "duration": 120
\}

I hope this segment captures what you were looking for!
```

問題がわかりますか?Claudeがレスポンス形式に対して_クリエイティブ_になっていました。JSONのみの時もあれば、親切なコメント付きのJSON、マークダウンコードブロックに包まれたJSONの時もありました。Temperature 0.7では、メトロノームが必要な場面でジャズミュージシャンのように即興演奏していたのです。

AIペアプログラミングの盲点

AIをペアプログラマーとして使うことの特徴は:コードを_動かす_ことには非常に優れていますが、明示的に求めない限り本番環境の懸念に対して最適化するわけではないということです。

「このLambda関数をCloud Runに移行して」と言ったとき、Claudeは移行要件にフォーカスしました:

- ✅ Cloud Runで動作させる

- ✅ 同じ入力と出力を処理する

- ✅ 同じ機能を維持する

- ❌ 本番効率の最適化

Claudeがtemperature 0.7を選んだのは、AIアプリケーションにとって「妥当なデフォルト」だからです。そしてそれは正しいのです!ほとんどのユースケースでは、0.7は創造性と一貫性の良いバランスを提供します。

しかしここで学んだのは:AIはあなたの特定の本番環境の制約を伝えなければ知りません。

元のAWSコードはtemperature 0とJSONモードを使用していました。JSON生成には決定論的出力と明示的なフォーマットの両方が必要だと(辛い思いをして)学んだからです。しかし移行中に「これは構造化データ生成用です」や「JSON固有の最適化をすべて維持して」と明示的に言いませんでした。

だからClaudeは合理的なデフォルトで完全に機能するコードを書きました。問題はAIではなく — 不完全な要件定義でした。

修正:AIにより具体的に

問題を特定した後、より良い要件でClaudeに戻りました:

「このコードを修正してほしい。本番環境でのJSON生成用です。100%の信頼性、ゼロの創造性が必要。Temperature 0と構造化データのためのその他の最適化を使って。」

Claudeはすぐに提案しました:

```python
response = anthropic.messages.create(
    model="claude-3-5-sonnet",
    temperature=0,  # Deterministic outputs
    response_format=\{"type": "json_object"\},  # JSON mode
    system="You are a JSON generation assistant. Output only valid JSON.",
    messages=[\{"role": "user", "content": prompt\}]
)
```

あれ、Claudeが持っていたJSONモードを落としました!(これが移行中にすべての本番要件を明示的に言及しないと起こることです!)

成功率は70%から99.9%に跳ね上がりました。残りの0.1%?ネットワークタイムアウト。それはClaudeのせいにはできません。

違いは?今回は本番環境の制約について明示的でした。単なる移行ではなく、本番最適化で信頼性重視のコードを求めました。

「妥当な」デフォルトの本当のコスト

この「妥当な」temperature設定が実際にいくらかかったかを分解してみましょう:

- 1日のポッドキャスト生成数: 約200

- 失敗率: 30%がリトライ必要

- 1日あたりの余分なAPI呼び出し: 60の失敗した呼び出しがリトライ必要

- 月間の無駄: 約1,800の不要なAPI呼び出し

- Claude 3.7 Sonnetの価格: 100万トークンあたり入力$3 + 出力$15

- 呼び出しあたりの平均トークン: 入力約2,000 + 出力1,500

- リトライあたりのコスト: 失敗1回あたり約$0.03

- 月間の超過: 無駄なAPI呼び出しで約$54

しかし本当のコストは月$54だけではありませんでした。各リトライは生成時間に3-5秒追加しました。ユーザーはより長く待たされ、Cloud Runインスタンスはより頻繁にスピンアップし、クオータをより速く消費していました。

核心は?本番環境のコンテキストを与えずにAIに本番環境の決定を任せたということです。「動く」と「効率的に動く」の典型的なケースです。

AIペアプログラミングから学んだこと

1. 本番要件について明示的であること

「動かして」は機能するコードを得られます。「これらの制約の下で本番環境で効率的に動かして」は最適化されたコードを得られます。AIはあなたが説明した問題を解くのが得意で、頭の中にある問題ではありません。

2. AIは「妥当な」デフォルトを使い、「最適な」ものではない

Temperature 0.7はほとんどのAIアプリケーションにとって妥当です。しかし本番システムにはtemperature 0とJSONモードのような特定の最適化が必要なことが多いです。AIは明示的に言及しない限りこれらを維持しません。

3. コードレビューはAI生成コードにも適用される

AIが書いたからといって本番対応済みとは限りません。コードレビューでこれを捕まえるべきでしたが、移行が動作するかどうかに集中しすぎてパラメータの監査をしませんでした。

4. コンテキストは思っている以上に重要

元のAWSコードにtemperature 0とJSONモードがあったのは正当な理由からでした — 辛い経験から学んだのです。移行中にそのコンテキストが失われたのは、明示的に言及しなかったからです。今ではすべてのパラメータと機能の「なぜ」をドキュメントに残しています。

新しいAIペアプログラミングワークフロー

今では本番コードでAIと作業するとき、制約についてはるかに明示的です:

以前:

「このLambda関数をCloud Runに移行して」

現在:

「このLambda関数をCloud Runに移行して。本番環境のJSON生成用です — 創造性よりも信頼性を優先して。Temperature 0、利用可能ならJSONモード、構造化データ出力のためのその他の最適化を使って。」

Claudeが構築を手伝ってくれた本番最適化設定はこちらです:

```python
def get_ai_json_response(prompt: str) -> dict:
    """Production-optimized JSON generation with AI"""
    response = anthropic.messages.create(
        model="claude-sonnet-4-20250514",
        temperature=0,  # Zero creativity for structured data
        response_format=\{"type": "json_object"\},  # Force JSON mode
        system="You are a JSON generation assistant. Output only valid JSON.",
        messages=[\{
            "role": "user",
            "content": f"{prompt\}\n\nRespond with valid JSON only."
        }]
    )

    # Explicit error handling for production
    try:
        return json.loads(response.content[0].text)
    except json.JSONDecodeError as e:
        logger.error(f"JSON parse failed: \{e\}")
        logger.error(f"Raw response: {response.content[0].text}")
        raise
```

違いは?AIに特定のユースケースに最適化するために必要なコンテキストを与えたことです。

結果

APIコスト30%削減、生成40%高速化。要件について具体的に伝えた1つの会話から得られた成果です。

面白いのは?「クリエイティブ」な対話生成でもtemperature 0を使用しています。決定論的だからといって退屈とは限りません — 信頼できるということです。会話はプロンプトとコンテンツリサーチがバリエーションを提供するため、ランダムなtemperature変動ではなく、自然に聞こえます。

結局のところ、AIペアプログラミングは、それがプログラミングであることを忘れなければうまくいきます — 要件の精度が結果の精度をもたらします。

AIアシスタントが「妥当な」選択をして、あなたのユースケースにはまったく間違っていたという経験はありますか?ぜひ戦争の話を聞きたいです — 誰もが合理的なデフォルトに噛まれた経験があると思います :)

よろしくお願いします、Chandler

自分だけのAIポッドキャストを有効なJSONで作りたいですか?DIALOGUEを試してみてください — 無料クレジット2つで始められます! :P

DIALOGUEエンジニアリングシリーズのパート3。「動かして」と「効率的に動かして」はまったく異なるリクエストだと学び続けています。chandlernguyen.comでAIペアプログラミングの冒険をフォローしてください。

次のシリーズ: 約7日後に公開予定 - 「3分から500msへ:意味不明だったサインアップバグ」

続きを読む

私の歩み
つながる
言語
設定