2024年12月13日金曜日

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

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

2025年7月14日追記 - Dify 1.6.0を使用した手順に更新しました。

ベクトル・ストアとして、すでにAPEX向けに作成したワークスペース・スキーマを使用します。DifyのDocker Composeはデフォルトで、Oracle Database 23ai Freeのコンテナを新規作成します。docker-compose.yamlのoracleprofilesの設定をoracleからoracle-skipへ変更することにより、すでに作成済みのスキーマへの接続に切り替えることができます。

謝辞:oracle-skipの設定については、以下の記事を参考にしています。
DifyでOracle Base Database Service(23ai)を利用する設定手順

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

概ね以下の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

==> Downloading https://formulae.brew.sh/api/formula.jws.json

==> Downloading https://formulae.brew.sh/api/cask.jws.json

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

To reinstall 5.5.2, run:

  brew reinstall podman

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

To reinstall 1.5.0, run:

  brew reinstall podman-compose

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

To reinstall 2.38.2, 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: 184984, done.

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

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

remote: Total 184984 (delta 966), reused 683 (delta 669), pack-reused 183776 (from 4)

Receiving objects: 100% (184984/184984), 101.73 MiB | 7.09 MiB/s, done.

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

% 


Difyのリポジトリに含まれるdockerのディレクトリへ移動します。

cd dify/docker

% cd dify/docker

docker % ls

certbot elasticsearch ssrf_proxy

couchbase-server generate_docker_compose startupscripts

docker-compose-template.yaml middleware.env.example tidb

docker-compose.middleware.yaml nginx volumes

docker-compose.png pgvector

docker-compose.yaml README.md

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`, `oracle`, `tencent`, `elasticsearch`, `elasticsearch-ja`, `analyticdb`, `couchbase`, `vikingdb`, `oceanbase`, `opengauss`, `tablestore`,`vastbase`,`tidb`,`tidb_on_qdrant`,`baidu`,`lindorm`,`huawei_cloud`,`upstash`, `matrixone`.

VECTOR_STORE=oracle


Oracle Databaseへの接続先を設定します。

ORACLE_USERに接続先となるデータベース・ユーザー名ORACLE_PASSWORDに、その接続先ユーザーのパスワードを設定します。接続先となるOracle Databaseはホスト・ポートの1521で接続の待ち受けを行なっているので、ORACLE_DSNの設定はhost.containers.internal:1521/FREEPDB1になります。

ORACLE_IS_AUTONOMOUSはデフォルトでfalseになっています。ORACLE_CONFIG_DIRORACLE_WALLET_LOCATIONORACLE_WALLET_PASSWORDは接続先データベースとしてAutonomous Databaseを選択したときに意味を持つ設定と思われるため、そのままの設定にしています。

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

ORACLE_USER=<接続するデータベース・ユーザー>

ORACLE_PASSWORD=<ORACLE_USERのパスワード>

ORACLE_DSN=host.containers.internal:1521/FREEPDB1

ORACLE_CONFIG_DIR=/app/api/storage/wallet

ORACLE_WALLET_LOCATION=/app/api/storage/wallet

ORACLE_WALLET_PASSWORD=dify

ORACLE_IS_AUTONOMOUS=false 


docker-compose.yamlを開き、profilesの設定でoracleとなっている箇所をoracle-skipに変更します。

  # Oracle vector database

  oracle:

    image: container-registry.oracle.com/database/free:latest

    profiles:

      - oracle-skip

    restart: always

    volumes:

      - source: oradata

        type: volume

        target: /opt/oracle/oradata

      - ./startupscripts:/opt/oracle/scripts/startup

    environment:

      ORACLE_PWD: ${ORACLE_PWD:-Dify123456}

      ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}


接続先となるデータベース・ユーザーに、最低限必要な権限を与えます。

grant db_developer_role to <接続先データベース・ユーザー>;
grant execute on ctx_ddl to <接続先データベース・ユーザー>;

以下の例では、接続先データベース・ユーザーはWKSP_APEXDEVになっています。

docker % sql sys/*********@localhost/freepdb1 as sysdba



SQLcl: 月 7月 14 12:36:11 2025のリリース25.2 Production


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


接続先:

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

Version 23.8.0.25.04


SQL> grant db_developer_role to wksp_apexdev;


Grantが正常に実行されました。


SQL> grant execute on ctx_ddl to wksp_apexdev;


Grantが正常に実行されました。


SQL> exit

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

Version 23.8.0.25.04から切断されました

docker % 


接続先データベース・ユーザーで接続し、Oracle Textのレクサーをworld_lexerという名前で作成します。実際のレクサーは言語に応じて選択します。以下ではJAPANESE_LEXERを選択しています。
begin
    ctx_ddl.create_preference(
        preference_name => 'world_lexer',
        object_name => 'JAPANESE_LEXER'
    );
end;
/

docker % sql wksp_apexdev/********@localhost/freepdb1



SQLcl: 月 7月 14 12:46:02 2025のリリース25.2 Production


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


接続先:

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

Version 23.8.0.25.04


SQL> begin

  2      ctx_ddl.create_preference(

  3          preference_name => 'world_lexer',

  4          object_name => 'JAPANESE_LEXER'

  5      );

  6  end;

  7* /


PL/SQLプロシージャが正常に完了しました。


SQL> exit

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

Version 23.8.0.25.04から切断されました

docker % 


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

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-web-1             Started                                                                  0.2s 

  Container docker-redis-1           Started                                                                  0.2s 

  Container docker-sandbox-1         Started                                                                  0.2s 

  Container docker-db-1              Healthy                                                                  4.7s 

  Container docker-ssrf_proxy-1      Started                                                                  0.1s 

  Container docker-api-1             Started                                                                  4.7s 

  Container docker-plugin_daemon-1   Started                                                                  4.7s 

  Container docker-worker-1          Started                                                                  4.8s 

  Container docker-nginx-1           Started                                                                  4.8s 

docker % 


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


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

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


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


サインインできました。


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

今回の作業ではチャット・モデルとしてqwen3:8bエンべディング・モデルとしてbge-m3:latestを使用します。

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

ollama pull bge-m3:latest
ollama pull qwen3:8b


 % ollama pull bge-m3:latest

pulling manifest 

pulling daec91ffb5dd: 100% ▕██████████████████▏ 1.2 GB                         

pulling a406579cd136: 100% ▕██████████████████▏ 1.1 KB                         

pulling 0c4c9c2a325f: 100% ▕██████████████████▏  337 B                         

verifying sha256 digest 

writing manifest 

success 

% ollama pull qwen3:8b

pulling manifest 

pulling a3de86cd1c13: 100% ▕██████████████████▏ 5.2 GB                         

pulling ae370d884f10: 100% ▕██████████████████▏ 1.7 KB                         

pulling d18a5cc71b84: 100% ▕██████████████████▏  11 KB                         

pulling cff3f395ef37: 100% ▕██████████████████▏  120 B                         

pulling 05a61d37b084: 100% ▕██████████████████▏  487 B                         

verifying sha256 digest 

writing manifest 

success 

% 


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


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


Ollamaのプラグインをインストールします。


プラグインとしてOllamaが追加されます。Ollamaにモデルを追加します。


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

以上で保存します。


続けて、チャット・モデルを追加します。先ほどと同様にモデルを追加をクリックします。

Model TypeLLMを選択し、Model Nameとしてqwen3:8bを設定します。Base URLhttp://host.containers.internal:11434です。

Completion ModeChatを選択します。

今回はベクトル検索の確認だけを行うので、このモデルは使用しません。

以上で保存します。


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


システム推論モデルとしてqwen3:8b埋め込みモデルとしてbge-m3:latestを設定します。

以上を設定し、保存します。


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

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


データソースの選択としてテキストファイルからのインポートを選択し、とりあえず空のナレッジベースを作成します


ナレッジベースの名称testとします。作成をクリックします。


ナレッジベースtestが作成されます。

ファイルを追加します。


ナレッジベースに登録するファイルを選択します。

へ進みます。


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

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

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


ナレッジベースにドキュメントがアップロードされたことを確認し、ドキュメントに移動します。


検索テストを開きます。


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

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

取得したチャンクが表示されることを確認します。


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

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

Oracle Database 23ai Freeに接続し、 接続先スキーマに作成されたオブジェクトを確認します。SQLclを使います。

sql <接続先データベース・ユーザー>/<パスワード>@localhost/freepdb1

docker % sql wksp_apexdev/*******@localhost/freepdb1



SQLcl: 月 7月 14 13:33:03 2025のリリース25.2 Production


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


接続先:

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

Version 23.8.0.25.04


SQL> 


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

select table_name from user_tables where table_name like '%EMBEDDING_VECTOR_INDEX%';

SQL> select table_name from user_tables where table_name like '%EMBEDDING_VECTOR_INDEX%';


TABLE_NAME                                                                        

_________________________________________________________________________________ 

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$I    

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$K    

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$U    

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$Q    

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$C    

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$B    

EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE                  

DR$IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE$N    


8行が選択されました。 


SQL> 


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

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

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

Oracle Text索引のレクサーとしてworld lexerが使用されていることが確認できます。

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


INDEX_NAME                                                                   PARAMETERS                                                                             

____________________________________________________________________________ ______________________________________________________________________________________ 

IDX_DOCS_EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE    FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP LEXER world_lexer    


SQL> 


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

SQL> desc EMBEDDING_VECTOR_INDEX_95FE2D6B_BFCB_460F_8269_41FD2588CBA3_NODE


名前           Nullかどうか    タイプ                  

____________ ___________ ____________________ 

ID                       VARCHAR2(100)        

TEXT         NOT NULL    CLOB                 

META                     JSON                 

EMBEDDING    NOT NULL    VECTOR(*,*,DENSE)    

SQL> 


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