mcpField
H
how-to-do-offline-recommendations-with-sqlite-and-gemini

how-to-do-offline-recommendations-with-sqlite-and-gemini

github.com/rodydavisデータ・データベース6048 回インストール2 週間前に更新
リポジトリ

how-to-do-offline-recommendations-with-sqlite-and-gemini について

SQLiteのベクトル検索とGeminiで生成した説明文・埋め込みを使い、オフラインで関連コンテンツを推薦する方法を解説します。CMSに推薦機能を加える開発者向けです。

主な機能

  1. 01Geminiによる説明文の生成
  2. 02テキスト埋め込みの作成
  3. 03sqlite-vecでのベクトル保存
  4. 04kNN検索による関連記事の取得
  5. 05コンテンツ変更時のベクトル更新

活用シーン

  1. 01関連するブログ記事の表示
  2. 02訪問ごとのネットワーク呼び出しなしでの推薦

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/rodydavis/skills --skill how-to-do-offline-recommendations-with-sqlite-and-gemini

インストール後、Claude Code で/how-to-do-offline-recommendations-with-sqlite-and-geminiを入力して読み込まれたか確認します。

詳細

SQLite と Gemini を使ったオフラインのレコメンデーション方法

PocketBase のような CMS を使う際、関連コンテンツをレコメンドする仕組みを追加することはよくあります。たとえば、ブログ記事の一覧を用意し、ランダムに選んだ記事や最近閲覧した記事を関連コンテンツとして表示できます。

この手法を初めて知ったのは、Aaron Francis の YouTube チャンネルでした。

テキスト埋め込み

テキスト埋め込み は、テキストのまとまりを数値の配列に変換する方法です。テキストを数学的に表現することで、データベースに簡単に保存し、一般的な関数を使って保存したベクトル間の距離を計算できます。

説明と埋め込みを生成するには、AI Studio の API キー が必要です。

埋め込みを作成するには、まず埋め込みのウィンドウサイズに収まる小さなチャンクを生成する必要があります。たとえば、Gemini を使ってブログ記事の説明を生成 し、その説明をベクトル化してデータベースに保存できます。

新しい埋め込みと説明を生成する必要があるのはコンテンツが変更されたときだけなので、課金コストはコンテンツの変更頻度に抑えられます。

ベクトルの保存

テキスト埋め込みをベクトルとして保存するには、sqlite-vec という実行時に読み込み可能な拡張機能を使って、SQLite データベースに保存できます。SQLite でベクトルを直接クエリする方法について、README にある例を紹介します。

.load ./vec0

create virtual table vec_examples using vec0(
  sample_embedding float[8]
);

-- vectors can be provided as JSON or in a compact binary format
insert into vec_examples(rowid, sample_embedding)
  values
    (1, '[-0.200, 0.250, 0.341, -0.211, 0.645, 0.935, -0.316, -0.924]'),
    (2, '[0.443, -0.501, 0.355, -0.771, 0.707, -0.708, -0.185, 0.362]'),
    (3, '[0.716, -0.927, 0.134, 0.052, -0.669, 0.793, -0.634, -0.162]'),
    (4, '[-0.710, 0.330, 0.656, 0.041, -0.990, 0.726, 0.385, -0.958]');


-- KNN style query
select
  rowid,
  distance
from vec_examples
where sample_embedding match '[0.890, 0.544, 0.825, 0.961, 0.358, 0.0196, 0.521, 0.175]'
order by distance
limit 2;
/*
┌───────┬──────────────────┐
│ rowid │     distance     │
├───────┼──────────────────┤
│ 2     │ 2.38687372207642 │
│ 1     │ 2.38978505134583 │
└───────┴──────────────────┘
*/

あとは、先ほど作成したベクトルをテーブルに保存し、コンテンツの変更に応じて更新できるようにします。

CREATE TABLE posts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  description TEXT.
  embeddings TEXT
);

CREATE VIRTUAL TABLE vec_posts USING vec0(
  id INTEGER PRIMARY KEY,
  embedding float[768]
);

-- Sync vectors
INSERT INTO vec_posts(id, embedding) SELECT id, embeddings FROM posts;

トリガーを設定して最新の状態に保つこともできますが、PocketBase ではイベントフックを使って仮想テーブルを最新の状態に保っています。

レコメンデーションの生成

オフラインでレコメンデーションを生成するには、ブログ記事の 1 つを入力クエリとして使用し、k 近傍法検索(kNN) を使って、関連する記事を N 件取得します。

SELECT
  vec_posts.id as id,
  vec_posts.embedding as embedding,
  posts.title as title,
  posts.description as description,
  posts.slug as slug
FROM vec_posts
INNER JOIN vec_posts.id = posts.id
WHERE embedding match ?
AND k = 6
ORDER BY distance;

現在選択されているブログ記事のベクトルを ? 引数に渡し、一覧からその記事を除外すれば、ベクトルデータベース内で最も近い N 件の関連ブログ記事を取得できます。

結論

これにより、ブログ記事が何回閲覧されても、レコメンデーションのためのネットワーク呼び出しは発生しないため、非常に高いスケーラビリティを実現できます。

実際の動作を確認するには、私のサイトにあるさまざまなブログ記事を開いてみてください。各記事の最後に、生成された説明と関連する記事が表示されます。

コメント