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

無料レッスン

実行前に人に確認する

このレッスンのあとで: 危険なツールを、人の承認が出るまで待たせることができる。

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

はいを待つべき呼び出しがある

値段を調べても、何も変わりません。保存、送信、削除をするツールは、何かを変えてしまいます。モデルが間違ってそれを頼むと、被害は本物です。

だから、危険な呼び出しを実行するかどうか決めるのは、モデルではなくプログラムです。危険な呼び出しでは、まず人に尋ねます。

このレッスンのゴール

メモ

危険なツールを、人の承認が出るまで待たせることができる。

キーワード

ことばいみ
読み取りツールデータを見るだけのツール
書き込みツール何かを変えるツール
承認呼び出しの実行前に出る、人の「はい」
原則拒否はっきりした「はい」がなければ断ること
ログ何を尋ね、何を実行したかの記録

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

変えられるものでツールを分ける

ツールごとにリスクを決めます。読み取りツールは見るだけなので、すぐ実行できます。書き込みツールは何かを変えるので、「はい」が必要です。

リスクは、自分のテーブルに持ちます。呼び出しの危険度をモデルが決めることはなく、間違えたモデルがテーブルをすり抜けることもできません。

例で確認:3つのツールとリスク

ツールすることリスク実行
get_price値段を調べるreadすぐ
add_noteメモのリストに足すwrite「はい」のあと
delete_noteメモを消すwrite「はい」のあと
それ以外の名前表にない不明実行しない

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

モデルを呼ぶヘルパーを保存する

コマンド
docker exec -w /home/node/project agent node -e "const ask=async(m,t,c)=>{const r=await fetch((process.env.AI_URL||'http://ai:4000')+'/v1/chat/completions',{method:'POST',headers:{'content-type':'application/json',authorization:'Bearer lab'},body:JSON.stringify({model:'lab',messages:m,tools:t,tool_choice:c,max_tokens:120})});const j=await r.json();if(r.ok)return j.choices[0].message;throw Error(r.status+' '+j.error.message)};require('fs').writeFileSync('ai.cjs','exports.ask='+ask+';');console.log('ai.cjsを保存しました:ask(messages, tools)はモデルのメッセージを返します。')"

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

人に尋ね、原則は断る

ツールが何をするかを表示して、答えを1つ読みます。「はい」はyだけです。空行や、答えがないことも含め、それ以外はすべて「いいえ」です。

これが原則拒否です。はっきりした「はい」があるときだけ、呼び出しは実行されます。次の実行では答えを先に入れておくので、全員が同じ行を見ます。手で入力すれば、あなたの答えを待ちます。

3つの呼び出しを決まった答えで通す

コマンド
printf 'y\nn\n' | docker exec -i -w /home/node/project agent node -e "const rl=require('readline').createInterface({input:process.stdin});const it=rl[Symbol.asyncIterator]();const R={get_price:'read',add_note:'write',delete_note:'write'};const N=['牛乳'];const F={get_price:a=>150,add_note:a=>N.push(a.text),delete_note:a=>N.splice(a.index,1)};(async()=>{const log=[];for(const c of [{n:'get_price',a:{item:'なし'}},{n:'add_note',a:{text:'卵'}},{n:'delete_note',a:{index:0}}]){let ok=R[c.n]=='read';if(ok===false){process.stdout.write(c.n+' '+JSON.stringify(c.a)+'を許可しますか?(y/n) ');const l=await it.next();ok=l.value?.trim()=='y';console.log(ok?'y':'n')}if(ok)F[c.n](c.a);log.push(c.n+':'+(ok?'実行':'拒否'))}console.log(log.join('、'));console.log('メモ:'+N.join('、'));rl.close()})()"

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

モデルに頼ませて、断る

コマンド
printf 'n\n' | docker exec -i -w /home/node/project agent node -e "const{ask}=require('./ai.cjs');const rl=require('readline').createInterface({input:process.stdin});const it=rl[Symbol.asyncIterator]();const T=[{type:'function',function:{name:'add_note',description:'メモを保存する。',parameters:{type:'object',properties:{text:{type:'string'}}}}}];(async()=>{let c;try{c=(await ask([{role:'user',content:'メモを保存してください:牛乳を買う'}],T,'required')).tool_calls[0].function}catch(e){console.log('モデルなし('+e.message+')。記録済みサンプル:');c={name:'add_note',arguments:JSON.stringify({text:'牛乳を買う'})}}process.stdout.write('モデルは'+c.name+' '+c.arguments+'を求めています。許可しますか?(y/n) ');const l=await it.next();const ok=l.value?.trim()=='y';console.log(ok?'y':'n');console.log(ok?'add_noteを実行しました。':'拒否しました。何も実行されていません。');rl.close()})()"

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

呼び出しをすべてログに残す

呼び出しごとに、名前、人に尋ねたか、何と答えたか、実行したかを記録します。ログを見れば、アシスタントが何をしたか、何を止められたかが分かります。

断った呼び出しも記録しましょう。誰にも見えない断りは、あとで謎になります。

よくある間違い

注意

危険な呼び出しが安全かどうかは、モデルが決めると思っている人が多くいます。決めません。モデルは間違えることも、読んだ文章にだまされることもあります。決めるのはあなたのプログラムで、書き込みの前には人に尋ねます。

さらに:答えを変えてみる

最初の実行で、先に入れる答えをyとnからnとnに変えます。もう一度実行して、メモの行を読みましょう。

その後、Rのget_priceをwriteに変えます。プログラムが何を尋ねるようになったか書きます。

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

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