はじめに

みなさん、こんにちは。
AI検証チームの宮井です。

前回の記事では、Oracle Database 23ai と Ollama を使って生成AIをローカル環境で動かす基本的な手順を解説しました。
今回はその続きとして、文章をベクトル化し、AIベクトル検索を実施してみました。

前回と同じくOCI Computeサーバ上にインストールしたOllamaを使用し、Base DBから実行する流れです。

以下のマニュアルを参考にしています。
Oracle AI Vector Searchユーザーズ・ガイド

Oracle AI Vector SearchはAIメディアブーストでも利用しています!
AI時代の新WEBマーケティングツール AIメディアブースト

テキスト埋め込みの実施

今回、埋め込みモデルは日本語が利用可能な「nomic-embed-text」を使用してみます。
これは、テキストをベクトル化、ベクトル検索するためのモデルです。

# ollama pull nomic-embed-text

次にOracle Databaseに接続し、まずはテストとして、「hello」という文字をベクトル化してみます。
dbms_vector.utl_to_embedding を使い、ベクトル化を実行します。
すると、ベクトル化できていることが確認できます。

SQL> var embed_ollama_params clob;
SQL> exec :embed_ollama_params := '{"provider": "ollama","host": "local","url": "http://xx.xx.xx.xx:11434/api/embeddings","model": "nomic-embed-text"}';
SQL> select dbms_vector.utl_to_embedding('hello', json(:embed_ollama_params)) ollama_output from dual;
[4.20678049E-001,-1.37839004E-001,-4.11926937E+000,-3.22374135E-001,7.9919827E-0
01,1.05128896E+000,2.91803926E-001,-6.03916347E-002,-3.47645193E-001,-9.23339367
・・以下省略・・

では、実際にベクトル化を試してみます。
以前、以下の記事で試したことと同じように当社サイトキャラクターの名前を尋ねてみます。
そのままだと正しく回答できないと思われるため、ベクトル化したデータを使用して、正しい名前が回答できるか確認していきます。
Oracle Database 23aiのAI Vector SearchでRAGを試してみた!

以下のSQLでベクトル化を実施します。
documentation_tabというテーブルは以前作成したひとりでできるもんの説明文が格納されているため、
そのテーブルのテキストデータをベクトル化していきます。

SQL> CREATE TABLE doc_chunks2 as
  (select dt.id doc_id, et.embed_id, et.embed_data, to_vector(et.embed_vector) embed_vector
   from
     documentation_tab dt,
     dbms_vector_chain.utl_to_embeddings(
         dbms_vector_chain.utl_to_chunks(dbms_vector_chain.utl_to_text(dt.data), json('{"normalize":"all"}')),
         json('{"provider": "ollama","host": "local","url": "http://xx.xx.xx.xx:11434/api/embeddings", "model": "nomic-embed-text"}')) t,
     JSON_TABLE(t.column_value, '$[*]' COLUMNS (embed_id NUMBER PATH '$.embed_id', embed_data VARCHAR2(4000) PATH '$.embed_data', embed_vector CLOB PATH '$.embed_vector')) et
  );

 

これで、準備は整いました。

まずはベクトルデータを利用せず、質問をしてみます。
謎のキャラクターDB(ダビー)が生まれました。正しくありません。。

SQL> set serveroutput on
SQL> declare
  2    input clob;
  3    params clob;
  4    output clob;
  5  begin
  6    input := 'DBひとりでできるもんのキャラクターの名前は何ですか?';
  7    params := '{"provider": "ollama","host"    : "local", "url"     : "http://xx.xx.xx.xx:11434/api/generate", "model"   : "gemma3:4b","transfer_timeout" : "600"}';
  8    
  9    utl_http.set_body_charset('UTF-8');
 10    output := dbms_vector_chain.utl_to_generate_text(input, json(params));
 11    dbms_output.put_line(output);
 12    if output is not null then
 13      dbms_lob.freetemporary(output);
 14    end if;
 15  exception
 16    when OTHERS THEN
 17      DBMS_OUTPUT.PUT_LINE (SQLERRM);
 18      DBMS_OUTPUT.PUT_LINE (SQLCODE);
 19  end;
 20  /
DB(データベース)ひとりでできるもんのキャラクターの名前は、**「DB(ダビー)」**
です。

DBは、コンピューターのシステムを監視するキャラクターで、ちょっとおせっか
いで、いつも何かを「ちゃんとやってる?」と確認してくるのが特徴です。


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

 

次にベクトル検索を実施してみます。
この時点で説明文が取得できていることが確認できます。

SQL> SET SERVEROUTPUT ON;
SQL> VAR prompt CLOB;
SQL> VAR user_question CLOB;
SQL> VAR context CLOB;
SQL> begin
  2     :user_question := 'DBひとりでできるもんに登場するキャラクターの名前は何ですか?';
  3     :context := '';
  4          for rec in (
  5              select embed_data from doc_chunks2
  6              order by vector_distance(embed_vector , (select to_vector(et.embed_vector) embed_vector from dbms_vector_chain.utl_to_embeddings(:user_question,
  7              json('{"provider": "ollama","host"    : "local","url"     : "http://xx.xx.xx.xx:11434/api/embeddings", "model"   : "nomic-embed-text"}')) t, json_table ( t.column_value, '$[*]' columns 
  8              ( embed_id number path '$.embed_id', embed_data varchar2 ( 4000 ) path '$.embed_data', embed_vector clob path '$.embed_vector' ) ) et), cosine)
  9              fetch first 3 rows only
 10          )
 11          loop
 12        :context := :context || rec.embed_data;
 13     end loop;
 14     :prompt := '次のコンテキストを使用して質問に回答してください。 '
 15                || ' コンテキスト : '
 16                || :context;
 17     dbms_output.put_line('Generated prompt: ' || :prompt);
 18  end;
 19  /
Generated prompt: 次のコンテキストを使用して質問に回答してください。
コンテキスト :
でぶちゃんはDBひとりでできるもんに登場するオリジナルのキャラクターです。
デザインのモチーフは、 ●ホットなCloudの帽子 ●3段階の身体はDiskを表現
●ハートのポシェットには、夢と希望と10TBのデータが格納●全体の色合いは当社コーポレ
ートカラー(赤とグレー) です。

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

では、上記の情報をもとに再度質問を行います。
キャラクターの名前を正しく判別できました!
ちょっと回答が気になるので、改良の余地はありそうですね。
渡した説明文も悪かったかもしれませんね。

SQL> set serveroutput on
SQL> declare
  2    input clob;
  3    params clob;
  4    output clob;
  5  begin
  6    input := 'DBひとりでできるもんのキャラクターの名前は何ですか?' || :prompt;
  7    params := '{"provider": "ollama","host"    : "local", "url"     : "http://xx.xx.xx.xx:11434/api/generate", "model"   : "gemma3:4b","transfer_timeout" : "600"}';

  8    
  9    utl_http.set_body_charset('UTF-8');
 10    output := dbms_vector_chain.utl_to_generate_text(input, json(params));
 11    dbms_output.put_line(output);
 12    if output is not null then
 13      dbms_lob.freetemporary(output);
 14    end if;
 15  exception
 16    when OTHERS THEN
 17      DBMS_OUTPUT.PUT_LINE (SQLERRM);
 18      DBMS_OUTPUT.PUT_LINE (SQLCODE);
 19  end;
 20  /
DBひとりでできるもんのキャラクターの名前は、コンテキストからは直接わかりません。
コンテキストには「でぶちゃんはDBひとりでできるもんに登場するオリジナルのキャラク
ターです」と書かれています。

「でぶちゃん」がDBひとりでできるもんのキャラクター
の名前であると推測できます。

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

まとめ

いかがでしたでしょうか?
今回はOllamaを使用してのRAGも実施してみました。
生成AIに関する記事は随時更新予定です。是非次回もご覧ください。

生成AIに関するお問い合わせはこちら

投稿者プロフィール

宮井 聡
宮井 聡
Oracle Database、Oracle Cloud、生成AIに関するエンジニア兼プリセールスなどを担当しています。
社内のOCI検証チームのとりまとめやAI検証チームの技術リーダーをしています。
資格はOracle Cloud Infrastructure Architect Professional 2023等を取得しています。