RAG(Retrieval-Augmented Generation)は、自社ドキュメントや DB のデータを AI に参照させて回答させる技術です。

「ChatGPT は自社の製品情報を知らない」という問題を解決できます。

本記事では Rails + PostgreSQL(pgvector 拡張)+ RubyLLM を使った RAG 実装を解説します。



RAG とは


RAG の流れはシンプルです。


ユーザーの質問
→ 質問をベクトル化(Embedding)
→ DB で類似ドキュメントを検索
→ 検索結果 + 質問を LLM に渡す
→ AI が回答を生成

LLM のファインチューニングが不要で、データを追加・更新するだけで最新情報に対応できます。



pgvector のセットアップ


まず PostgreSQL に pgvector 拡張を追加します。


# Gemfile
gem 'neighbor'
gem 'ruby_llm'

bundle install
bin/rails generate neighbor:vector

ドキュメントテーブルのマイグレーションを作成します。


bin/rails generate migration CreateDocuments title:string content:text

# db/migrate/XXXXXX_create_documents.rb
class CreateDocuments < ActiveRecord::Migration[8.0]
def change
create_table :documents do |t|
t.string :title
t.text :content
t.vector :embedding, limit: 1536 # OpenAI text-embedding-3-small の次元数
t.timestamps
end
add_index :documents, :embedding, using: :ivfflat,
opclass: :vector_l2_ops
end
end

bin/rails db:migrate


モデルに Embedding を組み込む


ドキュメント保存時に自動でベクトルを生成します。


class Document < ApplicationRecord
has_neighbors :embedding

before_save :generate_embedding

private

def generate_embedding
return if content.blank?
result = RubyLLM.embed(content, model: 'text-embedding-3-small')
self.embedding = result.vectors
end
end



ユーザーの質問をベクトル化して、近いドキュメントを取得します。


def find_relevant_docs(query, limit: 3)
query_embedding = RubyLLM.embed(query, model: 'text-embedding-3-small').vectors
Document.nearest_neighbors(:embedding, query_embedding, distance: 'cosine').limit(limit)
end


RAG で回答を生成


取得したドキュメントをコンテキストとして LLM に渡します。


def ask_with_rag(question)
docs = find_relevant_docs(question)
context = docs.map { |d| "#{d.title}:
#{d.content}" }.join("

")

prompt = <<~TEXT
以下の情報を参考に質問に答えてください。

#{context}

質問: #{question}
TEXT

chat = RubyLLM.chat(model: 'claude-sonnet-4-6')
chat.ask(prompt).content
end


まとめ


pgvector + RubyLLM の組み合わせで、完全にオンプレ・自社データで動く AI チャットが実装できます。

ドキュメントを DB に追加するだけで AI の知識が更新されるので、社内 FAQ や製品マニュアルへの Q&A 機能として非常に実用的です。