カナリア展開の仕組み
カナリア展開は、全員に変更を渡す前に、少しの割合の利用者にだけ先に渡します。変更が悪くても、問題に出会うのはわずかな人だけです。
小さく先に出せば、悪い変更を、早く、小さな害で見つけられます。このレッスンでは、割合を正確に決め、判断を、変更を出す前に書いた規則にします。
このレッスンのゴール
メモ
変更を少しの割合の利用者に送り、規則で次の一手を決めることができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| カナリア | 変更を最初に受け取る、小さな集まり | |
| 割合 | カナリアに入る利用者の百分率 | 5 |
| バケット | 利用者ごとに決まっている 0 から 99 の数 | |
| 進める | 変更をもっと多くの利用者に渡すこと | |
| 戻す | 変更をもう一度取り下げること | |
| 余裕 | カナリアが旧バージョンより悪くてよい幅 |
学生が入力するセルは、このプレビューでは空白です。
決まったバケットが、誰が入るかを決める
毎回ランダムに選んではいけません。同じ人が、古いバージョンと新しいバージョンの間を行き来してしまいます。利用者ごとに、変わらない 0 から 99 のバケットを決めます。
バケットが割合より小さい利用者が、カナリアに入ります。割合が 20 なら、バケット 0 から 19 が入ります。
例: 五人の利用者
| 利用者 | バケット | 割合 5 で入る | 割合 20 で入る | 割合 50 で入る |
|---|---|---|---|---|
| u7 | 4 | はい | はい | はい |
| u9 | 18 | いいえ | はい | はい |
| u15 | 33 | いいえ | いいえ | はい |
| u1 | 62 | いいえ | いいえ | いいえ |
| u10 | 98 | いいえ | いいえ | いいえ |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
小さなカナリアで失敗がなければ、変更は安全だと考える人が多いです。数人が少し送っただけでは、ほとんど何も分かりません。先に件数の最低ラインを決め、それだけ集まるまで待ちましょう。
展開の前に、規則を書く
同じ段階で、カナリアの失敗の百分率を、旧バージョンのものと比べます。割り算は整数で、切り捨てます。
カナリアが 50 件未満なら待ちます。百分率が、旧バージョンのものに余裕の 2 を足した数より大きければ戻します。それ以外は進めます。
例: 三つの段階
| 割合 | カナリアの件数 | カナリアの失敗 | 旧の百分率 | 判断 |
|---|---|---|---|---|
| 5 | 40 | 1 | 1 | 待つ、40 件しかない |
| 20 | 180 | 4 | 2 | 進める、2 は 4 より大きくない |
| 50 | 300 | 18 | 2 | 戻す、6 は 4 より大きい |
学生が入力するセルは、このプレビューでは空白です。
助っ人 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 bucket(user) {' ' let s = 0;' ' for (let i = 0; i < user.length; i++) s = s + user.charCodeAt(i);' ' return (s * 7) % 100;' '}' 'function inCanary(user, share) { return bucket(user) < share; }' 'const users = [];' 'for (let i = 1; i <= 20; i++) users.push(\"u\" + i);' > canary.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
カナリアのスクリプトを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const stages = [' ' { share: 5, cn: 40, ce: 1, bn: 760, be: 15 },' ' { share: 20, cn: 180, ce: 4, bn: 640, be: 13 },' ' { share: 50, cn: 300, ce: 18, bn: 450, be: 9 },' '];' 'function pct(e, n) { return Math.floor(e * 100 / n); }' 'function decide(s) {' ' if (s.cn < 50) return \"待つ\";' ' return pct(s.ce, s.cn) > pct(s.be, s.bn) + 2 ? \"戻す\" : \"進める\";' '}' >> canary.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
カナリアのスクリプトを書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' [5, 20].forEach(function (share) {' ' console.log(\"割合 \" + share + \": \" + users.filter(function (u) { return inCanary(u, share); }).join(\" \"));' ' });' ' for (const s of stages) {' ' const d = decide(s);' ' console.log(\"段階 \" + s.share + \": カナリア \" + pct(s.ce, s.cn) + \" パーセント、旧 \" + pct(s.be, s.bn) + \" パーセント -> \" + d);' ' if (d === \"戻す\" || d === \"待つ\") break;' ' }' ' const q = \"短く一文で答えてください。変更を、最初は少しの利用者にだけ送るのは、なぜですか。\";' ' const sample = \"変更が悪くても、問題に出会うのはわずかな人で、すぐに元に戻せるからです。\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 80);' ' console.log(\"モデル: \" + reply.text);' '}' 'main();' >> canary.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
カナリアを動かす
docker exec -w /home/node/project agent node canary.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run の出力
| 行 | 意味 |
|---|---|
| 割合 5: u7 | 割合 5 でカナリアに入る一人 |
| 割合 20: u7 u8 u9 u11 u12 u13 u20 | 七人。u7 は入ったまま |
| 段階 5: カナリア 2 パーセント、旧 1 パーセント -> 待つ | 50 件未満なので待つ |
| モデル: ... | ラボからの一文。モデルが答えなければ記録済みサンプル |
学生が入力するセルは、このプレビューでは空白です。