RAG+DB化 設計指示書
既存のAIチャットボットを、登録した本文を根拠に回答するRAGチャットボットへ改造するための指示書です。
すでに完成している既存のAIチャットボットを改造して、「登録した本文を根拠に答えるRAGチャットボット」にしてください。
目的は、生徒が仕組みを学べる最小構成です。ログイン、ユーザー管理、権限管理、複雑な記事管理画面は作らないでください。画面上でIDを入力・表示・管理する必要もありません。
【前提の確認:まず最初にやること】
- 現在のプロジェクト構成(言語・フレームワーク・ディレクトリ・既存ファイル)を確認する
- どのファイルを追加・変更するかを短く示してから実装に入る
- この指示書はPHPを前提に書いていますが、現在の環境がPHPでない場合(Node.js、Python、Nextjsなど)は、無理にPHPへ寄せず、その環境の作法に合わせて同じ構成を実装し直してください。テーブル定義・処理の流れ・実装ルールの考え方はそのまま流用できます
【残すもの】
- 現在の質問用チャット画面と既存のAI API接続は残す
- 利用者の質問にAIが回答する基本UIは壊さない
- 現在使っているAIモデルやAPI接続方式は、必要がない限り変更しない
【追加するもの】
1. SQLiteデータベース
- SQLiteのDBファイルを、Webから直接アクセスできない安全な場所に置く
- 外部キーを有効にする
- 以下の5テーブルを作成する
categories:
- id, name, description, parent_id, created_at, updated_at
articles:
- id, title, content, summary, category_id, created_at, updated_at
keywords:
- id, name, created_at
article_keywords:
- article_id, keyword_id
article_chunks:
- id, article_id, chunk_no, content, embedding_json, created_at
- article_chunksには、本文を分割したチャンク本文、順番、埋め込みベクトルを保存する
- 記事を削除したら、その記事のチャンクと関連情報も削除されるようにする
2. 「知識を教える」画面
- 新しいページを追加する
- 入力項目は最低限、タイトルと本文だけにする
- 本文を貼り付けて「教える」ボタンを押すと、次を自動実行する
1. articlesへ元の本文を保存する
2. 本文を日本語で自然な区切りを優先しつつ、おおむね500〜1,000文字ごとに分割する
3. 各チャンクを埋め込みAPIでベクトル化する
4. article_chunksへ、チャンク本文・順番・ベクトルを保存する
- 成功時は「この内容を教えました。チャットで質問できます。」と表示する
- エラー時は、原因を日本語で分かるように表示する
- 生徒用なのでログイン機能は付けない
3. 質問時のRAG検索
- チャットで質問が送られたら、その質問を同じ埋め込みモデルでベクトル化する
- 保存済みarticle_chunksのベクトルと類似度を比較する
- 類似度が高い上位3〜5件のチャンク本文だけを、既存のAIへの指示文に「参照資料」として追加する
- AIには、参照資料に根拠がある内容を優先して回答させる
- 参照資料に答えがない場合は、知識にないことを正直に伝えるようにする
- 回答画面は、現在のチャットUIを維持する
4. チャット画面の導線
- 既存のチャット画面の上部など、見つけやすい場所に「知識を教える」というリンクまたはボタンを追加する
- クリックすると新しい「知識を教える」画面へ移動する
- 教える画面にも「チャットに戻る」リンクを追加する
- この導線はログイン不要で誰でも使えるようにする
【実装ルール】
- CSSとJavaScriptはHTMLに直書きせず、外部ファイルに分ける
- 共通の処理や関数は共通ファイルにまとめ、重複させない(PHPならinclude、Node/Pythonならモジュール)
- APIキーはブラウザのJavaScriptや公開ディレクトリに置かず、サーバー側だけで使う
- SQLは必ずプリペアドステートメント(プレースホルダ)を使い、文字列連結でSQLを組み立てない
- 既存ファイルを壊さないよう、変更前に構成を確認する
- 実装後は、本文登録、チャンク保存、質問時の類似検索、チャット回答、画面リンクのすべてを動作確認する
【つまずきやすい点。あらかじめ考慮してください】
- 埋め込みモデルは、登録時と検索時で必ず同じものを使う。違うモデルのベクトルを比較しても意味のある結果になりません
- 類似度はコサイン類似度で計算する。ベクトルの正規化の有無を登録時と検索時で揃える
- 件数が増えると全件比較は重くなります。まずは全件比較で構いませんが、目安として数千チャンクを超えたら別の方法が必要になる、と理解しておいてください
- 埋め込みAPIは、長すぎる入力や空文字で失敗します。分割後のチャンクが空でないこと、極端に長くないことを確認してから送る
- 日本語の分割は句点や改行を優先し、単語の途中で切らないようにする
- 埋め込みAPIの呼び出しは失敗することがあります。失敗した場合はその記事の登録全体をなかったことにするか、どこまで成功したかが分かるようにする
- SQLiteはファイルなので、書き込み権限と同時アクセスに注意する
- ベクトルをJSONで保存する場合、取り出したあと必ず数値配列に戻してから計算する
- 参照資料をAIに渡す際、長すぎるとトークン上限に当たります。上位数件に絞り、必要なら各チャンクを短く切る
【この指示書について】
これは学習用の制作サンプルです。環境は人によって異なるため、ここに書いた通りに進めてうまくいかない場合は、エラーの内容を読んで、その環境に合う形へ読み替えて構いません。仕様を厳密に守ることより、仕組みを理解して動く状態にすることを優先してください。
お使いのAIコーディング環境(Claude Code、Codex、Cursorなど)にそのまま貼り付けてください。PHP以外の環境でも動くよう、読み替えの指示を含めてあります。あくまで学習用の制作サンプルなので、環境によってはそのまま通らないことがあります。その場合はエラーを読んで調整してください。