DifyはAI向けの開発ツールなだけあって、ナレッジベースへのドキュメントの投入、チャンクの分割およびエンべディングの生成など、一通りの作業を開発ツールのUIで実行できます。Dify自体は「Difyプラットフォームに組み込まれたナレッジベース機能とテキスト検索・取得メカニズムには制約があり、検索結果を簡単に変更することができません。」(ドキュメントのここ)と言っていて、高い要求には外部ナレッジベースの連携機能を提供しています。
そのため、Oracle Databaseとの連携という意味では、Oracle Databaseをナレッジベースとして呼び出せる外部連携APIを実装するという手段もあるかとは思います。今回は、手早くテキスト検索とベクトル検索を実装するために、DifyのナレッジベースをAPEXアプリケーションで検索してみます。
Difyの環境は記事「Oracle Database 23ai Freeをベクトル・ストアとしたDifyのローカル環境を作成する」にて紹介している手順で作成しています。DifyおよびOracle Databaseのコンテナは、macOSのpodmanで実行しています。
テキスト・エンべディングのモデルとして、Ollamaのbge-m3:latestを使用するように設定済みとします。
以下よりDifyでナレッジベースを作成して、APEXアプリケーションから検索するまでの作業を紹介します。
最初にDifyでナレッジベースを作成します。
ナレッジタブを開き、ナレッジベースを作成を実行します。
今回はテキストファイルからインポートしてナレッジベースを作成します。
参照をクリックして、アップロードするテキストファイルを選択します。
ファイルを選択したのち、次へ進みます。
APEXアプリケーションから検索できるように、インデックス方法に高品質、検索設定にハイブリッド検索を設定します。エンべディングの生成に使用される埋め込みモデルは、APEXアプリケーションでも使用するモデルになるため、確認しておきます。
検索にハイブリッド検索を設定することにより、エンべディングの生成とOracle Text索引の作成の両方が行われます(実際にはベクトル検索を選んだ時もOracle Text索引が生成されるように見受けられますが、ハイブリッド検索を選んだ方が確実です)。
その他のパラメータは必要に応じて調整します。
保存して処理をクリックします。
チャンクやエンべディングの生成が行われ、ナレッジベースの保管先であるOracle Databaseに保存されます。
ドキュメントに移動します。
アップロードされたドキュメントが利用可能になっていることを確認します。
検索テストを開きます。
チャンクが検索できたら、とりあえずナレッジベースの作成は完了です。
ナレッジベースの保存先になっているOracle Databaseのスキーマで、SQLを実行します。
今回はOracle APEXのワークスペース・スキーマにナレッジベースを保存しているので、SQLの実行にSQLワークショップのSQLコマンドを使用します。
最初に作成されたナレッジベースの表を探します。以下のSELECT文を実行します。
select object_type, object_name, to_char(created,'RR-MM-DD HH24:MI:SS') created from user_objects
where object_type = 'TABLE' and object_name like 'EMBEDDING_VECTOR_INDEX%NODE' order by created desc
ナレッジベースの表の名前は、EMBEDDING_VECTOR_INDEXで始まりNODEで終わるようです。これは現状がこうだった、ということで今後変わる可能性はあります。
この表名を参照してAPEXアプリケーションを作ると、表名が変わった時に面倒なので、ビューとしてDIFY_KB_TESTを作成します。元表の名前は上記のSELECT文で見つけたOBJECT_NAMEで置き換えます。主キー列はID、チャンクが保存されている列はTEXT(この列にOracle Text索引が作成されています)、エンべディングが保存されている列はEMBEDDINGです。
create or replace view dify_kb_test
as
select id, json_value(meta, '$.source') source, text, embedding from
EMBEDDING_VECTOR_INDEX_A6C2A40F_41B4_4D1C_B543_3EF634CC408A_NODE;
エンべディングが保存されている列のVECTOR_INFOを確認します。
select column_name, vector_info from user_tab_cols where table_name = 'DIFY_KB_TEST' and data_type = 'VECTOR'
VECTOR(*,*,DENSE)となっているため、エンべディングの次元数や精度を確認するには、表に保存されているエンべディングを参照する必要があります。
ビューDIFY_KB_TESTより1つだけエンべディングを取り出し、次元数と精度を確認します。
select vector_dimension_count(embedding) count, vector_dimension_format(embedding) format
from dify_kb_test where embedding is not null fetch first 1 rows only;
countが1024、formatがFLOAT64と返されました。APEXアプリケーションで検索文章からエンべディングを生成するときに、この次元数と精度を指定する必要があります。
以上で、Difyのナレッジベースとして作成された表について確認ができました。
これからAPEXでアプリケーションを作成します。
最初にエンべディングを生成するために、Ollamaのbge-m3:latestを呼び出すベクトル・プロバイダを作成します。
データベースに以下のファンクションgenerate_embeddingを作成します。
OllamaのようなローカルLLMをベクトル・プロバイダとする場合はPL/SQLによるカスタム・ファンクションが必要です。ONNXモデル、Oracleの生成AIサービス、OpenAIやCohereであれば、設定だけでベクトル・プロバイダを作成することができます。しかし、Difyがエンべディングを生成する際に選んだ精度とOracle側が選んだ精度が異なる場合は、これらの組み込みのプロバイダでもPL/SQLによるカスタム・ファンクションの作成が必要になるでしょう。
Difyと同じモデルを呼び出せないため、ONNXモデルは対象外になります。
作成したファンクションgenerate_embeddingを呼び出すベクトル・プロバイダを作成します。
共有コンポーネントのベクトル・プロバイダを開きます。
作成済みのベクトル・プロバイダの一覧画面で、作成をクリックします。
プロバイダ・タイプにカスタムPL/SQLを選択します。名前はOllama bge-m3:latest、静的IDはollama_bge_m3_latestとします。
ローカル埋込みのカスタム・ファンクション名に先ほどPL/SQLで作成したファンクションgenerate_embeddingを指定します。
以上で、ベクトル・プロバイダを作成します。
ベクトル・プロバイダとしてOllama bge-m3:latestが作成されました。
アプリケーションが作成されたら、共有コンポーネントの構成の検索(検索構成)を開きます。
作成済みの検索構成が一覧されます。作成をクリックし、新規に検索構成の作成を始めます。
名前はベクトル検索とします。検索タイプにOracleベクトル検索を選択します。
次へ進みます。
ベクトル・プロバイダに先ほど作成したOllama bge-m3:latestを選択します。ソース・タイプは表、表/ビューの名前としてDIFY_KB_TESTを選択します。
次へ進みます。
主キー列にID、ベクトル列にEMBEDDING、タイトル列にSOURCE、説明列にTEXTを選択します。アイコン・ソースにアイコン・クラスを選択し、アイコンCSSクラスにfa-chatbotを指定します。
以上で検索構成の作成をクリックします。
検索構成としてベクトル検索が作成されます。編集画面が開きます。
必須ではありませんが、後から参照しやすいように静的IDをVECTOR_SEARCHに変更します。
変更の適用をクリックします。
検索構成の一覧画面に戻ります。続けてテキスト検索の検索構成を作成します。
名前はテキスト検索とします。検索タイプにOracle Textを選択します。
次へ進みます。
ソース・タイプは表、表/ビューの名前としてDIFY_KB_TESTを選択します。
次へ進みます。
主キー列にID、Oracle Text索引列にTEXT、タイトル列にSOURCE、説明列にTEXTを選択します。アイコン・ソースにアイコン・クラスを選択し、アイコンCSSクラスにfa-fontを指定します。
以上で検索構成の作成をクリックします。
検索構成としてテキスト検索が作成されます。編集画面が開きます。
必須ではありませんが、後から参照しやすいように静的IDをTEXT_SEARCHに変更します。
変更の適用をクリックします。
以上で検索構成としてベクトル検索とテキスト検索が作成されました。
検索ページを作成します。
ページの作成をクリックします。
コンポーネントとして検索ページを選択します。
以上でページの作成をクリックします。
検索ページが作成されます。
今回は検索ができることが確認できるだけで良いので、検索結果のテキスト検索とベクトル検索の双方を選択し、外観の最大結果数を5に制限します。
以上で、ページの保存と実行をクリックします。
検索ページが開かれます。
適当な文章や文字を入力して、ベクトル検索とテキスト検索の双方で検索結果が返されることを確認します。
Difyで全文検索を行った際に以下のエラーが発生しました。
** Resource [93mpunkt_tab[0m not found. Please use the NLTK Downloader to obtain the resource: [31m>>> import nltk >>> nltk.download('punkt_tab') [0m For more information see: https://www.nltk.org/data.html Attempted to load [93mtokenizers/punkt_tab/english/[0m Searched in: - '/root/nltk_data' - '/app/api/.venv/nltk_data' - '/app/api/.venv/share/nltk_data' - '/app/api/.venv/lib/nltk_data' - '/usr/share/nltk_data' - '/usr/local/share/nltk_data' - '/usr/lib/nltk_data' - '/usr/local/lib/nltk_data' **
原因をClaudeに聞いたところ、以下の回答が得られました。
「このエラーは、Difyのナレッジベースでテキスト処理を行う際に、NLTK(Natural Language Toolkit)のpunkt_tabリソースが見つからないために発生しています。」
対処としてコンテナdocker-api-1にpunktにpunkt_tabをインストールしました。
対処としてコンテナdocker-api-1にpunktにpunkt_tabをインストールしました。
% podman exec -it docker-api-1 bash
root@4d7fbfca0440:/app/api# python
Python 3.12.11 (main, Jul 1 2025, 10:08:28) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import nltk; nltk.download('punkt_tab')
[nltk_data] Downloading package punkt_tab to /root/nltk_data...
[nltk_data] Unzipping tokenizers/punkt_tab.zip.
True
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>>
root@4d7fbfca0440:/app/api#
punkt_tabをインストールすると、エラーの発生は解消しました。
今回の記事は以上になります。
単純にこのまま使えるというものではありませんが、少なくても検索はできることが確認できました。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/dify-knowlegebase-search.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完