💬

Dify のRAGバックエンドベクトルストアにTiDB Vector Search を設定する

2025/01/07に公開

今日は最近生成AI関連の開発用プラットフォームとして注目を集めているDifyとTiDB Vector Search を連携していきます。

Dify とは

https://dify.ai/
AI開発ツールやプラットフォームで、特にAIアプリケーションや機械学習の開発を支援するサービスです。AIモデルやアプリケーションを簡単に作成、テスト、デプロイできる環境が提供されます。主に以下のような特徴がある可能性があります。
いわゆるローコードツールに分類され、複雑なコードを書かずにAIモデルの開発を行えるようにするため、ユーザーインターフェースで様々な設定が可能になっています。これにより、AIに関する専門的な知識がなくても、基本的なAIシステムの作成ができるようになります。

TiDB Vector Search とは

https://zenn.dev/kameping/articles/13086a865619b3
元々はTiDB Serverless にビルトインされているベクトル検索機能でしたが、TiDB Dedicatedにもその機能が2024年12月に加わっています。最大の特徴はMySQL互換DBにベクトルインデックスが同居しているため、単一のSQLで通常のCRUDデータ操作とベクトル検索を行えることです。

早速やってみる

Difyにはクラウドサービス版とオープンソースコミュニティベースのセルフホストローカル版が存在しています。このうち2025年1月現在、TiDB Vector Search に対応しているのはセルフホストローカル版のみになりますので、そちらを使います。

事前環境準備

  1. Amazon Linux 2023 (外部からアクセス可能なPublicIP付)
    (Difyを起動する場合smallではなくmedium、ストレージは20GB程度を推奨します)
  2. TiDB Serverless Cluster
    この2つの構築方法についてはこの記事では割愛します。

3. Amazon Linux 2023 へ必要モジュールのインストール

まずはgitとdockerをインストールします。(公式手順ではdocker composeを使っていますが、以下の手順では不要です)

sudo dnf install git -y
sudo dnf install docker -y
sudo systemctl start docker

4. TiDB Serverless への接続情報の入手

Serverlessクラスター管理コンソール画面右上からConnectをクリックします。

初回起動時は管理用パスワードが設定されていませんのでGenerate Passwordをクリックしてパスワードを生成します。

次に以下の接続情報を手元にメモしておきます。

5. TiDB Serverless でスキーマの作成

必要なテーブルなどはすべてDify側で自動で作成してくれますが、用いるスキーマだけは作成しておく必要があります。最初からデフォルトでtestが設定されていますので、それを使っても問題ありませんが作成を行い場合SQL Editorで以下を実行します。

CREATE SCHEMA dify;

6. Dify セルフホストローカル版の設定と起動

まずは以下を実行しgitレポジトリから必要モジュールをクローンしておきます。

git clone https://github.com/langgenius/dify.git
cd dify/docker
cp .env.example .env

次に.envを編集します。.envには各連携可能サービスのパラメータが含まれていて長いですが必要なのは以下の部分です。先ほど手元にメモした情報をもとに置き換えます。

<snip>
# The type of vector store to use.
# Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `pgvecto-rs`, `chroma`, `opensearch`, `tidb_vector`, `oracle`, `tencent`, `elasticsearch`, `analyticdb`, `couchbase`, `vikingdb`, `oceanbase`.
VECTOR_STORE=tidb_vector
<snip>
# TiDB vector configurations, only available when VECTOR_STORE is `tidb`
TIDB_VECTOR_HOST=tidb
TIDB_VECTOR_PORT=4000
TIDB_VECTOR_USER=
TIDB_VECTOR_PASSWORD=
TIDB_VECTOR_DATABASE=dify
<snip>

次に各コンテナを起動します。

sudo docker-compose up -d

少し時間がかかりますが以下のような画面が表示されているはずです。

[+] Running 0/8
[+] Running 32/8⠀] Pulling                                                                                                                             3.2s 
[+] Running 61/8                                                                                                                                       8.9s 
[+] Running 67/8                                                                                                                                       8.9s 
 ✔ redis Pulled                                                                                                                                        8.9s 
 ⠋ worker Pulling                                                                                                                                     65.0s 
 ⠋ api [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 957.6MB / 970.8MB Pulling                                                                                                        65.0s 
 ✔ db Pulled                                                                                                                                          14.5s 
 ✔ ssrf_proxy Pulled                                                                                                                                  37.5s 
 ✔ sandbox Pulled                                                                                                                                     45.2s 
 ✔ web Pulled                                                                                                                                         33.9s 
 ✔ nginx Pulled

完了したらsudo docker psを実行すると以下のように8個コンテナが起動していることがわかります。

CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS                             PORTS                                                                      NAMES
e183bc521ae2   nginx:latest                     "sh -c 'cp /docker-e…"   26 seconds ago   Up 23 seconds                      0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   docker-nginx-1
2aec7f206fdc   langgenius/dify-api:0.14.2       "/bin/bash /entrypoi…"   27 seconds ago   Up 24 seconds                      5001/tcp                                                                   docker-api-1
1b9b658e4ebd   langgenius/dify-api:0.14.2       "/bin/bash /entrypoi…"   27 seconds ago   Up 24 seconds                      5001/tcp                                                                   docker-worker-1
30bd8060537f   langgenius/dify-web:0.14.2       "/bin/sh ./entrypoin…"   28 seconds ago   Up 25 seconds                      3000/tcp                                                                   docker-web-1
300d29410647   ubuntu/squid:latest              "sh -c 'cp /docker-e…"   28 seconds ago   Up 25 seconds                      3128/tcp                                                                   docker-ssrf_proxy-1
2e181c8a7b78   langgenius/dify-sandbox:0.2.10   "/main"                  28 seconds ago   Up 25 seconds (health: starting)                                                                              docker-sandbox-1
0df507cef173   postgres:15-alpine               "docker-entrypoint.s…"   28 seconds ago   Up 25 seconds (healthy)            5432/tcp                                                                   docker-db-1
0a1db73e78c3   redis:6-alpine                   "docker-entrypoint.s…"   28 seconds ago   Up 25 seconds (health: starting)   6379/tcp                                                                   docker-redis-1

7. Difyへのアクセスと初期設定

ブラウザでEC2のパブリックIPアドレスにアクセスすると以下のように初期の管理者登録画面で表示されます。

登録が完了した後、再度ID/パスワードを入力してログインします。

ログインが完了すると以下のようにDify管理コンソールのトップページが表示されます。

8.ナレッジの作成

次にナレッジを作成します。ナレッジとはRAGでいうAIモデルが外部の情報源から情報を取得し、その情報を基に回答を生成する仕組みにおける外部知識やデータを指します。つまりここに検索対象文章がチャンクという単位に分割されベクトル化された値が保存されます。当然そのベクトル化された値の保存先はTiDB Serverless Vector Searchになります。
ナレッジナレッジの作成をクリックします。

検索対象の文章を設定します。

今日は以下のサイトのPDFを使います。
https://www.ppc.go.jp/personalinfo/legal/

チャンクの設定をします。デフォルト(自動)では500文字ですが少し長すぎるので250で設定します。

オーバーラップとは

チャンク間のオーバーラップは、複数のチャンクが同じ文字を重複して含むことを示します。特定の情報が重要な文脈で複数のチャンクに含まれ、より正確に検索結果を取得するために役立つため、RAGでは一般的にある程度の重複をさせます。

次に埋め込み(チャンクに分割された文章をベクトルに変換)用モデルの指定を行いますが、高品質を選択します。高品質を選択した場合、外部生成AIモデルの指定が可能となりデータストアも指定されたものが利用されます。一方経済的を指定した場合あらかじめDifyが持っているものが使われます。すなわち経済的を指定した場合 TiDB Serverless Vector Searchは使われないことに注意してください。

個々の記事ではOpenAIを使います。OpenAI API用キーの取得方法は割愛しますが、以下のURLから取得可能です。

https://platform.openai.com/settings/organization/general
API Baseは空欄で問題ありません。
OpenAIが設定できたら、次に埋め込みモデルを選びます。

保存するとPDFの埋め込み処理(チャンクに文章を分解してベクトル化しVector Searchへ保存する処理)が開始されます。

本来の次のStepはDifyの画面からアプリケーションの開発ですが、実際は開発せずにモデルだけを試すことが可能です。

TiDB のSQLEditorでベクトル化されたデータが書き込まれていることがわかります。

このテスト検索で表示されるのはチャンク化された文字列のみで、本来のRAGはこの情報をもとに生成AIモデルを用いて自然な日本語が出力されます。この記事ではVector Searchとの連携方法に主眼を置いていますので実際のチャットボットはまた別の記事とします。

参考ブログ

https://pingcap.co.jp/blog/dify-tidb-build-scalable-ai-agent-with-knowledge-base/
https://zenn.dev/bohnen/articles/6a1969b5f17b8e

Discussion