04. 継続会話の基礎

この資料は 2025 年 11 月時点での田中正吾の雑感として書いたものです。あくまでもハッカソンでザっと AI の連携を作れるようにするために、動かして進められるような説明用の資料とサンプル群を用意した次第です。

ワンショット(1回の質問・回答)から継続会話(複数ターン)へステップアップしましょう。

学べること

  • メッセージ履歴の管理方法
  • ユーザーとアシスタント両方のメッセージを保存する重要性
  • 過去の文脈を参照した会話の実現
  • システムメッセージによる役割設定
  • トークン数の増加への対処

準備するもの

  • Node.js (v18 以上)
  • OpenAI API キー
  • 02 と 03 の理解

セットアップ

サンプルコードは本教材の Codespace(リンク集を参照)の 04_conversational-basics/ にあります。

フォルダ移動

まず、ターミナルに表示されているカレントディレクトリ(現在の作業フォルダ)を確認しましょう。

  • /workspaces/hackathon-ai-and-mcp-sample-202511-codespace/ の場合は、以下のコマンドでフォルダ移動します。
cd 04_conversational-basics
  • 続けて 03 から勉強している場合は、カレントディレクトリが /workspaces/hackathon-ai-and-mcp-sample-202511-codespace/03_function-calling で一つ階層が深いので、以下のコマンドでフォルダ移動します。
cd ../04_conversational-basics

手元の Visual Studio Code で作業されている方は、現在作業中のカレントディレクトリを確認いただいて上記を参考にフォルダを移動しましょう。

※フォルダ移動について詳しくは「Codespace でのフォルダ移動」を参照してください。

インストール

カレントディレクトリの移動が確認できたら、関連ライブラリをインストールして準備します。

npm install

これ以降はこのカレントフォルダでコマンドを打って作業していきましょう。

API キーの設定

各サンプルファイルの先頭にある API キー設定箇所を、お使いの OpenAI API キーに書き換えてください。

01_simple-conversation.js の場合:

// OpenAI API キー
const OPENAI_API_KEY = "ここにあなたのAPIキーを入力";

02_conversation-with-context.js の場合:

// OpenAI API キー
const OPENAI_API_KEY = "ここにあなたのAPIキーを入力";

サンプル一覧

シンプルな継続会話

ファイル: 01_simple-conversation.js

node 01_simple-conversation.js

最もシンプルな継続会話の実装例です。3ターンの会話を通じて、メッセージ履歴の管理方法を学びます。

学べること:

  • messages 配列による会話履歴の管理
  • ユーザーとアシスタント両方のメッセージを保存する重要性
  • 過去の文脈を参照した会話の実現

文脈を保持した会話

ファイル: 02_conversation-with-context.js

node 02_conversation-with-context.js

実践的な会話シナリオ(レストラン予約)を通じて、文脈を保持した自然な対話を実装します。

学べること:

  • システムメッセージによる役割設定
  • 会話関数の抽象化(再利用可能なパターン)
  • 複数ターンにわたる情報の蓄積と参照
  • トークン数の増加に対する注意点

大切な考え方

メッセージ履歴の管理

継続会話を実現するには、会話の履歴全体を保持し、毎回 API に送信する必要があります。

const messages = [];

// ユーザーの発言を追加
messages.push({ role: "user", content: "こんにちは" });

// API に履歴全体を送信
const completion = await openai.chat.completions.create({
  messages: messages,  // ← 履歴全体
  model: "gpt-4o-mini"
});

// アシスタントの返答も履歴に追加(重要!)
messages.push({
  role: "assistant",
  content: completion.choices[0].message.content
});

ポイント:

  • messages 配列に会話履歴を保存
  • API 呼び出しのときに履歴全体を送信
  • アシスタントの返答もかならず履歴に追加

メッセージの役割(role)

  • system: AI の振る舞いや役割を定義
  • user: ユーザーの発言
  • assistant: AI の返答

システムメッセージの例:

messages.push({
  role: "system",
  content: "あなたは親切なレストラン予約アシスタントです。"
});

システムメッセージは、AI の応答スタイルや役割を設定するのに使います。

トークン数への配慮

会話が長くなるほど、毎回送信するトークン数が増加します。

長い会話では以下のような対策もあります:

  • 古いメッセージの削除
  • 会話の要約
  • Prompt Caching の活用

ハッカソンでは、適度な長さの会話を想定すれば大丈夫です。まずは動かしてみて、必要に応じて調整していきましょう。

ワンショットとの違い

02_api-basics(ワンショット)

// 毎回新しい会話
const completion = await openai.chat.completions.create({
  messages: [
    { role: "user", content: "質問" }  // ← 1回きり
  ],
  model: "gpt-4o-mini"
});

毎回独立した質問・回答です。前の会話は覚えていません。

04_conversational-basics(継続会話)

// 履歴を保持
const messages = [];
messages.push({ role: "user", content: "1回目の質問" });
// ... API 呼び出し、返答を messages に追加 ...

messages.push({ role: "user", content: "2回目の質問" });
// ... API 呼び出し(履歴全体を送る) ...

会話履歴を保持することで、文脈を理解した応答が可能になります。

コードの説明

基本的な実装パターン

const OpenAI = require("openai");

const OPENAI_API_KEY = "your-api-key";
const openai = new OpenAI({ apiKey: OPENAI_API_KEY });

// 会話履歴を保持する配列
const messages = [];

// システムメッセージ(オプション)
messages.push({
  role: "system",
  content: "あなたは親切なアシスタントです。"
});

// 1回目の会話
messages.push({ role: "user", content: "こんにちは" });
let completion = await openai.chat.completions.create({
  messages: messages,
  model: "gpt-4o-mini",
});
messages.push(completion.choices[0].message);

// 2回目の会話(履歴を参照できる)
messages.push({ role: "user", content: "私の名前は覚えていますか?" });
completion = await openai.chat.completions.create({
  messages: messages,
  model: "gpt-4o-mini",
});
messages.push(completion.choices[0].message);

このパターンを繰り返すことで、長い会話を実現できます。

よくあるパターン

アシスタントの返答も履歴に追加

AI の返答も messages に追加することで、AI が自分の発言を覚えられるようになります。

// よくある書き方:AI の返答を追加していない
messages.push({ role: "user", content: "質問" });
await openai.chat.completions.create({ messages, model: "gpt-4o-mini" });
// → 次のターンで AI は自分が何を言ったか覚えていない

// 推奨される書き方:AI の返答も追加
messages.push({ role: "user", content: "質問" });
const completion = await openai.chat.completions.create({ messages, model: "gpt-4o-mini" });
messages.push(completion.choices[0].message);
// → AI が過去の会話を参照できる

システムメッセージは最初に設定

システムメッセージは、会話の最初に設定するのが一般的です。

const messages = [
  { role: "system", content: "あなたは〜です。" },
];

// その後にユーザーの発言を追加
messages.push({ role: "user", content: "..." });

会話のリセット

会話をリセットしたい場合は、messages 配列を空にします。

messages.length = 0;  // 会話履歴をクリア

または、新しい配列を作成します。

const messages = [];  // 新しい会話を開始

次のステップ

継続会話の仕組みがわかってきたでしょうか。次は標準入力を使って、実際にユーザーと会話できるアプリケーションを作ってみましょう。