コンテンツにスキップ
Nibiru docsv0.9.2

RAG プラグイン

テキストをインジェストし、埋め込み、上位K件を取得し、基づいた質問に答える—すべて1つのPHPクラスで行います。

Stable Reading time ~ 1 min Edit on GitHub

RAG プラグインは、製品ビルダーにとって AI モジュールのキーフィーチャーです。これにより、ヘルプドキュメント、エラーログ、Stripe の請求書、カスタマーサポートチケットなど、任意のテキストの山が、大体 4 行の PHP コードで検索可能な知識ベースに変換されます。

use Nibiru\Module\Ai\Ai;
$ai = new Ai();
$rag = $ai->rag('product-help'); / a named collection
$rag->ingestDir(__DIR__ . '/help/'); / walks .md/.txt/.php under help/
$rag->ingestText('FAQ entry…', ['source' => 'faq-12']);
echo $rag->ask('How do I cancel my subscription?');
// → grounded answer, citing chunks like [1] [2] [3]

それだけです。ベクトルデータベースはありません。SDKはありません。Pythonサイドカーもありません。

ingestText / ingestFile / ingestDir
chunk → embed (Ollama nomic-embed-text)
pack vectors → JSON file at cache/rag/<collection>.json
ask(question) → embed question → cosine top-K → chat with chunks as context

ストレージはコレクションごとに1つのJSONファイルです。各チャンクはtextmetadataを含むオブジェクトで、ベクトルはbase64エンコードされたFloat32Arrayです — 各チャンク約3 KBです。約10,000個のチャンクはメモリに十分に収まります。

同じアプリケーション内に任意の数のコレクションを持つことができます。それぞれが独自のJSONファイルを持ちます。これらは[AI]設定から埋め込みモデルとチャットモデルを共有します。

$docs = $ai->rag('docs');
$tickets = $ai->rag('support-tickets');
$logs = $ai->rag('error-logs');
$docs->ingestDir(__DIR__ . '/help/');
$tickets->ingestText($ticket->body, ['ticket_id' => $ticket->id]);
$logs->ingestText($exception->__toString(), ['ts' => time()]);
$rag = $ai->rag('name'); / get/create a named collection
// --- Ingestion ---
$rag->ingestText($text, $metadata = []); / single chunk
$count = $rag->ingestFile('path'); / returns chunks added
$count = $rag->ingestDir('dir', ['md','txt','php']); / recursive
// --- Querying ---
$hits = $rag->search('query', $k = null); / [{score, text, metadata}, ]
$answer = $rag->ask('question', $k = null); / top-K chat call
// --- Maintenance ---
$rag->reset(); / forget everything (deletes file)
$n = $rag->size(); / number of chunks

application/module/ai/settings/ai.ini に:

[AI]
embed.model = "nomic-embed-text" ; or mxbai-embed-large for higher quality
rag.top_k = 6 ; chunks injected into the chat call
rag.chunk_target = 600 ; tokens per chunk (target)
rag.chunk_min = 120 ; smaller chunks merged
rag.chunk_max = 900 ; larger paragraphs split on sentences
rag.storage_path = "/../../application/module/ai/cache/rag/"
  • ヘルプ / FAQ チャット — お手伝い記事をインジェストし、/ask エンドポイントを公開します。
  • アプリ内コード検索application/module/ をインジェストし、「VAT をどこで計算しているのか?」と尋ねます。
  • 内部ドキュメントアシスタント — チームのウィキダンプをインジェストします。
  • 顧客履歴検索 — チケットをインジェストし、「このエラーは以前に見ましたか?」と尋ねます。
  • リアルタイム、書き込みが重いデータ — RAG はスナップショットです。ライブデータの場合、エージェントが呼び出す Tool を作成してください。
  • 大量のコーパス (> 100k チャンク) — JSON ファイルストレージが不十分になります。Qdrant / pgvector / Weaviate に移行します;自分自身が必要になったらアダプターを公開します。
  • 正確な回答が必要な場面、確率的な回答ではなく RAG は確率的です。データベースクエリレイヤーとして使用しないでください。
  • nomic-embed-text がプルされていません。 最初の ingestText 呼び出しは、プルコマンドを指す明確なエラーで失敗します。
  • 埋め込みモデルの不一致です。 nomic-embed-text チャンクと mxbai-embed-large クエリを混在させないでください — 違うベクトル空間です。embed.model を変更する場合は、まず $rag->reset() を実行してください。
  • 古いコレクションです。 ingestDir の再実行は重複を削除しません。reset() を使用してから再インジェストするか、コンテンツハッシュチェックを自分で維持してください。
  • 小さなチャンクです。 約80トークン未満の場合、埋め込みがノイジーになります。デフォルトの rag.chunk_min = 120 は小さな隣接チャンクをマージします。