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

無料レッスン

文章からレコードを作る流れ

このレッスンのあとで: 雑な文章から、確かめ済みのレコードを作る、小さな流れを組み立てられる。

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

たまったメッセージの山

文章からレコードを作る流れとは、雑なメッセージを、プログラムが保存できる、確かめ済みのレコードにする仕組みです。ここまでの各段階は小さく、実際の仕事では、全部がいっしょに必要になるからです。

高校の事務室に、自由な文章の備品の依頼がたまります。誰かが、品物、数、急ぎかどうかを、行にしてほしいと考えます。300件を手で打ちたい人はいません。

このレッスンのゴール

メモ

雑な文章から、確かめ済みのレコードを作る、小さな流れを組み立てられる。

キーワード

ことばいみ
パイプライン結果を次へ渡していく、段階の列
バッチまとめて処理する、文章の集まり
却下理由を付けて、その文章を除くこと
却下率却下された文章の割合
保存確かめ済みのレコードを、どこかへ書くこと
個人データ人を特定できる情報

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

4つの段階を、順に行う

どのメッセージも、同じ段階を通ります。取り出し: モデルに項目を聞きます。検証: スキーマでレコードを確かめます。修復: 失敗したら、違反を付けて1回だけ聞き直します。保存: 良いレコードを書きます。

それでも失敗するメッセージは却下します。保存はされませんが、失われもしません。文章と理由を残します。

却下を数え、理由を残す

却下は情報です。文章と理由を残し、却下率を出します。却下率が高ければ、プロンプトかスキーマに手直しが要ります。

個人データには気を付けます。モデルには、必要な文章だけを送ります。ログには、人についてのメッセージの文章ではなく、理由を書きます。

モデル用の補助を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '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 || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    return (await res.json()).choices[0].message.content;' > model.js"

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

モデル用の補助を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' >> model.js"

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

流れ全体を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const { ask } = require(\"./model\");' '' 'const texts = [' '  \"美術室に鉛筆を12本送ってください。急ぎではありません。\",' '  \"今日中に、チョークを3箱お願いします。できるだけ急ぎです。\",' '  \"職員室はどこにありますか。\",' '];' '// 記録済みサンプル。モデルが答えないときだけ使う。きれいな返事、修復が1回要る返事、' '// 依頼のないメッセージ (却下される)。' 'const samples = [' '  JSON.stringify({ item: \"鉛筆\", quantity: 12, urgent: false }),' '  [\"はい、こちらです: \" + JSON.stringify({ item: \"チョーク\", quantity: \"3\", urgent: true }), JSON.stringify({ item: \"チョーク\", quantity: 3, urgent: true })],' '  [JSON.stringify({ item: null, quantity: null, urgent: false }), \"このメッセージには依頼が見つかりません。\"],' '];' > pipeline6.js"

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

流れ全体を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function pullJson(text) {' '  const start = text.indexOf(\"{\");' '  const end = text.lastIndexOf(\"}\");' '  if (start === -1 || end < start) return null;' '  try { return JSON.parse(text.slice(start, end + 1)); } catch (error) { return null; }' '}' '' '// 最初の問題。レコードが良ければ空の文字列。' 'function problemOf(record) {' '  if (record === null) return \"JSON ではない\";' '  if ((typeof record.item === \"string\") === false || record.item === \"\") return \"item が不正\";' '  if (Number.isInteger(record.quantity) === false || record.quantity < 1 || record.quantity > 20) return \"quantity が不正\";' '  if ((typeof record.urgent === \"boolean\") === false) return \"urgent が不正\";' '  return \"\";' '}' >> pipeline6.js"

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

流れ全体を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const PROMPT = \"このメッセージから item、quantity (1から20)、urgent (true か false) を取り出してください。JSON だけで答えてください。\n\nメッセージ: \";' '' 'async function handle(text, sample) {' '  const messages = [{ role: \"user\", content: PROMPT + text }];' '  let reply = await ask(messages, sample, 80);' '  let problem = problemOf(pullJson(reply));' '  if (problem.length > 0) {' '    // 修復を1回: 悪い返事と問題を送り返し、もう1度だけ聞く。' '    messages.push({ role: \"assistant\", content: reply });' '    messages.push({ role: \"user\", content: \"次の問題を直し、JSON だけで答えてください。\" + problem });' '    reply = await ask(messages, sample, 80);' '    problem = problemOf(pullJson(reply));' '  }' '  return { record: pullJson(reply), problem: problem };' '}' >> pipeline6.js"

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

流れ全体を書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const saved = [];' '  const rejected = [];' '  for (let at = 0; at < texts.length; at = at + 1) {' '    const result = await handle(texts[at], samples[at]);' '    if (result.problem.length > 0) rejected.push({ text: texts[at], why: result.problem });' '    else saved.push({ item: result.record.item, quantity: result.record.quantity, urgent: result.record.urgent });' '  }' '  fs.writeFileSync(\"records.json\", JSON.stringify(saved, null, 2));' '  console.log(\"保存: \" + saved.length + \" 件を records.json に書きました\");' '  for (const one of rejected) console.log(\"却下: \" + one.text + \" (\" + one.why + \")\");' '  console.log(\"却下率: \" + Math.floor(rejected.length * 100 / texts.length) + \" パーセント\");' '}' 'main();' >> pipeline6.js"

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

3つのメッセージで実行する

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

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

出力の一例

行表示されるかもしれないもの
記録済みサンプル: ...モデルが答えなかったときだけ、呼び出しごとに1行出る (サンプルでは5行)
保存たとえば、2 件を records.json に書きました
却下職員室のメッセージと、item が不正のような理由
却下率3通のうち1通が却下されたときは、33 パーセント

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

よくある間違い

注意

「却下されたメッセージがあるなら、流れは失敗だ」と考える人が多くいます。依頼のないメッセージを却下するのは正しい動きです。失敗なのは、数えず、理由も残さずに却下することです。

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

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