2024年12月13日金曜日

Oracle Database 23ai Freeをベクトル・ストアとしたDifyのローカル環境を作成する

オープンソースのLLMアプリ開発プラットフォームのDifyをApple MシリーズのMacbook Proにインストールします。インストールにあたって、ベクトル・ストアとしてOracle Database 23ai Freeを構成します。ベクトル検索の確認にはエンべディングの生成が必要ですが、それにはローカルで実行しているOllamaを呼び出します。

ベクトル・ストアにOracle Database 23ai Freeを使用するので、APEXを同居させるとデータベースに保存されているはずの、チャンク分割したテキストやベクトル・データを活用できるかと考えたのですが、かなり難しそうです。

以下より、Difyを動かすまでに行った作業を紹介します。作業を行ったマシンは、M4を積んだApple Macbook Pro、OSはmacOS Sequoia 15.1.1です。

概ね以下のDifyのドキュメントの記載に従って作業を行います。ただし、作業にはdockerの変わりにpodmanを使用します。podman composeを実行する際に外部のcompose providerとしてdocker-composeが呼び出されるように、docker-composeもインストールしておきます。

brewにてpodmanpodman-composeおよびdocker-composeをインストールします。

brew install podman podman-compose docker-compose

私の環境ではすでにインストール済みだったので、そのように報告されました。

% brew install podman podman-compose docker-compose

Warning: podman 5.3.1 is already installed and up-to-date.

To reinstall 5.3.1, run:

  brew reinstall podman

Warning: podman-compose 1.2.0 is already installed and up-to-date.

To reinstall 1.2.0, run:

  brew reinstall podman-compose

Warning: docker-compose 2.31.0 is already installed and up-to-date.

To reinstall 2.31.0, run:

  brew reinstall docker-compose

% 


podmanの構成コマンドは以下になります。CPU数やメモリ量(ディスクサイズはデフォルトで100GB)は、環境に合わせて調整します。

podman machine init
podman machine set --cpus 8 --memory 16384
podman machine ls
podman machine start

Difyをクローンします。

git clone https://github.com/langgenius/dify.git

% git clone https://github.com/langgenius/dify.git

Cloning into 'dify'...

remote: Enumerating objects: 122407, done.

remote: Counting objects: 100% (28860/28860), done.

remote: Compressing objects: 100% (3069/3069), done.

remote: Total 122407 (delta 26233), reused 26359 (delta 25746), pack-reused 93547 (from 1)

Receiving objects: 100% (122407/122407), 73.29 MiB | 14.00 MiB/s, done.

Resolving deltas: 100% (92006/92006), done.

% 


Difyのソース・コードに含まれるdockerのディレクトリへ移動します。

cd dify/docker

% cd dify/docker

docker % ls

README.md docker-compose.middleware.yaml middleware.env.example startupscripts

certbot docker-compose.png nginx volumes

couchbase-server docker-compose.yaml ssrf_proxy

docker % 


構成ファイルとして.envを作成します。雛形の.env.exampleをコピーします。

cp .env.example .env

docker % cp .env.example .env

docker % 


.envの設定を変更します。

私の環境ではpodmanをルートレス・モードで起動しているため、DifyのHTTPポートに80番を使用できません。以下のEXPOSE_NGINX_PORTEXPORT_NGINX_SSL_PORTの番号を変更します。以下ではそれぞれ80848484に変更しています。

# ------------------------------

# Docker Compose Service Expose Host Port Configurations

# ------------------------------

EXPOSE_NGINX_PORT=8084

EXPOSE_NGINX_SSL_PORT=8484


謝辞:EXPOSE_NGINX_PORTについては、Aran NakayamaさんのQiitaの記事を参考にしています。
podmanを使ってDifyをローカルで動かしてみる(Macユーザー向け)

VECTOR_STOREの設定をoracleに変更します。

# ------------------------------

# Vector Database Configuration

# ------------------------------


# 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=oracle


必要であればORACLE_PWDを変更します。これはOracle Database 23ai Freeのコンテナ作成時にオプション-e ORACLE_PWDとして与える値、つまりSYS、SYSTEMのパスワードになります。

# ------------------------------

# Environment Variables for Oracle Service

# (only used when VECTOR_STORE is Oracle)

# ------------------------------

ORACLE_PWD=Dify123456

ORACLE_CHARACTERSET=AL32UTF8


必要であれば、Oracleの構成を変更します。デフォルトではチャンクやベクターを保存するスキーマは、ORACLE_USERに設定されているDIFYになります。

# Oracle configuration, only available when VECTOR_STORE is `oracle`

ORACLE_HOST=oracle

ORACLE_PORT=1521

ORACLE_USER=dify

ORACLE_PASSWORD=dify

ORACLE_DATABASE=FREEPDB1


以上で必要最小限の設定ができました。

Difyの環境の作成と起動を行います。

podman compose up -d

docker % podman compose up -d

>>>> Executing external compose provider "/opt/homebrew/bin/docker-compose". Please see podman-compose(1) for how to disable this message. <<<<


[+] Running 11/11

  Network docker_default             Created                                0.0s 

  Network docker_ssrf_proxy_network  Created                                0.0s 

  Container docker-oracle-1          Started                                0.3s 

  Container docker-web-1             Started                                0.2s 

  Container docker-redis-1           Started                                0.3s 

  Container docker-ssrf_proxy-1      Sta...                                 0.2s 

  Container docker-db-1              Started                                0.2s 

  Container docker-sandbox-1         Starte...                              0.2s 

  Container docker-worker-1          Started                                0.3s 

  Container docker-api-1             Started                                0.3s 

  Container docker-nginx-1           Started                                0.3s 

ynakakoshi@Ns-Macbook docker % 


以上でDifyが起動しました。手元のブラウザから接続します。


初回接続時は、管理者アカウントの作成を求められます。

メールアドレスユーザー名パスワードを入力して、セットアップをクリックします。


直前に入力したメールアドレスパスワードを入力し、サインインします。


サインインできました。


これからベクトル検索ができることを確認します。

今回の作業ではチャット・モデルとしてlucas2024/llama-3-elyza-jp-8b:q5_k_mエンべディング・モデルとしてparaphrase-multilingual:latestを使用します。

Ollamaでこれらのモデルをpullしておきます。

ollama pull paraphrase-multilingual:latest
ollama pull lucas2024/llama-3-elyza-jp-8b:q5_k_m

docker % ollama pull paraphrase-multilingual:latest

pulling manifest 

pulling aa99ebfc77f4... 100% ▕███████████████████████████████████████▏ 562 MB                         

pulling 43070e2d4e53... 100% ▕███████████████████████████████████████▏  11 KB                         

pulling e700587efa15... 100% ▕███████████████████████████████████████▏   16 B                         

pulling 95ef58267922... 100% ▕███████████████████████████████████████▏  411 B                         

verifying sha256 digest 

writing manifest 

success 

docker % ollama pull lucas2024/llama-3-elyza-jp-8b:q5_k_m

pulling manifest 

pulling 1bc7f8f7512b... 100% ▕███████████████████████████████████████▏ 5.7 GB                         

pulling dc3cb4f1d01e... 100% ▕███████████████████████████████████████▏  273 B                         

pulling 0de69c989f89... 100% ▕███████████████████████████████████████▏  150 B                         

pulling fd3131382332... 100% ▕███████████████████████████████████████▏   98 B                         

pulling c0db79732798... 100% ▕███████████████████████████████████████▏  487 B                         

verifying sha256 digest 

writing manifest 

success 

docker % 


ユーザー名のプルダウン・メニューに含まれる設定を開きます。


モデルプロバイダーを開き、Ollamaモデルを追加をクリックします。


Model TypeとしてText Embeddingを選択します。Model Nameparaphrase-multilingual:latestBase URLは(DifyからみるとOllamaはコンテナ外のホストで動作しているため)、http://host.containers.internal:11434を指定します。

以上で保存します。


Ollamaがモデルプロバイダとしても追加されたので、画面の上部に移動しています。

モデルを追加をクリックし、Ollamaをモデルプロバイダとしたチャット・モデルを追加します。


Model TypeLLMを選択し、Model Nameとしてlucas2024/llama-3-elyza-jp-8b:q5_k_mを設定します。Base URLhttp://host.containers.internal:11434です。

Completion ModeChatを選択します。

今回はベクトル検索の確認だけを行うので、このモデルは使用しません。残りの設定はデフォルトのままとします。

以上で保存します。


システムモデル設定をクリックします。


システム推論モデルとしてlucas2024/llama-3-elyza-jp-8b:q5_k_m埋め込みモデルとしてparaphrase-multilingual:latestを設定します。


今ひとつうまく設定ができず、モデルプロバイダーのパネルを閉じたり開いたり、モデルの設定を開いて何も変更せずに保存したりを繰り返す必要がありました。


設定の保存をクリックすると、変更していなくてもOllamaへリクエストが送信されます。


以上でモデルの設定は完了です。

ナレッジを開き、ナレッジを作成します。


データソースの選択としてテキストファイルからのインポートを選択し、適当なファイルを選択します。

へ進みます。


Oracle Database 23ai Freeがベクトル・ストアとして使用されることを確認することが目的なので、パラメータの調整などは省きます。

チャンク設定自動にします。インデックス・モード高品質を選択します。検索設定ベクトル検索を選択します。ベクトル・ストアやシステムモデルが設定されているため、これらはデフォルトで選択されています。

以上で保存して処理をクリックします。


ナレッジが作成されたことを確認し、ドキュメントに移動します。


検索テストを開きます。


ソーステキストベクトル検索と表示されていることを確認します。

ソーステキストとして適当な文章を入力し、テスト中をクリックします。

検索結果パラグラフが表示されることを確認します。


精度の確認はさておき、検索結果パラグラフが表示されていれば、ベクトル検索自体は成功しています。ベクトル・ストアとしてOracle Database 23ai Freeは正しく構成されています。

Difyでの確認作業は以上になります。

作成されたOracle Database 23ai Freeに接続し、スキーマDIFYに作成されたオブジェクトを確認します。データベースのコンテナ名はdocker-oracle-1です。

podman exec -it docker-oracle-1 bash

docker % podman exec -it docker-oracle-1 bash

bash-4.4$ 


デフォルトの設定を変更していなければ、スキーマDIFYのパスワードはdifyです。

sqlplus dify/dify@localhost/freepdb1

bash-4.4$ sqlplus dify/dify@localhost/freepdb1


SQL*Plus: Release 23.0.0.0.0 - Production on Fri Dec 13 09:35:36 2024

Version 23.5.0.24.07


Copyright (c) 1982, 2024, Oracle.  All rights reserved.


Last Successful login time: Fri Dec 13 2024 09:29:00 +00:00


Connected to:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.5.0.24.07


SQL> 


作成されている表を確認します。

select table_name from user_tables order by 1 asc;

SQL> select table_name from user_tables order by 1 asc;


TABLE_NAME

--------------------------------------------------------------------------------

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$B

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$C

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$I

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$K

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$N

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$Q

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE$U

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$B

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$C

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$I

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$K


TABLE_NAME

--------------------------------------------------------------------------------

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$N

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$Q

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE$U

EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE

EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE


16 rows selected.


SQL> 


DR$で始まる表はOracle Textの全文索引を構成する表です。おそらくDifyではベクトル・ストアにオラクルを選択すると、ハイブリッド検索にOracle Text検索を使うように構成されているようです。

全文検索索引の構成を確認してみます。

select index_name, parameters from user_indexes where index_type = 'DOMAIN';

SQL> select index_name, parameters from user_indexes where index_type = 'DOMAIN';


INDEX_NAME

--------------------------------------------------------------------------------

PARAMETERS

--------------------------------------------------------------------------------

IDX_DOCS_EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE

FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP LEXER sys.my_c

hinese_vgram_lexer


IDX_DOCS_EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE

FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP LEXER sys.my_c

hinese_vgram_lexer



SQL>


レクサーが中国語なので、日本で使うには作り直しが必要になるでしょう。しかし、オラクルのVGRAMレクサーは文字が単位だったはずで、AL32UTF8環境であれば中国語も日本語も同じ結果になる気はします。

それ以外の表は列TEXTにチャンク分割された文字列、列METAにJSON形式のメタデータ、列EMBEDDINGにベクトルが保存されています。

SQL> desc EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE

 Name   Null?    Type

 ----------------------------------------- -------- ----------------------------

 ID     VARCHAR2(100)

 TEXT   NOT NULL CLOB

 META     JSON

 EMBEDDING   NOT NULL VECTOR(*, *)


SQL> select count(*) from EMBEDDING_VECTOR_INDEX_1B049961_A438_4D42_8CBE_4D0308B42355_NODE;


  COUNT(*)

----------

21


SQL> desc EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE

 Name   Null?    Type

 ----------------------------------------- -------- ----------------------------

 ID     VARCHAR2(100)

 TEXT   NOT NULL CLOB

 META     JSON

 EMBEDDING   NOT NULL VECTOR(*, *)


SQL> select count(*) from EMBEDDING_VECTOR_INDEX_7570DF07_0C06_4C22_A55D_027C5970124F_NODE;


  COUNT(*)

----------

       139


SQL> 


表名がこのような感じなので、他のアプリケーションから参照するのは難しそうです。

今回の記事は以上になります。