遅延の予算とは
遅延とは、利用者が答えを待つ時間です。遅延の予算とは、許す時間の最大で、一つのリクエストの各段階で分け合います。
コスト、トレース、信頼性のモジュールでは、パーセンタイルとタイムアウトを学びます。このレッスンは、さらに進みます。リクエスト全体の予算と、ストリーミングが変えるものと変えないものです。
このレッスンのゴール
メモ
遅延の予算を決め、ストリーミングが何を変えるかを言うことができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| 遅延 | 利用者が待つ時間 | |
| 最初のトークンまでの時間 | 最初の言葉が出るまでの待ち | 600 ms |
| 合計時間 | 最後の言葉が出るまでの待ち | |
| ストリーミング | 言葉を、できた順に送ること | |
| 予算 | 許す時間の最大。段階で分け合う | |
| ミリ秒 | 1000 分の 1 秒 |
学生が入力するセルは、このプレビューでは空白です。
二つの時間: 最初の言葉と最後の言葉
返答は、最初の言葉が出るまでに少しかかり、そのあとは言葉ごとに少しずつかかります。最初の時間が、最初のトークンまでの時間です。最後が合計時間です。
合計時間は、最初のトークンまでの時間に、トークンごとの時間とトークンの数をかけたものを足した数です。
例: 二つの返答
| 返答 | 最初のトークンまで | 1 トークンごと | トークン数 | 合計 |
|---|---|---|---|---|
| 短い | 600 | 20 | 30 | 1200 |
| 長い | 600 | 20 | 300 | 6600 |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
ストリーミングで、返答が速くなると考える人が多いです。速くなりません。最後の言葉は、まったく同じ時刻に届きます。変わるのは、利用者が最初に言葉を見る時刻で、待ちが短く感じられます。
待ちを感じるのはどこか
ストリーミングがないと、利用者は合計時間まで何も見えません。あると、最初のトークンまでの時間のあとに言葉が見え、読み始められます。
長い返答では、違いが大きくなります。例では、最初の言葉を待つ時間が 6600 から 600 ミリ秒に減り、6000 の節約になります。
ストリーミングの代償
重要
返答全体を検査する前に、言葉が表示されます。安全の検査のように、全文が要る検査は、先に動かせません。ストリーミングをオンにする前に、その扱いを決めておきます。
予算を段階で分ける
リクエストの段階は、モデルだけではありません。待ち行列で待ち、資料を探し、返答を検査します。時間を順に足します。
途中までの合計が、初めて予算を超える段階が、最初に直すか、削る段階です。
例: 予算 1000
| 段階 | 時間 | 途中までの合計 | 1000 を超える? |
|---|---|---|---|
| 待ち行列 | 150 | 150 | いいえ |
| 資料の検索 | 400 | 550 | いいえ |
| モデルの最初のトークン | 600 | 1150 | はい。最初に超える |
| 安全の検査 | 200 | 1350 | はい。350 超過 |
学生が入力するセルは、このプレビューでは空白です。
助っ人 model.js を書く(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"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
助っ人 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 data = await res.json();' ' const text = data.choices[0].message.content;' ' return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"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\");' 'function total(r) { return r.ttft + r.perToken * r.tokens; }' 'function first(r) { return r.streamed ? r.ttft : total(r); }' 'const replies = [' ' { name: \"短い返答\", ttft: 600, perToken: 20, tokens: 30, streamed: false },' ' { name: \"長い返答\", ttft: 600, perToken: 20, tokens: 300, streamed: false },' ' { name: \"長い返答(ストリーム)\", ttft: 600, perToken: 20, tokens: 300, streamed: true },' '];' > latency.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
遅延のスクリプトを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const parts = [[\"待ち行列\", 150], [\"資料の検索\", 400], [\"モデルの最初のトークン\", 600], [\"安全の検査\", 200]];' 'function budget(limit) {' ' let sum = 0;' ' let over = \"なし\";' ' for (const p of parts) {' ' sum = sum + p[1];' ' if (sum > limit && over === \"なし\") over = p[0];' ' }' ' return \"合計 \" + sum + \"、残り \" + (limit - sum) + \"、最初に超えた部分: \" + over;' '}' >> latency.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
遅延のスクリプトを書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' for (const r of replies) console.log(r.name + \": 最初 \" + first(r) + \"、合計 \" + total(r));' ' console.log(\"予算 1000: \" + budget(1000));' ' console.log(\"予算 2000: \" + budget(2000));' ' const started = Date.now();' ' const reply = await ask([{ role: \"user\", content: \"短く一文で答えてください。言葉が早く出ると、利用者がうれしいのは、なぜですか。\" }], \"すぐに読み始められるので、待つ時間が短く感じられるからです。\", 80);' ' console.log(\"モデル: \" + reply.text);' ' console.log(\"返答全体の測った待ち時間: \" + (reply.recorded ? \"測っていません\" : Date.now() - started + \" ms\"));' '}' 'main();' >> latency.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
遅延の計算を動かす
docker exec -w /home/node/project agent node latency.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run の出力
| 行 | 意味 |
|---|---|
| 短い返答: 最初 1200、合計 1200 | ストリームなし。最初の言葉は合計の時刻 |
| 長い返答: 最初 6600、合計 6600 | ストリームなし。返答が長いので、待ちも長い |
| 長い返答(ストリーム): 最初 600、合計 6600 | ストリーム。最初は早く、合計は同じ |
| 予算 1000: 合計 1350、残り -350、最初に超えた部分: モデルの最初のトークン | 直す段階 |
| 予算 2000: 合計 1350、残り 650、最初に超えた部分: なし | 予算を増やすと、どの段階も超えない |
| モデル: ... | ラボからの一文。モデルが答えなければ記録済みサンプル |
| 返答全体の測った待ち時間: ... | 本物の ms。記録済みサンプルなら測っていません |
学生が入力するセルは、このプレビューでは空白です。