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

無料レッスン

チャットAPIのメッセージとロール

このレッスンのあとで: 言語モデルの呼び出しが受け取るメッセージのリストを作れる。

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

呼び出しはメッセージのリストを受け取る

言語モデルへのチャット呼び出しは、メッセージのリストを受け取ります。各メッセージには、ロールと文章があります。モデルはリスト全体を読み、次のメッセージを書きます。

これが大切なのは、モデルが呼び出しの間に何も覚えていないからです。覚えているように見えるチャットは、前のメッセージを毎回送り直しているプログラムです。

この課のゴール

メモ

言語モデルの呼び出しが受け取るメッセージのリストを作れる。

キーワード

ことばいみれい
メッセージチャットの一回分:ロールと文章
ロールメッセージを書いた人の役割user
システムメッセージモデルのふるまいを決める指示
履歴前のメッセージ。呼び出しのたびに送り直す
リクエスト本体呼び出しと一緒に送る JSON

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

メッセージはロールと文章

メッセージは、二つのキーを持つオブジェクトです。role は誰の発言かを表し、content は言葉を持ちます。

ロールは三つあります。system は、モデルのふるまいを決めます。user は、人が言ったことです。assistant は、モデルが前に言ったことです。

一回の呼び出しのリクエスト本体

コード: node
{
  "model": "lab",
  "max_tokens": 60,
  "messages": [
    { "role": "system", "content": "一文で短く答えてください。" },
    { "role": "user", "content": "プログラミングの変数とは何ですか。" }
  ]
}

ラボのモデルに呼び出しを送る

コマンド
docker exec -w /home/node/project agent node -e '/* リクエストの本体:モデル名、返答の上限、メッセージのリストです。 */ const body = { model: "lab", max_tokens: 60, messages: [ { role: "system", content: "一文で短く答えてください。" }, { role: "user", content: "プログラミングの変数とは何ですか。" } ] }; (async () => { try { const url = (process.env.AI_URL || "http://ai:4000") + "/v1/chat/completions"; const answer = await fetch(url, { method: "POST", body: JSON.stringify(body), headers: { "content-type": "application/json", authorization: "Bearer lab" } }); if (!answer.ok) throw new Error("HTTP " + answer.status); const data = await answer.json(); console.log("モデルの答え:" + data.choices[0].message.content); } catch (error) { console.log("モデルは答えませんでした(" + error.message + ")。"); console.log("記録済みのサンプル:変数は、プログラムが変えられる値を入れる名前です。"); } })();'

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

モデルは呼び出しの間に何も覚えない

呼び出しは、それぞれ独立しています。モデルが見るのは、その呼び出しのメッセージだけです。

会話を続けるには、プログラムがリストを持ちます。答えが返るたびに、質問と答えを足します。次の呼び出しでは、新しい質問を最後に付けて履歴を送り直します。

補助ファイル lab.js を書く

コマンド
docker exec -w /home/node/project agent node -e 'require("fs").writeFileSync("lab.js", ["// lab.js その1:ラボのモデルへ呼び出しを送る、ただ一つの場所です。", "const base = process.env.AI_URL || \"http://ai:4000\";", "", "async function send(body, timeout) {", "  return fetch(base + \"/v1/chat/completions\", {", "    method: \"POST\",", "    headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },", "    body: JSON.stringify({ model: \"lab\", ...body }),", "    signal: AbortSignal.timeout(timeout || 30000),", "  });", "}"].join("\n") + "\n")'

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

サンプル付きの ask を足す

コマンド
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("lab.js", ["", "// その2:一度たずねます。モデルが答えられなければ、記録済みのサンプルを返します。", "async function ask(body, sample) {", "  try {", "    const answer = await send(body);", "    if (!answer.ok) throw new Error(\"HTTP \" + answer.status);", "    const data = await answer.json();", "    return { label: \"モデルの答え\", text: data.choices[0].message.content, data: data };", "  } catch (error) {", "    return { label: \"記録済みのサンプル\", text: sample, note: error.message };", "  }", "}", "", "module.exports = { send, ask };"].join("\n") + "\n")'

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

履歴ありと、履歴なしでたずねる

コマンド
docker exec -w /home/node/project agent node -e 'const lab = require("./lab.js"); const system = { role: "system", content: "短い一文で答えてください。" }; const history = [ { role: "user", content: "私の名前は健です。" }, { role: "assistant", content: "はじめまして、健さん。" } ]; const question = { role: "user", content: "私の名前は何ですか。" }; (async () => { const withHistory = await lab.ask({ max_tokens: 30, messages: [system, ...history, question] }, "健さんです。"); console.log("履歴あり、" + withHistory.label + ":" + withHistory.text); const without = await lab.ask({ max_tokens: 30, messages: [system, question] }, "お名前はわかりません。"); console.log("履歴なし、" + without.label + ":" + without.text); console.log("各回に送ったメッセージ数:" + [system, ...history, question].length + " と " + [system, question].length); })();'

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

よくある間違い

注意

モデルは前の呼び出しを覚えていると考える人が多くいます。そうではありません。履歴なしの二回目の呼び出しは、名前を知りようがありませんでした。モデルに使わせたいことは、送るメッセージの中に入れてください。

例:各呼び出しが運んだもの

呼び出し送ったメッセージモデルが知り得ること
履歴ありsystem、user、assistant、user(4件)健という名前
履歴なしsystem、user(2件)健については何も知らない

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

メッセージの順序は大切

system メッセージを最初に置きます。その後は、user、assistant、user と交互に続けます。最後のメッセージは user です。モデルが答える相手だからです。

ほとんどのモデル API は、この順序が崩れたリストを断るか、おかしな答えを返します。送る前に、自分のコードで順序を確かめましょう。

さらに:system メッセージを変える

履歴の Run を開き、system の指示を「英語で答えてください」に変えます。もう一度 Run を押してください。

何が変わり、何が変わらなかったかを書きましょう。そして、その指示が送るメッセージの中になければならなかった理由を、一文で言ってください。

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

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