目次
Headless Vector Searchとは
Headless Vector Searchとは、Supabaseが提供するAI x Vectorsカテゴリのサンプルプロジェクトの1つです。
Supabase DocsのAI x Vectorsページ
このプロジェクトを理解することで、SupabaseとOpenAI、GitHub Actionsを組み合わせ、高度な検索システムを比較的簡単に構築する方法を学べます。
また、フロントエンドを持たない「ヘッドレス」な設計になっている点もポイントです。
これらの内容のハンズオンを紹介した後、詳しく解説します。
やってみる
具体的な操作は公式ドキュメントやReadmeにも記載されていますが、英語かつ不足している手順があったので日本語でまとめておきます。
手続き的な内容なので、不要な場合は読み飛ばしてください。
技術スタック
- Supabase: Database, Edge Functions
- OpenAI: Embeddings, Completions
- GitHub Actions: supabase / embeddings-generator
事前準備
Headless Vector Searchと関係のない部分は本記事では割愛します。
- Supabaseのプロジェクトを作成する
- Supabase Cliをインストールする
- OpenAIのAPIキーを取得する
- GitHubリポジトリを作成する
① SupabaseでDatabaseとEdge Functionsを構築する
git clone git@github.com:supabase/headless-vector-search.git
をクローンします。supabase link --project-ref xxx
をプロジェクトルートで実行して、ローカルとSupabaseを紐付けます。
この際に利用するxxx
は、SupabaseのプロジェクトのURLのhttps://xxx.supabase.co
の部分です。supabase db push
を実行して、ローカルのデータベースをSupabaseに反映します。supabase secrets set OPENAI_API_KEY=sk-xxx
を実行して、OpenAIのAPIキーを設定します。supabase functions deploy --no-verify-jwt
を実行して、Edge Functionsをデプロイします。Supabase Dashboard
のProject Settings
>API
>Exposed schemas
にdocs
を追加します。
公開スキーマの設定画面
② GitHub Actionsを実行する
- プロジェクトルートに
docs
ディレクトリを作成し、検索させたいドキュメントをMarkdownまたはMDX形式で配置します。 Supabase Dashboard
のProject Settings
>API
>Project API keys
のService Role
をコピーします。- 自身のGitHubリポジトリのシークレットに
OPENAI_KEY
とSUPABASE_SERVICE_ROLE_KEY
を設定します。 - 自身のGitHubリポジトリにpushします。
- GitHub Actionsが正常に実行され、ドキュメントがSupabaseに保存されていることが確認できればOKです!
Table Editorのテーブルデータ表示画面
③ ベクトル検索をする
以下のShellスクリプトはベクトル検索をするためのものです。
xxx
とyyy
は自身の環境に合わせて変更してください。
QUERY
の質問に対する回答が表示されればOKです。
回答がベクトルデータベースにない場合、Sorry, I don't know how to help with that.
が表示されます。
解説
本プロジェクトのポイント
あっという間でしたが、上記のデモは「ベクトルデータ保存フロー」と「ベクトルデータ検索フロー」の2つで構成されています。
そして、それぞれの処理の流れを整理することで、SupabaseとOpenAI、GitHub Actionsを用いた、ベクトル検索機能の仕組みを理解できます。
それでは、それぞれの処理の流れを解説していきます。
① ベクトルデータ保存フロー
ベクトルデータの保存はとてもシンプルなフローで実装されています。
またGitHub Actionsのembeddings-generator
アクションが全ての処理を行うため、開発者側が意識することはあまりありません。
ベクトルデータが保存されるまでの処理フロー
処理の流れ
embedding-generator
がdocs
ディレクトリのMarkdownファイルを読み込み、OpenAIのEmbeddings APIを呼び出して、ベクトルデータを生成します。- 生成したベクトルデータをSupabaseのデータベースの
page_section
テーブルに保存します。この際、ページレベルの情報はpage
テーブルに保存します。
ポイント: データベースの構造
page
とpage_section
はpage_id
カラムで紐付けられているため、page_section
をベクトル検索することでpage
のデータを取得できるようになっています。
docsスキーマのテーブル定義
② ベクトルデータ検索フロー
こちらは少し複雑なフローになっています。
一つずつ見ていきましょう。
ベクトル検索の結果が返却されるまでの処理フロー
処理の流れ
- curlコマンドで、Edge Functionsの
vector-search
関数を呼び出します。 vector-search
は、質問の内容(文章)を受け取り、OpenAIのEmbeddings APIを呼び出して、ベクトル化します。- 取得したベクトル値を用いて
page_section
テーブルに対してベクトル検索をします。 - 取得したセクション情報とOpenAIのCompletions APIを用いて、自然な文章を生成します。
- 生成した文章をストリーム形式で返却します。
ポイント: ベクトル検索はPostgreSQLで実装されている
処理2のベクトル検索は、Edge FunctionsがPostgreSQLのmatch_page_sections
関数が呼び出すことで実現しています。つまり正確には、match_page_sections
が、page_section
テーブルに対してベクトル検索をしているということです。
さらに言うとmatch_page_sections
は、PostgreSQLの拡張機能pgvector
を用いて、ベクトル検索を実装しています。
以下が、match_page_sections
の実装内容です。とてもシンプルで、生成AIを使えば初心者でも理解できる内容だと思います。
まとめ
SupabaseのAI x Vectorsカテゴリのサンプルプロジェクトである、「Headless Vector Search」を解説しました。
ハンズオンのみの場合、実装内容がブラックボックスなので一見難しそうに見えますが、処理フローさえ理解してしまえば、実装難易度はそこまで高くありません。
Supabaseのベクトル検索の仕組みは、ベンダーロックインがなく非常に便利なので、ぜひ試してみてください!