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

無料レッスン

モデルのサーバーはどうまとめるか

このレッスンのあとで: サーバーが、たくさんの要求をバッチにする仕組みを説明できる。

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

一限の開始時に、全員が質問する

授業が始まった瞬間、クラスの全員が同じモデルに質問を送ったとします。モデルのサーバーは、モデルをメモリに置き、たくさんの人に答えるプログラムです。要求を待ち行列に入れ、まとめてバッチにします。

一つのチップが一人ずつ答えると、残りの人は待たされます。部屋がいっぱいでも速さを保つのが、バッチです。

このレッスンのゴール

メモ

サーバーが、たくさんの要求をバッチにする仕組みを説明できる。

キーワード

ことばいみ
待ち行列届いた順に待っている要求
バッチまとめて答える要求のかたまり
待ち時間届いてから始まるまでの時間
最初の言葉まで待ち時間に、最初のトークンを作る時間を足したもの
スループット決まった時間に終わる要求の数

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

待ち行列がチップに仕事を渡す

要求は待ち行列に並びます。チップが空くと、サーバーは届いている要求を取り、一つのバッチにして一緒に動かします。

このレッスンのモデルでは、バッチに、始めるのに 2 ティック、そのうえバッチの中でいちばん長い仕事の分がかかります。短い要求を足しても、ほとんど増えません。

同じ五つの要求、二つのバッチの大きさ

バッチの大きさ待ち (a, b, c, d, e)平均の待ち
10 5 9 16 148.80
30 5 4 3 53.40

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

二つの速さ: 最初の言葉と、一秒あたり

最初の言葉までは、待ち時間に、最初のトークンを作る時間を足したものです。人が「遅い」と感じるのはこれです。スループットは、決まった時間に終わる要求の数で、持ち主が払うお金に響きます。

バッチはスループットを上げます。ただし、バッチの中の短い要求は、いちばん長い要求が終わるまで終わりません。長い要求が一つあると、残りが遅れます。

よくある間違い

注意

「バッチは大きいほどよい」と考えがちです。大きいとスループットは上がりますが、バッチは中でいちばん長い要求と同じだけ続きます。待ちとスループットの両方を見て、大きさを選びます。

モデル用の補助を書く(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\");' 'const reqs = [[\"a\", 0, 4], [\"b\", 1, 3], [\"c\", 2, 6], [\"d\", 3, 2], [\"e\", 9, 3]];' 'function simulate(list, maxBatch) {' '  const out = [];' '  let time = 0;' '  let next = 0;' '  while (next < list.length) {' '    if (list[next][1] > time) time = list[next][1];' '    const batch = [];' '    while (next < list.length && batch.length < maxBatch && list[next][1] <= time) {' '      batch.push(list[next]);' '      next++;' '    }' > serve.js"

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

待ち行列を模擬するスクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '    const end = time + 2 + Math.max(...batch.map(function (r) { return r[2]; }));' '    batch.forEach(function (r) { out.push({ id: r[0], wait: time - r[1], end: end }); });' '    time = end;' '  }' '  return out;' '}' >> serve.js"

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

待ち行列を模擬するスクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function report(maxBatch) {' '  const rows = simulate(reqs, maxBatch);' '  const waits = rows.map(function (r) { return r.wait; });' '  const mean = waits.reduce(function (a, b) { return a + b; }, 0) / waits.length;' '  console.log(\"バッチ \" + maxBatch + \": 待ち \" + waits.join(\" \") + \"、平均 \" + mean.toFixed(2) + \"、終了 \" + rows[rows.length - 1].end);' '}' >> serve.js"

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

待ち行列を模擬するスクリプトを書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  report(1);' '  report(3);' '  const q = \"サーバーが要求をまとめてバッチにする理由を、短い一文で書いてください。\";' '  const sample = \"バッチにすると、チップが複数の要求を同時に処理でき、同じ時間でより多くの人に答えられるからです。\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 60);' '  console.log(\"返事: \" + reply.text);' '}' 'main();' >> serve.js"

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

待ち行列を模擬する

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

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

出力の例

行示していること
バッチ 1: 待ち 0 5 9 16 14、平均 8.80 ...一人ずつだと、待ちが長い
バッチ 3: 待ち 0 5 4 3 5、平均 3.40 ...まとめると、待ちが短い
終了 28 と 19全体がより早く片付く
返事: ...モデルの一文。言葉は毎回違う

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

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

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