先月の終わり、請求の画面を眺めながら「この作業だけ、安い道具に移せば半分になるのでは」と考え込んでおりました。ストアの文言を整える作業と、ログを読み解く作業と、コードを見てもらう作業。三つとも同じ道具に投げていたからです。個人開発で壁紙アプリを何年も運用していると、ストアの多言語文言の見直しは毎月のように発生します。一回あたりは小さくても、積み重なると請求の画面に形で現れてきます。
結論を先にお伝えします。道具を分けて得をするのは、月額の差額が「切り替える手間」を上回る作業だけです。 単価の安さだけを見ると、ほとんどの作業で判断を誤ります。
ここから先は、作業ごとの月額と手間を同じ表に並べて、損益分岐を出す小さなスクリプトをお見せします。特定のツールの優劣を決める話ではありません。単価は読んでくださる方ご自身の数字を入れていただく前提です。
単価だけを比べると、なぜ外れるのか
最初のうちの私は、料金表の「100 万トークンあたり」の数字だけを見て、安いほうへ寄せようとしました。結果は芳しくありませんでした。
理由は二つあります。
- 同じ作業でも、道具が違えば入力の組み立て方や出力の整え直しが変わり、一回ごとに数分が足されていきます
- 月に数回しか回さない作業は、差額が小さすぎて、乗り換えの準備だけで赤字になります
つまり、比べるべきなのは「単価」ではなく、一か月の作業量を掛けたあとの差額と、そこに足される自分の時間です。
表に並べる四つの数字
作業ごとに、次の四つだけを集めます。細かい計測は要りません。直近の会話履歴を眺めて、おおまかな桁が分かれば十分です。
| 項目 | 意味 | 集め方 |
|---|---|---|
| runs | その作業を月に何回回すか | 履歴やカレンダーから数える |
| in_tokens | 1 回あたりの入力量 | 貼り付けた文章やファイルの大きさから見積もる |
| out_tokens | 1 回あたりの出力量 | 返ってきた文章の長さから見積もる |
| current | いま使っている道具 | そのまま書く |
ほかに、道具ごとの単価(入力と出力)、切り替え 1 回あたりの手間(分)、自分の 1 時間の価値の三つを引数に渡します。月額や回数の枠で使うプランの場合は、「単価」を「1 回あたりに消費する枠の金額換算」に読み替えてください。課金の単位が違っても、表の考え方は変わりません。
損益分岐を出すスクリプト
何を解決するか。作業ごとに「最安の道具」と「切り替えたほうが得か」を一行で出します。
import csv, json, sys
# prices.json: {"tool_a": {"in": 3.0, "out": 15.0}, ...} (USD per 1M tokens)
prices = json.load(open(sys.argv[1]))
rows = list(csv.DictReader(open(sys.argv[2], encoding="utf-8")))
overhead_min = float(sys.argv[3]) # 道具を切り替える1回あたりの手間(分)
hourly = float(sys.argv[4]) # 自分の1時間の価値(USD)
def run_cost(tool, tin, tout):
p = prices[tool]
return (tin * p["in"] + tout * p["out"]) / 1_000_000
total = {t: 0.0 for t in prices}
for r in rows:
n, tin, tout = int(r["runs"]), int(r["in_tokens"]), int(r["out_tokens"])
costs = {t: run_cost(t, tin, tout) * n for t in prices}
best = min(costs, key=costs.get)
base = costs[r["current"]]
saving = base - costs[best]
switch_cost = n * overhead_min / 60 * hourly if best != r["current"] else 0
verdict = "切り替える" if saving > switch_cost else "今のまま"
print(f'{r["task"]:<14} 今={r["current"]} 最安={best} 月の差額={saving:6.2f} 手間換算={switch_cost:6.2f} -> {verdict}')
for t in prices:
total[t] += costs[t]
print("全部を1本に寄せた場合の月額:", {t: round(v, 2) for t, v in total.items()})なぜこう書くか。判断の材料を二つに絞ったからです。月の差額と手間の換算額を並べて、大きいほうで決めます。作業が増えても行を足すだけで済み、表計算ソフトを開くよりも、条件を変えて何度も回しやすいと感じています。
動かしてみる(数値はダミーです)
単価ファイルと作業表を用意します。以下の数字は説明のためのダミー値で、実在の料金ではありません。
{"tool_a": {"in": 3.0, "out": 15.0}, "tool_b": {"in": 1.25, "out": 10.0}}task,current,runs,in_tokens,out_tokens
日本語の校正,tool_a,60,6000,1500
コードレビュー,tool_a,40,30000,3000
ログ整理,tool_a,80,12000,800切り替えの手間を 1 回 1.5 分、自分の 1 時間を 20 ドルとして実行します。
python3 split_cost.py prices.json tasks.csv 1.5 20手元で動かすと、次のように出ました。
日本語の校正 今=tool_a 最安=tool_b 月の差額= 1.08 手間換算= 30.00 -> 今のまま
コードレビュー 今=tool_a 最安=tool_b 月の差額= 2.70 手間換算= 20.00 -> 今のまま
ログ整理 今=tool_a 最安=tool_b 月の差額= 2.00 手間換算= 40.00 -> 今のまま
全部を1本に寄せた場合の月額: {'tool_a': 11.67, 'tool_b': 5.89}最後の行だけを見ると、半額近くになります。ところが作業ごとに分けて見ると、三つとも差額より手間のほうが大きいのです。この例では、使い分けは赤字になります。
結果の読み方 — 三つの分かれ道
出力を見たあとに、私は次の順で考えるようにしています。
- 手間換算が差額を上回る作業は、いまの道具のままにします
- 差額が手間を上回る作業が出たら、そこだけ切り替えを試します
- 全作業を一本に寄せたときの月額が下がるなら、「分ける」ではなく「寄せる」を検討します
先ほどの例では、最後の行が示すとおり、分けるより一本に寄せるほうが効くことがあります。切り替えの手間が毎回かからないからです。この線引きが、いちばん大きな収穫でした。
もう一つ、手間の数字は自分に正直に置いてください。1.5 分を 0.2 分と書けば、どんな作業も「切り替える」と出ます。書き換えた数字で出た結論は、翌月の請求書では報われません。
私の場合は、どう動いたか
ストア文言の校正は、月に回す数が多い代わりに一回の入力が短い作業です。ここは差額が小さく、手間のほうが勝ちました。逆にログを丸ごと読ませる作業は入力が大きく、差額が育ちやすいのです。それでも、切り替えの準備に毎回数分かかるうちは、動かないほうが得でした。
最終的に私が選んだのは、「分ける」ではなく、道具を増やさないまま、入力を短く整えてから投げる運用です。表を作ってみて初めて、減らすべきなのは単価ではなく入力の量だったのだと気づきました。
つまずきやすい点
- 入力の大きさを見積もるとき: 長いログを丸ごと貼る作業は入力が支配的になり、短い文章を整える作業は出力が支配的になります。「in」と「out」を分けて入れる理由はここにあります
- 無料枠や月額の定額プラン: 追加料金が発生しない範囲では、差額は 0 です。この場合は単価を 0 にして、手間だけで判断してください
- 品質の差: このスクリプトは費用しか見ません。出力の質が違うなら、切り替える前に同じ入力で一度ずつ試して、手直しにかかる時間を「手間」に足してください
次のアクション
まずは直近の作業を三つだけ、上の四項目で書き出していただければと思います。単価ファイルは、各社の料金ページで確認した数字を入れてください。私もダミー値を自分の数字に置き換えるところから始めました。
道具を分ける前に、手間を数字にしておきます。 この一手間だけは、乗り換えの前に必ず入れるようにしています。