リスクを書き出して、漏らさない
リスク台帳とは、機能に何が起こりうるか、どれくらい起こりやすいか、どうするかを書いた表です。
話すだけのチームは、いくつかを忘れます。台帳は書いてあるので、抜けを調べ、悪いものから順に並べられます。
このレッスンのゴール
メモ
AI機能のリスクを、一つも抜かさずに書き出すことができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| リスク | 誰かにとって悪いことが起こりうること | |
| 起こりやすさ | どれくらい起こりやすいか。1 から 3 | |
| 影響 | 起こったとき、どれくらい悪いか。1 から 3 | |
| 対策 | リスクを小さくするためにすること | |
| 分野 | データの旅の一部分 | storage |
学生が入力するセルは、このプレビューでは空白です。
リスクごとに点数と対策がある
各リスクに、起こりやすさと影響を、それぞれ 1 から 3 で付けます。点数は二つの積です。点数が 2 以下なら低、3 か 4 なら中、6 か 9 なら高です。
どの行にも対策も要ります。対策のないリスクは、ただの心配です。
例: 起こりやすさ かける 影響
| リスク | 起こりやすさ | 影響 | 点数 | レベル |
|---|---|---|---|---|
| プロンプトにメールが入る | 3 | 2 | 6 | 高 |
| ログがプロンプト全文を残す | 2 | 3 | 6 | 高 |
| バックアップが削除したデータを残す | 2 | 2 | 4 | 中 |
| 社員が全員の会話を読める | 1 | 3 | 3 | 中 |
学生が入力するセルは、このプレビューでは空白です。
台帳には抜けも間違いもある
一つの行が間違うことがあります。起こりやすさが 5 だったり、対策が空だったりします。台帳全体が足りないこともあります。データの旅の分野ごとに、行が一つ以上あるかを調べます。
代表的な分野は、収集、送信、保存、閲覧、削除、学習の六つです。学習とは、集めたデータを使ってモデルを訓練することです。行のない分野が、抜けです。
このレッスンの台帳には、学習の行がありません。次の Run は、それを抜けとして見つけます。
よくある間違い
注意
点数は測った値だ、と考える人が多いです。そうではありません。判断を数にしたもので、人によって違います。話す順番を決めるために使い、機能が安全だという証拠には使いません。短い台帳は、足りない台帳かもしれません。
助っ人 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\");' 'const required = [\"collection\", \"sending\", \"storage\", \"access\", \"deletion\", \"training\"];' 'const register = [' ' { risk: \"プロンプトにメールが入る\", area: \"sending\", l: 3, i: 2, fix: \"先に伏せ字にする\" },' ' { risk: \"ログがプロンプト全文を残す\", area: \"storage\", l: 2, i: 3, fix: \"文字数だけ記録する\" },' ' { risk: \"バックアップが削除したデータを残す\", area: \"deletion\", l: 2, i: 2, fix: \" \" },' ' { risk: \"社員が全員の会話を読める\", area: \"access\", l: 1, i: 3, fix: \"読める人を絞る\" },' ' { risk: \"委託先がプロンプトを保存する\", area: \"collection\", l: 0, i: 3, fix: \"契約を確かめる\" },' '];' > register.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
台帳を確かめる道具を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function level(s) { return s <= 2 ? \"低\" : s <= 4 ? \"中\" : \"高\"; }' 'function problems(r) {' ' const out = [];' ' if (r.l < 1 || r.l > 3) out.push(\"起こりやすさが範囲外\");' ' if (r.i < 1 || r.i > 3) out.push(\"影響が範囲外\");' ' if (r.fix.trim().length === 0) out.push(\"対策がない\");' ' return out;' '}' >> register.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
台帳を確かめる道具を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function covered(area) {' ' return register.some(function (r) { return r.area === area; });' '}' 'async function main() {' ' const ranked = register.slice().sort(function (a, b) { return b.l * b.i - a.l * a.i; });' ' ranked.forEach(function (r) {' ' const s = r.l * r.i;' ' console.log(s + \" \" + level(s) + \" | \" + r.risk + \" | \" + JSON.stringify(problems(r)));' ' });' ' console.log(\"抜けている分野: \" + JSON.stringify(required.filter(function (a) { return covered(a) === false; })));' ' const q = \"次のリスクへの対策を、短く一つだけ書いてください。バックアップが、削除の依頼のあとも本人のデータを残す。\";' ' const sample = \"バックアップの保存期間を短くし、消える日を本人に伝えます。\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 80);' ' console.log(\"モデル: \" + reply.text);' '}' 'main();' >> register.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
台帳を確かめる道具を動かす
docker exec -w /home/node/project agent node register.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run の出力
| 行 | 意味 |
|---|---|
| 6 高 | プロンプトにメールが入る | [] | 一番悪いリスクで、問題はない |
| 4 中 | バックアップが ... | ["対策がない"] | 部分が抜けた行(全角の空白だけ) |
| 0 低 | 委託先が ... | ["起こりやすさが範囲外"] | 数が間違った行 |
| 抜けている分野: ["training"] | 行のない分野 |
| モデル: ... | 一文。言葉は毎回変わる |
学生が入力するセルは、このプレビューでは空白です。