はじめに
RAGとは、LLMが外部のデータベースへ問い合わせを行い、それを元に回答を行うことで回答の精度を向上させる技術です。LLM本体が持たないドメインの知識を外部データベースで補足することができます
以前は、外部のデータベースを作成するため、必要な情報(データ)を集めてから、チャンク化(トークン制限未満の塊に分割),ベクトル化(意味が近い言葉を検索しやすくするために数値化),ベクトルデータベースへの保存といった複雑な準備が必要でした
ところが2024年末ころ、ChatGPT本体でRAG(File search)を利用できるようになったため、複雑な準備をすることなくRAGを利用できるようになりました
そこで、簡単なサンプルプログラムを作ってみます
必要なライブラリのインストール
OpenAI Node API Libraryをインストールします
npm i openai, dotenv
環境変数の設定
.envファイルに、OpenAIのAPIキーと、ベクトルストアのid(後述)を設定します
OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VECTOR_STORE_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ベクトルストへの登録サンプル
参照用ファイル(markdown形式)を./docディレクトリに入れておきます
- doc/ ディレクトリにあるファイルをベクトルストアにアップロードします
- 完了後に表示される ベクトルストアのid を.envに記載します
/**
* upload-vector-store.js
* Response APIで参照するドキュメント群をベクトルストアにアップロードする
* - docs/ 以下にMarkdownファイルを用意しておくこと
*/
import 'dotenv/config';
import OpenAI from "openai";
import fs from "fs";
import fsp from "fs/promises";
import path from "path";
const client = new OpenAI();
const DOC_DIR = "./docs";
// ベクトルストアの新規作成
const vs = await client.vectorStores.create({ name: "product-manuals" });
// docs/ 以下のMarkdownファイルをすべてアップロード
const entries = (await fsp.readdir(DOC_DIR)).filter((f) => /\.md$/i.test(f));
// File/Blob/ReadableStream 形式で渡す必要がある(文字列は不可)
const files = entries.map((name) => fs.createReadStream(path.join(DOC_DIR, name)));
await client.vectorStores.fileBatches.uploadAndPoll(vs.id, { files });
/* アップロード完了後、ベクトルストアIDを表示(Responses APIで利用するため.envなどに設定しておく) */
console.log(`VECTOR_STORE_ID=${vs.id}`);
ベクトルストアを利用した問い合わせサンプル
-
toolsに、file_searchを指定することで、ベクトルストアを参照しながら回答を行ってくれます
import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Responses API のレスポンスからテキスト部分を安全に抽出するヘルパー
const extractText = (response) => {
return (response.output || [])
.map(item => {
if (!item || !item.content) return "";
return item.content.map(c => c.text || "").join("");
})
.join("\n");
};
/**
* Responses API + File search を呼び出す最小サンプル
*/
async function main() {
try {
const response = await client.responses.create({
model: "gpt-5-mini",
input: [
{ role: "system", content: "あなたは自社サービスのユーザーサポート担当です。可能な場合はマニュアルのurlを回答の最期に記載してください。" },
{ role: "user", content: "ユーザー登録をするには?" },
],
// マニュアルを参照して回答するため、ベクトルストアから情報を取得する
tools: [{
type: "file_search" ,
vector_store_ids: [process.env.VECTOR_STORE_ID],
max_num_results: 2,
}],
});
// レスポンスからテキスト部分を抽出
const text = extractText(response);
console.log("Response:\n", text);
} catch (err) {
console.error("Error:", err);
process.exit(1);
}
}
main();