クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

LLMのトークンコストと予算の上限

このレッスンのあとで: 私は、ユーザーごとの上限、一日の上限、分かりやすいメッセージで、機能の使いすぎを防げます。

60分のレッスンコマンド8件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

機能が使いすぎないようにする

LLM 機能の予算とは、トークンをお金に換え、上限を超える呼び出しを断る仕組みです。コストは使われるほど増えます。よく使う一人のユーザーや一つのループが、一か月分の予算を午後だけで使い切ることもあります。

モデルはトークン単位で課金され、請求書は月末まで見えません。自分のコードに置いた上限は、その場で効く唯一のブレーキです。

このレッスンのゴール

メモ

私は、ユーザーごとの上限、一日の上限、分かりやすいメッセージで、機能の使いすぎを防げます。

キーワード

ことばいみ
トークンモデルが読み書きし、課金の単位にもなるもの
価格表100 万トークンあたりの、入力と出力の値段
ユーザーごとの上限一つのアカウントが一日に使える最大額
一日の上限機能全体が一日に使える最大額
台帳使った額を足していく記録
拒否理由を付けて呼び出しを断ること

学生が入力するセルは、このプレビューでは空白です。

トークンをお金に換える

モデルには二つの値段があります。入力トークン用と出力トークン用で、たいてい 100 万トークンあたりです。呼び出しの費用は、入力トークンに最初の値段を掛け、出力トークンに二つ目の値段を掛けて足したものです。

お金に浮動小数点は使いません。小さな整数の単位で数えます。ここでは、100 万トークンあたりの円が、そのままトークン一つのマイクロ円になるので、計算が整数で済みます。このレッスンの価格は架空です。

例: 二つの呼び出し

モデル入力出力計算費用
small、価格 1 と 4900300900 x 1 + 300 x 42100 マイクロ円
large、価格 10 と 40200100200 x 10 + 100 x 406000 マイクロ円

学生が入力するセルは、このプレビューでは空白です。

課金の前に上限を調べる

台帳を付けます。ユーザーごとの合計と、一日の合計です。呼び出しに課金する前に、まず調べます。ユーザーが自分の上限を超えるか、一日の合計が上限を超えるなら、断ります。合計が上限ちょうどなら許します。

ユーザーの上限を先に調べます。そのほうがメッセージが役に立つからです。断った呼び出しには課金しません。断るときは、人が次に何をすればよいか分かる言葉で理由を伝えます。

よくある間違い

注意

「上限は悪用を防ぐためだけのものだ」と考えて、公開のあとで設定する人が多くいます。コストは、再試行のループや、全員に送った長いプロンプトなどの不具合でも増えます。最初のユーザーが来る前に、二つの上限を決めましょう。

モデル用の助っ人を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// 応答に含まれるトークン数。なければ null。' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用の助っ人を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const d = await res.json();' '    return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '' '// 架空の価格表。100万トークンあたりの円。トークン数に価格を掛けるとマイクロ円になる。' 'const PRICE = { small: { in: 1, out: 4 }, large: { in: 10, out: 40 } };' 'const USER_LIMIT = 5000; // 一人が一日に使えるマイクロ円' 'const DAY_LIMIT = 8000; // 全員が一日に使えるマイクロ円' 'const spent = { user: new Map(), day: 0 };' 'function cost(model, inTokens, outTokens) {' '  return inTokens * PRICE[model].in + outTokens * PRICE[model].out;' '}' > budget3.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function check(user, price) {' '  const mine = spent.user.get(user) || 0;' '  if (mine + price > USER_LIMIT) return \"user\";' '  if (spent.day + price > DAY_LIMIT) return \"day\";' '  return \"ok\";' '}' 'function charge(user, price) {' '  spent.user.set(user, (spent.user.get(user) || 0) + price);' '  spent.day = spent.day + price;' '}' >> budget3.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function message(why, user) {' '  if (why === \"user\") return user + \" さん、この呼び出しを行うと、今日の利用枠を超えてしまいます。枠は真夜中に戻ります。\";' '  return \"アシスタントは、全員分の一日の上限に達しました。明日もう一度お試しください。\";' '}' 'async function demo() {' '  const prompt = \"五語であいさつしてください。\";' '  const reply = await ask([{ role: \"user\", content: prompt }], \"こんにちは、ご用件は何ですか。\", 20);' '  const inT = reply.inTokens === null ? Math.ceil(prompt.length / 2) : reply.inTokens;' '  const outT = reply.outTokens === null ? Math.ceil(reply.text.length / 2) : reply.outTokens;' '  const how = reply.inTokens === null ? \"推定\" : \"実測\";' '  console.log(\"あなたの呼び出し: 入力 \" + inT + \"、出力 \" + outT + \" (\" + how + \")、\" + cost(\"small\", inT, outT) + \" マイクロ円\");' '}' >> budget3.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const calls = [' '  { user: \"yuki\", model: \"small\", in: 900, out: 300 },' '  { user: \"haruto\", model: \"small\", in: 1000, out: 500 },' '  { user: \"yuki\", model: \"large\", in: 200, out: 100 },' '  { user: \"sakura\", model: \"large\", in: 300, out: 50 },' '  { user: \"sakura\", model: \"small\", in: 500, out: 100 },' '  { user: \"ren\", model: \"large\", in: 200, out: 50 },' '];' >> budget3.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を書く(5)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  await demo();' '  calls.forEach(function (c, at) {' '    const price = cost(c.model, c.in, c.out);' '    const why = check(c.user, price);' '    const label = \"#\" + (at + 1) + \" \" + c.user + \" \" + c.model + \" \" + price + \" マイクロ円: \";' '    if (why === \"ok\") { charge(c.user, price); console.log(label + \"ok\"); }' '    else console.log(label + message(why, c.user));' '  });' '  console.log(\"今日の合計: \" + spent.day + \" マイクロ円 = \" + (spent.day / 1000000).toFixed(6) + \" 円\");' '}' 'main();' >> budget3.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を実行する

コマンド
docker exec -w /home/node/project agent node budget3.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力の例

行示していること
あなたの呼び出し: 入力 42、出力 17 (実測)...あなた自身の呼び出し。応答に使用量があれば実測、なければ推定。実行のたびに変わる
#1 yuki small 2100 マイクロ円: ok課金された
#3 yuki large 6000 マイクロ円: yuki さん...ユーザーの上限で断られ、メッセージが付く
#4 sakura large 5000 マイクロ円: アシスタントは...一日の上限で断られた
今日の合計: 6000 マイクロ円 = 0.006000 円課金された呼び出しだけが数えられる

学生が入力するセルは、このプレビューでは空白です。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。