本文へスキップ
BecomeCoder

RAGコース · 第3章 ベクトルと検索 · レッスン11

ミニ・ベクトルストアを作る ― 全件検索とtop-k

ブラウザで完結

導入

ここまでの「ベクトル化」と「類似度計算」を1つにまとめ、文書を貯めておいて質問を投げると上位k件を返してくれる、小さな「ベクトルストア」をクラスとして作ってみましょう。これがRAGの**検索器(retriever)**の正体そのものです。

説明

import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

class MiniVectorStore:
    def __init__(self, docs):
        self.docs = docs
        self.vectorizer = TfidfVectorizer().fit(docs)
        self.matrix = self.vectorizer.transform(docs)

    def search(self, query, k=3):
        q = self.vectorizer.transform([query])
        scores = cosine_similarity(q, self.matrix)[0]
        idx = np.argsort(scores)[::-1][:k]
        return [(self.docs[i], float(scores[i])) for i in idx]

store = MiniVectorStore([
    "Paris is the capital of France.",
    "Tokyo is the capital of Japan.",
    "The Louvre museum is in Paris.",
    "Mount Fuji is near Tokyo.",
    "Python is a programming language.",
])

for doc, score in store.search("famous places in Paris", k=2):
    print(f"{score:.3f}  {doc}")

__init__ でやっているのは、文書を受け取って一度だけベクトル化しておくこと(索引の構築)です。search メソッドが呼ばれるたびに、この索引を毎回作り直す必要はありません。

search の中身は前レッスンとほぼ同じですが、np.argsort(scores) でスコアを小さい順に並べたインデックスを取得し、[::-1] で逆順にして大きい順にし、[:k] で上位k件だけを残しています。これが「top-k検索」と呼ばれる、検索システムの基本パターンです。

実務のRAGシステムでは、ここの TfidfVectorizer の部分を、次のレッスンで紹介する本物の埋め込みモデルに、self.matrix の部分をベクトルDBに置き換えます。仕組みそのものは、このミニ・ベクトルストアと変わりません。

やってみよう

store.search(...)k3 に変えたり、"famous places in Paris""Japan mountains" など別の質問に変えたりして、返ってくる結果がどう変わるか確かめてみましょう。

演習

store.search("python programming", k=2) の結果から、文書の文字列だけ(スコアは表示せず)を print で表示してください。

ヒント1を見る

store.search(...) の戻り値は (文書, スコア) のタプルのリストです。for doc, score in store.search(...): のように受け取れます。

ヒント2を見る

ループの中で print(doc) だけを呼べば、スコアを表示せずに文書だけ出せます。

実際に動かしてみよう

下のエディタにPythonを書いて「実行」を押すと、scikit-learn(TF-IDF)とnumpyで本物の「検索」をその場で動かせます。RAGの検索フェーズ――文書のチャンク分割・ベクトル化・類似度計算・並べ替え――が実際に動きます。scikit-learn を使う回は初回の読み込みに数十秒かかることがあります。検索デモのサンプル文書は英語です(TF-IDFの既定トークナイザが日本語を分割できないため。日本語検索の対処は読み物で解説します)。LLMの生成や本物の埋め込みAPIは、APIキーが要るため読み物の回でコードを示します。

Python — ライブラリ付きで実行(Pyodide)

numpy / pandas / matplotlib が使える本物のPython(Pyodide)を読み込みます。初回のみ読み込みに少し時間がかかります(以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。