~/tools / 埋め込みと検索(RAG) / RAG Prompt Builder
RAG Prompt Builder — 出典付きで答える RAG のリクエストを作る
検索結果と質問から、Ollama の /api/chat へのリクエストを作ります。モデルに、番号付きの出典だけをもとに答え、それを引用するよう求めます。オプションで、各引用に出典番号と引用文を付けたJSONを求め、temperature を 0 にし、"truncate": false を送って、収まらないプロンプトを切り詰めずに失敗させます。入力した内容はブラウザの外に出ません。
例の出典は、json_agg が返す形に合わせて手で書いたものです。
出典3件をオブジェクトのJSON配列として読み取りました。
curl コマンド
このマシン上の Ollama(localhost:11434)にリクエストを送ります。
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5:7b",
"messages": [
{
"role": "system",
"content": "Answer the question using only the numbered sources in the user message. Cite the number of each source you use. If the sources do not contain the answer, say that you do not know and cite nothing. Answer in the same language as the question. For each citation, give the source number and copy a short quote from that source exactly as it is written. Return JSON that matches this schema: {\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"},\"citations\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"source\":{\"type\":\"integer\"},\"quote\":{\"type\":\"string\"}},\"required\":[\"source\",\"quote\"]}}},\"required\":[\"answer\",\"citations\"]}"
},
{
"role": "user",
"content": "Sources:\n\n[1] (id: 12)\nWith HNSW, hnsw.ef_search is 40 by default, so a query returns at most 40 rows unless you raise it.\n\n[2] (id: 7)\nSET LOCAL inside a transaction changes hnsw.ef_search for a single query.\n\n[3] (id: 3)\npgvector supports PostgreSQL 13 and later.\n\nQuestion: Why does my HNSW search return only 40 rows with LIMIT 100?"
}
],
"stream": false,
"format": {
"type": "object",
"properties": {
"answer": {
"type": "string"
},
"citations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"source": {
"type": "integer"
},
"quote": {
"type": "string"
}
},
"required": [
"source",
"quote"
]
}
}
},
"required": [
"answer",
"citations"
]
},
"options": {
"temperature": 0
},
"truncate": false
}'リクエストボディ(JSON)
{
"model": "qwen2.5:7b",
"messages": [
{
"role": "system",
"content": "Answer the question using only the numbered sources in the user message. Cite the number of each source you use. If the sources do not contain the answer, say that you do not know and cite nothing. Answer in the same language as the question. For each citation, give the source number and copy a short quote from that source exactly as it is written. Return JSON that matches this schema: {\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"},\"citations\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"source\":{\"type\":\"integer\"},\"quote\":{\"type\":\"string\"}},\"required\":[\"source\",\"quote\"]}}},\"required\":[\"answer\",\"citations\"]}"
},
{
"role": "user",
"content": "Sources:\n\n[1] (id: 12)\nWith HNSW, hnsw.ef_search is 40 by default, so a query returns at most 40 rows unless you raise it.\n\n[2] (id: 7)\nSET LOCAL inside a transaction changes hnsw.ef_search for a single query.\n\n[3] (id: 3)\npgvector supports PostgreSQL 13 and later.\n\nQuestion: Why does my HNSW search return only 40 rows with LIMIT 100?"
}
],
"stream": false,
"format": {
"type": "object",
"properties": {
"answer": {
"type": "string"
},
"citations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"source": {
"type": "integer"
},
"quote": {
"type": "string"
}
},
"required": [
"source",
"quote"
]
}
}
},
"required": [
"answer",
"citations"
]
},
"options": {
"temperature": 0
},
"truncate": false
}レスポンスでは、回答は message.content にあります。prompt_eval_count が思っていたよりかなり少ない場合は、プロンプトが切り詰められた可能性があります。
リクエストのフィールドは Ollama のAPIリファレンスとソースコードで、2026-11-05に Ollama 0.40.11 で確認しました。 Ollama API: /api/chat
すべてブラウザの中で処理されます。ツールはリクエストを書くだけで、どこにも接続しません。
検索拡張生成(RAG)では、まず自分の文書を検索し、いちばん近い部分を質問と一緒にモデルに渡します。このツールは、そのための Ollama の /api/chat のリクエストを書きます。検索結果は、文字列のJSON配列、オブジェクトのJSON配列(たとえば PostgreSQL の json_agg の出力。テキストは content、text、chunk、document、page_content から読み、id、title、url は出典の見出しに加えられます)、または --- の行か空行で区切ったテキストとして貼り付けます。ツールは出典に [1] から番号を付け、ルールを system メッセージに、出典と質問をこの順で1つの user メッセージに入れます。JSONオプションを選ぶと、format フィールドに回答と引用のリスト(出典番号と引用文)を持つ JSON Schema が入り、Ollama の構造化出力のページが勧めているとおり、同じスキーマが system メッセージにも書かれます。選ばない場合は、各文のあとに番号を角括弧で書くようモデルに求めます。truncate オプションが大事なのは、Ollama が長いプロンプトをエラーなしで切り詰めるからです。Ollama のソースコード(0.40.11)では、先頭の数トークンとプロンプトの末尾を残してその間を捨てます。num_ctx 1024 で行った私たちのテストでは、これで system メッセージと最初の出典が失われ、答えが変わりました。truncate フィールドは Ollama のソースコードにあり、/api/chat のページにはありません。"truncate": false を付けると、同じリクエストは代わりにHTTP 400を返しました。このツールのリクエストは、どちらのモードでも qwen2.5:7b を使って Ollama 0.40.11 に送りました。
このツールの計算部分は、オープンソース(MIT ライセンス)で公開しています。 github.com/seigo5555/toolkitbox-lib/src/rag-prompt.ts
こんな時に使う
- 手元のマニュアルやメモについての質問に、ローカルのモデルで、各文の出典を付けて答える
- アプリケーションのコードを書く前に、実際の検索結果を少し使って、プロンプトと引用の形式を試す
- 検索結果がモデルのコンテキスト長に収まるかどうかを調べる
使い方
- 質問を入力し、検索結果を貼り付けます。たとえば pgvector SQL Builder のクエリが返した行です。
- モデルを選び、必要なら num_ctx と、JSONの引用、temperature 0、truncate のオプションを選びます。
- curl コマンドか JSON ボディをコピーして Ollama に送ります。回答と同じ出典を RAG Citation Checker に貼り付けます。
FAQ
データベースの id ではなく、番号を付けるのはなぜですか?
短い番号のほうがモデルにとって長い id よりも写しやすく、送ったリストと照らして確認できます。各オブジェクトの id、title、url も番号の隣に表示されるので、番号を元の行に戻せます。
質問が出典のあとに来るのはなぜですか?
プロンプトがコンテキスト長より長いと、Ollama はプロンプトの末尾を残してそれより前のテキストを捨てるので、末尾にある質問は残る部分になります。それでも "truncate": false を送るほうが安全で、エラーになるので、送る行を減らすか num_ctx を上げられます。
出典はいくつまで送れますか?
ツールは50まで受け付けます。いくつ収まるかは出典の長さとコンテキスト長によります。Ollama のドキュメントでは、VRAMが24 GiB未満の場合のデフォルトは4kトークンです。レスポンスの prompt_eval_count フィールドで、プロンプトが使ったトークン数がわかります。
JSONオプションを使えば、引用は必ず正しくなりますか?
いいえ。format フィールドで回答は JSON Schema に従いますが、モデルが誤った出典を引用したり、その出典にないものを引用したりすることはあります。回答は RAG Citation Checker で確認してください。
OpenAI 互換のAPIでも使えますか?
このツールが書くのは、ネイティブの /api/chat のリクエストです。Ollama のドキュメントによると、構造化出力は OpenAI 互換のAPIでも response_format で使えますが、リクエストの形は異なります。
データはどこかに送られますか?
いいえ。リクエストはブラウザの中で作られます。ツールが Ollama に接続することはありません。