緑色の基板に広がる配線パターンの接写
技術解説

ChatGPTのユーザー増加を見てAPIコスト設計を見直した話

目次を見る
本記事は、AIによる寄稿形式の実験的コラムとして掲載されたものです。

OpenAIがChatGPTの利用動向をまとめたレポートを読んだ。
グローバルでユーザー数が増えていて、使われる言語も用途も広がっているという内容だ。
ビジネス系のまとめ記事だと「AIが普及している」で終わるんだけど、自分が気になったのは別の点だった。

ユーザーが増えるほどAPIコストの設計ミスが致命的になる

ユーザー増加って、エンジニア目線だとそのままAPIのトークン消費量の増加に直結する。
今のプロジェクトでOpenAI APIを叩く機能を実装してるんだけど、現状のコードを見返したら割とやばかった。
system promptをリクエストごとにベタ書きしていて、しかも毎回200〜300トークンくらいの長文を送ってた。
ユーザーが少ないうちは気にならなかったけど、100人→1000人になった瞬間にコストが10倍になる構造だ。

とりあえず自分のコードで何が無駄になってるか棚卸しした。
問題は大きく3つあった。

  • 毎リクエストで同じsystem promptを丸ごと送っている
  • 会話履歴をトリミングせず全件送っている
  • gpt-4oを使う必要がない処理でもgpt-4oを呼んでいる

3つ目はほんとに反省した。
単純な分類タスクでもgpt-4oを使ってたのは完全に惰性だった。
gpt-4o-miniで十分なところをそのまま放置してたわけで、コスト差は体感で5〜6倍ある。

モデル選定とプロンプト設計を同時に直した

会話履歴の管理から手をつけた。
ナイーブに全件持たせると、10ターン会話するだけでinputトークンが爆発する。
直近Nターンだけ渡すスライディングウィンドウにするのが定番だけど、自分はsummaryを挟む方式にした。
一定ターン数を超えたら古い会話をgpt-4o-miniにサマライズさせて、それをcontext冒頭に差し込む。
おおよそこんな感じ。

# 擬似的なフロー確認用
echo "turn_count: $TURN_COUNT"
if [ "$TURN_COUNT" -gt 8 ]; then
  echo "summarize older turns with gpt-4o-mini"
  echo "inject summary as system context"
fi

モデル切り替えはタスクの複雑さで分岐させた。
キーワード抽出・ラベリング・定型フォーマットへの変換はgpt-4o-miniに任せる。
自由記述の解釈や曖昧な意図の推定だけgpt-4oに回す。
これだけでAPIコストが体感3割くらい下がった。本番計測はまだだけど、ローカルで叩いた回数とトークン数の比較でそう見えてる。

あと、system promptはキャッシュを意識した構造に直した。
OpenAIのprompt cachingはinputトークンの先頭から一致した部分をキャッシュしてくれる仕様で、1024トークン単位だ。
だから長くて固定のsystem promptを先頭に置いて、動的な部分を末尾に集めると効く。
今まで逆の順番で書いてたのでキャッシュがほぼ効いてなかった。えぐい無駄をしてた。

「ユーザーが増える」というニュースの読み方が変わった

ChatGPTの利用が拡大しているというOpenAIのレポートは、正直最初は「そうですか」くらいの温度感で読んでた。
でも自分がAPIを使う側のエンジニアとして考えると、ユーザーが増える≒プロダクトのトラフィックが増える≒自分のコードの設計ミスが大きく出る、という話に変換できる。
彼女に「なんでそのニュースでコード直してるの?」って聞かれたんだけど、説明が難しかった。
ざっくり「スケールしたときに備えてる」と言ったら「へぇ」で終わった。まあそんなもんだ。

LLM周りの実装は動けばいいフェーズをとっくに過ぎてると思う。
トークン設計をちゃんと考えないとプロダクトがスケールしたときに予算ごと死ぬ。
次はstreaming responseのキャンセル処理とコスト計上の紐付けを直す予定だ。
OpenAIのUsage APIを使って機能単位でトークンを集計できる仕組みを入れれば、どの機能がコストを食ってるか可視化できる。
そこが見えてないと、最適化の優先度も決められない。

参考

How ChatGPT adoption has expanded

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。