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

無料レッスン

AIアプリで安全に記録する

このレッスンのあとで: リクエストを直すのに足りるだけ記録し、残してはいけないものは残さないことができる。

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

役に立ち、漏らさない記録

ログとは、アプリが何をしたかを書き残した記録です。返事が遅いときや間違うとき、まずログを見ます。

不注意なログは、すべてのプロンプトとメールを、多くの人が読めるファイルに写してしまいます。目指すのは、直すのに足りるだけ残し、それ以上は残さないことです。

このレッスンのゴール

メモ

リクエストを直すのに足りるだけ記録し、残してはいけないものは残さないことができる。

キーワード

ことばいみれい
ログの記録一つの出来事について、プログラムが書く一行
リクエスト ID一つのリクエストの記録を、すべて結ぶ札r-001
ハッシュ値から作る短い符号。元には戻せない
ソルトハッシュにする前に混ぜる、秘密の言葉
切り詰める値を、数文字だけに短くすること

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

直すのに要るものを残す

まず、ログを何に使うかを考えます。遅い返事を直すなら、リクエスト ID、時間、モデル、文字数が要ります。言葉そのものは要りません。

言葉のない記録も、元のリクエストに結び付けられます。結ぶ鍵が、リクエスト ID です。

例: 一つの記録の前と後

項目生の記録安全な記録理由
request_idr-001r-001ログとリクエストを結ぶ
user_email[email protected]ハッシュ 8 文字ソルト付きのハッシュで、人数は数えられる
message注文の返金をお願いします12(文字数)言葉はログに入れない
ms420420遅い返事を探すのに要る

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

ハッシュは値を隠すが、人は隠さない

ハッシュは、メールを短い符号にします。同じメールはいつも同じ符号になるので、人数は数えられます。符号を見ても、元のメールには戻せません。

ソルトを混ぜると、符号を当てにくくなります。そのうえで、誰がログを読めるかも決めます。誰も読む必要のないログは、作らないのが一番です。

メールの最初の数文字だけに切り詰める方法もあります。ただ、残った文字から人を当てられることがあるので、ハッシュと同じく、まだ個人情報として扱います。

よくある間違い

注意

ハッシュは匿名だ、と考える人が多いです。そうではありません。メールの一覧を持つ人は、全部をハッシュにして符号を照らし合わせられます。ハッシュは仮の名前で、ログはまだ個人情報です。ソルトを使い、ソルトをログから離して置きます。

助っ人 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 crypto = require(\"crypto\");' 'const raw = [' '  { request_id: \"r-001\", user_email: \"[email protected]\", message: \"注文の返金をお願いします\", model: \"lab\", ms: 420 },' '  { request_id: \"r-002\", user_email: \"[email protected]\", message: \"090-0000-1111に電話してください\", model: \"lab\", ms: 380 },' '  { request_id: \"r-003\", user_email: \"[email protected]\", message: \"荷物はどこにありますか\", model: \"lab\", ms: 910 },' '];' > logsafe.js"

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

安全な記録の道具を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hash8(v) {' '  return crypto.createHash(\"sha256\").update(\"lab-salt:\" + v).digest(\"hex\").slice(0, 8);' '}' 'function safe(r) {' '  return { request_id: r.request_id, user: hash8(r.user_email), length: r.message.length, model: r.model, ms: r.ms };' '}' 'function holdsEmail(r) {' '  return Object.values(r).some(function (v) {' '    return typeof v === \"string\" && (v.includes(\"@\") || v.includes(\"@\"));' '  });' '}' >> logsafe.js"

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

安全な記録の道具を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const out = raw.map(safe);' '  raw.forEach(function (r, i) {' '    console.log(r.request_id + \" 生の記録にメール: \" + holdsEmail(r) + \" | 安全な記録にメール: \" + holdsEmail(out[i]));' '    console.log(\"  \" + JSON.stringify(out[i]));' '  });' '  console.log(\"r-001 と r-003 は同じ利用者: \" + (out[0].user === out[2].user));' '  console.log(\"r-001 と r-002 は同じ利用者: \" + (out[0].user === out[1].user));' '  const q = \"短く一文で答えてください。ログには、メッセージそのものではなく、なぜ文字数を残すのですか。\";' '  const sample = \"文字数は遅い返事を調べる役に立ち、本人については何も含まないからです。\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 80);' '  console.log(\"モデル: \" + reply.text);' '}' 'main();' >> logsafe.js"

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

安全な記録の道具を動かす

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

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

Run の出力

行意味
r-001 生の記録にメール: true | 安全な記録にメール: false安全な記録にメールはない
{"request_id":"r-001","user":"...",...}ハッシュと文字数だけ
r-001 と r-003 は同じ利用者: true同じ人は今も結び付く
r-001 と r-002 は同じ利用者: false違う二人は別のまま
モデル: ...一文。言葉は毎回変わる

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

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

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