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

無料レッスン

文章からデータを取り出す方法

このレッスンのあとで: 値を作り出さずに、段落を1つのレコードにできる。

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

誰も教えていない電話番号

文章からレコードを取り出すとは、モデルに段落を読ませて、決まった項目を埋めてもらうことです。「推測するな」と伝えないと、モデルは空欄を推測で埋めてしまうからです。

大学の事務室に、名前、教室、日付はあるが、電話番号のない教室の依頼が届きます。ところが、ツールは電話番号を表示します。誰も教えていません。モデルが作り出したのです。

このレッスンのゴール

メモ

値を作り出さずに、段落を1つのレコードにできる。

キーワード

ことばいみれい
取り出す文章から、名前のある事実を抜き出すこと
項目レコードの中の、名前のある1つの事実date
null項目がないことを表す値
元の文章事実の出どころになる段落
裏付けがある元の文章で見つかり、推測ではないこと
埋まり具合値が入っている項目の割合

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

項目を決めて、null を許す

ほしい項目と、各項目の型を、正確に伝えます。そのあと、事実が文章にないときの扱いを伝えます。null にして、推測しない、ということです。

この決まりがないと、モデルはすべての項目を埋めることがあります。埋まったレコードは、良い答えに見えるからです。空欄を残してよい、と許可してください。

例: 1通のメッセージ、5つの項目

項目メッセージにあるか正しい値
nameある:「田中さくらです」田中さくら
roomある:「教室 B12」B12
dateある:「2026-11-20」2026-11-20
studentsある:「学生24人」24
phoneないnull

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

すべての値に裏付けがあるか確かめる

プロンプトだけを信じてはいけません。返事のあとで、各値を元の文章と照らし合わせます。値が文章になければ、作り出された値とみなし、null にします。

この確認は簡単で、弱点があります。たとえば学生の数が 2 と間違っていても、2 は 2026-11-20 の中にあるので、残ってしまいます。もっと細かい確認は、語全体を比べます。それでも、作り出された電話番号は見つかります。

モデル用の補助を書く(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 { ask } = require(\"./model\");' '' 'const source = \"こんにちは、田中さくらです。2026-11-20 に教室 B12 を借りたいです。学生24人と教員3人で使います。返事はメールでお願いします。\";' 'const fields = [\"name\", \"room\", \"date\", \"students\", \"phone\"];' '' '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; }' '}' > extract4.js"

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

取り出すスクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// 値は、元の文章に本当にあるときだけ採用します。' 'function grounded(record, source, fields) {' '  const result = {};' '  for (const name of fields) {' '    const value = record === null ? null : record[name];' '    if (value === null || value === undefined || value === \"\") {' '      result[name] = null;' '      console.log(name + \": null (ない)\");' '    } else if (source.toLowerCase().includes(String(value).toLowerCase())) {' '      result[name] = value;' '      console.log(name + \": \" + value + \" (採用)\");' '    } else {' '      result[name] = null;' '      console.log(name + \": \" + value + \" (文章にないので外した)\");' '    }' '  }' '  return result;' '}' >> extract4.js"

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

取り出すスクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const prompt = \"次のメッセージから、キー name (文字列)、room (文字列)、date (文字列、年-月-日)、students (整数)、phone (文字列) を持つ JSON オブジェクトを取り出してください。メッセージにない項目は null にしてください。推測してはいけません。JSON だけで答えてください。\n\nメッセージ: \" + source;' '// 記録済みサンプル。モデルが答えないときだけ使う。わざと電話番号を作り出してある。' 'const sample = JSON.stringify({ name: \"田中さくら\", room: \"B12\", date: \"2026-11-20\", students: 24, phone: \"090-1234-5678\" });' >> extract4.js"

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

取り出すスクリプトを書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const reply = await ask([{ role: \"user\", content: prompt }], sample, 150);' '  const record = grounded(pullJson(reply), source, fields);' '  let filled = 0;' '  for (const name of fields) {' '    if (record[name] === null) continue;' '    filled = filled + 1;' '  }' '  console.log(\"埋まった項目: \" + filled + \" / \" + fields.length);' '}' 'main();' >> extract4.js"

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

取り出しを実行する

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

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

出力の一例

行表示されるかもしれないもの
記録済みサンプル: ...モデルが答えなかったときだけ、1行目に出る
name、room、date、students値と (採用) が付く
phonenull (ない)、または (文章にないので外した) が付いた値
埋まった項目モデルが4つの事実だけを見つけたときは、4 / 5

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

よくある間違い

注意

「埋まった項目は、空の項目より良い」と考える人が多くいます。作り出された値は本物に見え、誰も確かめようとしません。null は、人が見る必要があると、はっきり伝えます。

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

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