実測ラボ

AI APIのコストを下げる方法5選|データ形式を変えるだけで3分の1になる【実測】

「AI APIの請求が思ったより高い」

モデルを乗り換える前に、やることがあります。 実際に測ったところ、同じデータでも渡し方だけで消費トークンが3倍変わりました

この記事では、効果が大きく実装が簡単な順に、5つの削減方法を実測データつきで紹介します。1番目はコードを1行変えるだけです。

この記事の要点

  • 整形JSONをやめるだけで約4割削減indent を外す。1行の変更)
  • XMLはCSVの3.05倍のトークンを消費する。最も重い形式
  • 出力を短くするのが最も効く。出力単価は入力の5〜6倍
  • 日本語で使うなら単価に1.4倍を掛けたものが実質コスト

削減効果ランキング

順位 方法 削減率 実装の手間
1位 出力を短くする(プロンプトに1行追加) 最大80% 1行
2位 XML・YAMLをやめてCSV/TSVにする 最大67% 数行
3位 JSONのindentを外す 37% 1行
4位 プロンプトキャッシュを使う 最大90%(該当時)
5位 軽いモデルに変える 最大99%

1位と3位はコードをほぼ変えずにできます。 ここから着手してください。


【1位】出力を短くする(最大80%削減)

各社の料金表を見ると、出力の単価は入力の5〜6倍に設定されています。

モデル 入力 出力 倍率
Claude Sonnet 5 $2.00 $10.00 5倍
gpt-5.6-terra $2.00 $12.00 6倍
gemini-3.5-flash $1.50 $9.00 6倍

つまり出力が長いほど請求は跳ね上がります

やること

プロンプトに1行足すだけです。

簡潔に答えてください。前置きと要約は不要です。

これだけで、モデルが「〜についてご説明します」「以上が〜のまとめです」といった定型的な前後の文章を出さなくなります。回答が3倍長いモデルは、3倍高いということです。

構造化出力(JSON形式で返させる等)を使っている場合は、返すフィールドを必要最小限に絞ってください。


【2位】データ形式を変える(最大67%削減)

ここからが実測です。商品マスタ10件を7つの形式で表現し、トークン数を数えました。

実測結果(日本語データ10件)

形式 文字数 トークン数 CSV比
TSV 248 173 0.99
CSV 260 174 1.00
Markdown表 376 221 1.27
JSON(最小化) 525 267 1.53
YAML 504 358 2.06
JSON(整形) 826 426 2.45
XML 1,020 530 3.05

XMLはCSVの3.05倍。 英語データではさらに差が開き、3.59倍になりました。

なぜここまで差が出るのか

キー名の繰り返しが原因です。

CSVはヘッダー行にキー名を1回書くだけ。JSONやXMLはレコードごとに全キー名を書き直します。10件なら10回、1,000件なら1,000回です。

# CSV — キー名は1回だけ
商品名,価格,在庫,カテゴリ
ワイヤレスマウス,2980,45,周辺機器

# XML — 同じキー名を開始タグと終了タグで2回書く
<item>
  <商品名>ワイヤレスマウス</商品名>
  <価格>2980</価格>
</item>

XMLが最も重いのは、同じキー名を2回書くためです。

注意:CSVが常に正解ではない

形式 向いているデータ 注意点
CSV / TSV フラットな表形式 ネスト構造・配列を表現できない。値に区切り文字が入るとエスケープが必要
Markdown表 フラットな表形式 CSVより27%重いが、モデルが表として認識しやすい
JSON(最小化) ネスト構造・可変スキーマ 人間が読みにくい
XML 既存システムがXML固定の場合 最も重い。他に選択肢があるなら避ける

ネストが必要ならJSONを使ってください。 ただし次の方法を併用します。


【3位】JSONのindentを外す(37%削減・1行)

これが最も費用対効果が高い変更です。

形式 トークン数
JSON(整形・indent=2) 426
JSON(最小化) 267

差は159トークン、37%減。 そのほとんどが改行とインデントの空白です。人間が読むために入れた空白に、そのまま課金されています。

やること

# 変更前
json.dumps(data, ensure_ascii=False, indent=2)

# 変更後
json.dumps(data, ensure_ascii=False, separators=(",", ":"))

indent を消すだけです。 LLMに渡す用途では、整形する理由がありません。デバッグ時だけ整形すればよく、本番のリクエストで空白に課金される必要はありません。


【4位】プロンプトキャッシュを使う

同じシステムプロンプトを繰り返し使う場合、キャッシュが効きます。

モデル 通常入力 キャッシュヒット 削減率
Claude Sonnet 5 $2.00 $0.20 90%
Claude Opus 5 $5.00 $0.50 90%
gpt-5.6-terra $2.00 $0.20 90%

キャッシュヒット時は入力単価が10分の1になります。

ただしキャッシュへの書き込みには通常より高い単価(Claude Sonnet 5で$2.50)がかかるため、同じ内容を何度も使う場合にのみ有効です。1回きりの処理では逆に高くつきます。

長いシステムプロンプトや、共通のドキュメントを毎回添付するRAG構成では効果が大きくなります。


【5位】軽いモデルに変える(最大99%削減)

最後に、モデル自体の変更です。

同じ作業量(月100万文字の日本語処理)で計算すると、最安と最高で111倍の差があります。

モデル 月額
gemini-2.5-flash-lite 18円
gpt-5.6-luna 45円
Claude Sonnet 5 411円
Claude Opus 5 1,027円
Claude Fable 5 2,055円

詳しい順位はコスパの良いAI APIランキングに掲載しています。

ただし安いモデルで精度が足りなければ、人間が直す手間が発生して結局高くつきます。 分類・抽出・タグ付けのように正解が明確な処理から順に、軽いモデルへ移すのが安全です。


日本語を使うなら1.4倍で見積もる

削減方法とは別に、前提として知っておくべきことがあります。

日本語は英語の1.42倍のトークンを消費します(実測値)。

言語 1トークンあたり
日本語 1.46文字
英語 4.83文字

公式の単価表は英語圏を基準にした数字です。日本語で使うなら、単価に1.4倍を掛けたものが実質コストになります。詳細はAI API料金比較の落とし穴にまとめました。


よくある質問

一番効果が大きい方法はどれですか

出力を短くすることです。 出力単価は入力の5〜6倍なので、生成中心の使い方をしている場合はここが最も費用を圧迫しています。プロンプトに1行足すだけで実行できます。

JSONをCSVに変えると精度は落ちませんか

本記事では検証していません(未検証)。 トークン数は機械的に測れますが、モデルの解釈精度は別問題です。実運用では自分のタスクで比較してください。とくに列の対応を取り違えないか、値が欠損した場合の扱いは確認する価値があります。

indentを外すだけで本当に4割減りますか

実測では426トークン→267トークンで37%減でした。ただしデータの構造(キー名の長さ、ネストの深さ)によって変わります。自分のデータで測ることを勧めます。

キャッシュはいつ使うべきですか

同じ内容を繰り返し送る場合のみです。書き込み単価が通常より高いため、1回きりの処理では逆に高くなります。長いシステムプロンプトやRAGの共通文書に向いています。

安いモデルに変えて大丈夫ですか

タスクによります。分類・抽出・タグ付けのように正解が明確で量が多い処理なら軽いモデルで足りることが多いです。顧客に見せる文章や複雑な判断を伴う処理は、精度不足のリスクがあります。


まとめ:この順で試す

  1. プロンプトに「簡潔に」を追加(1行・最大80%減)
  2. json.dumps から indent を外す(1行・37%減)
  3. フラットなデータはCSV/TSVに変える(最大67%減)
  4. 繰り返し使う内容はキャッシュに載せる
  5. 精度が許すならモデルを軽くする

1と2はコードを2行変えるだけで、今日から効きます。


測定条件と再現方法

項目 内容
測定日時 2026年8月25日 12:06 JST
ライブラリ tiktoken 0.14.0
エンコーディング o200k_base(GPT-4o以降)
データ 商品マスタ10件(商品名・価格・在庫・カテゴリの4列)
import csv, io, json, yaml, tiktoken

ROWS = [
    {"商品名": "ワイヤレスマウス", "価格": 2980, "在庫": 45, "カテゴリ": "周辺機器"},
    # ... 全10件
]

def as_csv(rows):
    buf = io.StringIO()
    w = csv.DictWriter(buf, fieldnames=list(rows[0].keys()))
    w.writeheader(); w.writerows(rows)
    return buf.getvalue()

enc = tiktoken.get_encoding("o200k_base")
for name, text in [
    ("JSON (整形)",   json.dumps(ROWS, ensure_ascii=False, indent=2)),
    ("JSON (最小化)", json.dumps(ROWS, ensure_ascii=False, separators=(",", ":"))),
    ("YAML",          yaml.dump(ROWS, allow_unicode=True, sort_keys=False)),
    ("CSV",           as_csv(ROWS)),
]:
    print(f"{name}: {len(enc.encode(text))} トークン")

注記

  • 測定はOpenAIのトークナイザー(o200k_base)によるものです。Anthropic・Googleでは比率が変わる可能性があります(未検証
  • 料金は2026年8月25日時点の公式価格に基づきます
  • 形式によるモデルの回答精度の変化は検証していません(未検証