Oracle Database 23ai FreeとAPEXでRAGを使った生成AIアプリをローコード開発してみた (事前準備編)

[先日Oracle Database 23aiがGAになりました。](https://blogs.oracle.com/database/post/oracle-23ai-now-generally-available)
23aiには目玉機能として「AI Vector Search」が追加され、Oracle Database上でベクトル型データ、およびベクトル検索を扱えるようになっています。
これにより生成AIの活用において、Oracle Databaseを使ったRAGの実装が可能となっています。
(RAGについて簡単に補足しますと、生成AIに社内ドキュメントなどの付加情報を連携し、それら情報を使った回答を生成させる手法です。
その実装にはベクトルデータ、ベクトル検索が重要な技術要素となっています。)

せっかく23aiがGAになったので、早速23aiを使ったRAG対応の生成AIアプリを作ってみました。
アプリ作成にはOracle Database上で使える、無償のローコード開発プラットフォームの「APEX」を使いました。

なお23aiの提供形態としてはオンプレ向けにはFree版が出ています。
今回は23ai Freeを活用して実装しました。

ちなみに本記事ではアプリ実装前の事前準備のみを扱います。
アプリ実装編は別途まとめますが、完成イメージは以下の通りです。
![WS000010.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33182/2cb37e74-c3ba-c461-bf83-1d2828486eb1.jpeg)
![WS000009.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33182/992fa08a-4059-ab50-7e7f-6f2eeabe325b.jpeg)
※RAGの画面に表示されている情報は架空のものです。

こちらはPDFやOfficeファイルなど、任意のファイルをアップロードしてRAGに使えるアプリです。
メタデータ情報を使った、ベクトル検索前のフィルタリングにも対応しています。

またアプリのexportファイルを以下に置いています。
https://github.com/mago1chi/apex/blob/main/ragapp_cohere.sql
今回のアプリ実装は作業数が多いため、すぐに動くものを見たい方は上記ファイルをご自分のAPEX環境にimportしてお試しください。
その場合でも、以下記事の作業は事前に行う必要がありますのでご注意ください。
+ 本記事の作業全体
+ [Oracle Database 23ai FreeとAPEXでRAGを使った生成AIアプリをローコード開発してみた (アプリ実装 前編)](https://qiita.com/ssfujita/items/c53579bbb3eed4145942)
    - ｢ワークスペースの作成」までを実施します。
+ [Oracle Database 23ai FreeとAPEXでRAGを使った生成AIアプリをローコード開発してみた (アプリ実装 後編)](https://qiita.com/ssfujita/items/53df4f342e28c238a5a2)
    - ｢Web資格証明の設定」までを実施します。

## 環境情報

+ VM: OCI上の VM.Standard.E4.Flex (1 OCPU、メモリ 16GB)
+ OS: Oracle Linux 8.9
+ DB: Oracle Database 23ai Free
+ AP: Oracle APEX 23.2
+ LLM: Cohere Command R+
+ Embedding:
    - Cohere embed-multilingual-v3.0
    - ONNX (google-bert/bert-base-multilingual-cased)

Embeddingは主にCohereの embed-multilingual-v3.0 を使いましたが、
参考までにDB内でEmbeddingができるONNXを使った方法も記載予定です。
Oracle DatabaseではONNXフォーマットでexportされたモデルをimportし、DB内でEmbeddingできるようになっています。

また23ai Freeには以下の制約があります。
+ フォアグラウンド・プロセスが利用出来るCPU: 2 CPUs
+ メモリ: 2GB RAM (SGA + PGA)
+ ユーザデータで使える容量: 12GB

Cohereのモデル利用は無償のTrialキーを使いました。

## Oracle Database 23ai Freeインストール

インストール手順は下記マニュアルを参考にしました。
[Installing Oracle Database Free](https://docs.oracle.com/en/database/oracle/oracle-database/23/xeinl/installing-oracle-database-free.html#GUID-46EA860A-AAC4-453F-8EEE-42CC55A4FAD5)

RPMをダウンロードしてインストールします。

```bash
$ sudo su -

## プリインストールRPMを使ってOS設定
$ dnf -y install oracle-database-preinstall-23ai

## 本体RPMをダウンロード＆インストール
$ wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm
$ dnf install -y oracle-database-free*
```

DBを作成します。
SYS、SYSTEMのパスワードを入力すると、あとは自動で作成されます。

```bash
$ /etc/init.d/oracle-free-23ai configure

Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:
Confirm the password:
Configuring Oracle Listener.
Listener configuration succeeded.
Configuring Oracle Database FREE.
Enter SYS user password: 
************* **
Enter SYSTEM user password: 
************* **
Enter PDBADMIN User Password: 
************* ***
Prepare for db operation
7% complete
...(略)...
Running Custom Scripts
100% complete
Database creation complete. For details check the logfiles at:
 /opt/oracle/cfgtoollogs/dbca/FREE.
Database Information:
Global Database Name:FREE
System Identifier(SID):FREE
Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details.

Connect to Oracle Database using one of the connect strings:
     Pluggable database: 23aif/FREEPDB1
     Multitenant container database: 23aif
```

oracleユーザになり、環境変数を設定します。

```bash
$ sudo su - oracle
$ vim .bashrc
## 以下を追記
## export ORACLE_SID=FREE
## export ORACLE_BASE=/opt/oracle
## export ORACLE_HOME=/opt/oracle/product/23ai/dbhomeFree
## export PATH=$PATH:$ORACLE_HOME/bin

$ . ~/.bashrc
```

ログインできるか確認します。

```bash
$ sqlplus / as sysdba

SQL*Plus: Release 23.0.0.0.0 - Production on Fri May 3 07:25:44 2024
Version 23.4.0.24.05

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


Connected to:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05

SQL> show pdbs

    CON_ID CON_NAME  OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
 2 PDB$SEED  READ ONLY  NO
 3 FREEPDB1  READ WRITE NO
SQL> 
SQL> set tab off
SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 FREEPDB1                       READ WRITE NO
```

## APEXインストール

手順は下記ブログを参考にしました。
https://apexugj.blogspot.com/2022/11/building-oracle-apex-environment-05-apex.html

最新のAPEXをダウンロードして解凍します。

```bash
$ curl -OL https://download.oracle.com/otn_software/apex/apex-latest.zip
$ unzip apex-latest.zip 
```

APEXの静的ファイルを配置するディレクトリを作成し、必要なファイルをコピーします。
23.2より最新のバージョンを利用する際は、コピー先ディレクトリ名を適宜変更してください。

```bash
$ mkdir i
$ cp -r -p apex/images i/23.2.0
```

解凍したディレクトリに移動し、インストール用に言語設定した上でSYSとしてDBログインします。

```bash
$ cd apex
$ export NLS_LANG=American_America.AL32UTF8
$ sqlplus / as sysdba
```

PDB (FREEPDB1) に移動し、APEXインストール用スクリプトを実行します。
インストール先にSYSAUX表領域を、一時表領域にTEMPを指定しています。
またイメージなどの静的ファイルを配置するディレクトリを最後に指定しています。

```sql
SQL> alter session set container=freepdb1;
SQL> @apexins SYSAUX SYSAUX TEMP /i/23.2.0/
...(略)...
Thank you for installing Oracle APEX 23.2.0

Oracle APEX is installed in the APEX_230200 schema.

The structure of the link to the Oracle APEX administration services is as follows:
http://host:port/ords/apex_admin

The structure of the link to the Oracle APEX development interface is as follows:
http://host:port/ords


timing for: Phase 3 (Switch)
Elapsed:    0.17


timing for: Complete Installation
Elapsed:    5.33
```

APEXを日本語対応させるために、日本語リソースをインストールします。

```sql
SQL> @load_trans JAPANESE
```

パスワードを入力し、APEX管理ユーザを設定します。
ここで作成した管理ユーザでワークスペースの作成や編集を行います。

```sql
SQL> @apxchpwd
```

最後に後述するORDSの利用に必要な APEX_PUBLIC_USER をアンロックします。

```sql
SQL> ALTER USER APEX_PUBLIC_USER NO AUTHENTICATION ACCOUNT UNLOCK;
```

## ORDSインストール

手順は下記ブログを参考にしました。
http://apexugj.blogspot.com/2022/11/building-oracle-apex-environment-06-ords.html

APEXの管理画面にブラウザでアクセスするには、Oracle REST Data Services (ORDS) のインストールが必要です。
まずはインターネット経由でAPEXにアクセスできるよう、ファイアウォールを設定します。
今回はoracleユーザでアプリをホストするため、well-known portである80や443ポートを別のポートへフォワードします。

```bash
sudo su -
## https通信を許可
firewall-cmd --add-service=https
## http通信を許可
firewall-cmd --add-service=http
## 443ポートへの通信を8443にフォワード
firewall-cmd --add-forward-port=port=443:proto=tcp:toport=8443
## 80ポートへの通信を8080にフォワード
firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080
## 設定保存
firewall-cmd --runtime-to-permanent
## 設定リロード
firewall-cmd --reload
## 内容確認
firewall-cmd --list-all
```

ORDSの稼働にはJavaの実行環境が必要なので、JDKをインストールします。
ORDSは JDK 11 もしくは 17 に対応しています。

```bash
## RPMダウンロード
$ curl -OL https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
## RPMインストール
$ dnf -y localinstall jdk-17_linux-x64_bin.rpm
## Javaバージョン確認
$ java -version

java version "17.0.11" 2024-04-16 LTS
Java(TM) SE Runtime Environment (build 17.0.11+7-LTS-207)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.11+7-LTS-207, mixed mode, sharing)
```

ORDS本体をインストールします。

```bash
dnf -y --repofrompath ol8_oracle_software,http://yum.oracle.com/repo/OracleLinux/OL8/oracle/software/x86_64 install ords
```

ORDSのセットアップを行います。
設定ファイルは `/etc/ords/config` に配置します。
無事にセットアップが完了すると、ORDSが起動状態となります。
その場合プロンプトは返ってきません。

```bash
$ su - oracle
$ export PATH=/usr/local/bin:$PATH
$ cd /etc/ords/config

## いくつか聞かれた項目に入力していきます。
## 間違えると修正が面倒だった気がするので、下記ログを参考に対応してください。
$ ords install

Oracle REST Data Services - Interactive Install

  Enter a number to select the database connection type to use
    [1] Basic (host name, port, service name)
    [2] TNS (TNS alias, TNS directory)
    [3] Custom database URL
  Choose [1]:
  Enter the database host name [localhost]:
  Enter the database listen port [1521]:
  Enter the database service name [orcl]: freepdb1
  Provide database user name with administrator privileges.
    Enter the administrator username: sys
  Enter the database password for SYS AS SYSDBA:

Retrieving information.
ORDS is not installed in the database. ORDS installation is required.

  Enter a number to update the value or select option A to Accept and Continue
    [1] Connection Type: Basic
    [2] Basic Connection: HOST=localhost PORT=1521 SERVICE_NAME=freepdb1
           Administrator User: SYS AS SYSDBA
    [3] Database password for ORDS runtime user (ORDS_PUBLIC_USER): <generate>
    [4] ORDS runtime user and schema tablespaces:  Default: SYSAUX Temporary TEMP
    [5] Additional Feature: Database Actions
    [6] Configure and start ORDS in Standalone Mode: Yes
    [7]    Protocol: HTTP
    [8]       HTTP Port: 8080
    [9]   APEX static resources location:
    [A] Accept and Continue - Create configuration and Install ORDS in the database
    [Q] Quit - Do not proceed. No changes
  Choose [A]: 9
  Enter the APEX static resources location: /home/oracle/i
  Enter a number to update the value or select option A to Accept and Continue
    [1] Connection Type: Basic
    [2] Basic Connection: HOST=localhost PORT=1521 SERVICE_NAME=freepdb1
           Administrator User: SYS AS SYSDBA
    [3] Database password for ORDS runtime user (ORDS_PUBLIC_USER): <generate>
    [4] ORDS runtime user and schema tablespaces:  Default: SYSAUX Temporary TEMP
    [5] Additional Feature: Database Actions
    [6] Configure and start ORDS in Standalone Mode: Yes
    [7]    Protocol: HTTP
    [8]       HTTP Port: 8080
    [9]   APEX static resources location: /home/oracle/i
    [A] Accept and Continue - Create configuration and Install ORDS in the database
    [Q] Quit - Do not proceed. No changes
  Choose [A]:
...(略)...
2024-05-03T07:58:51.957Z INFO        Oracle REST Data Services initialized
Oracle REST Data Services version : 24.1.0.r1080942
Oracle REST Data Services server info: jetty/10.0.20
Oracle REST Data Services java info: Java HotSpot(TM) 64-Bit Server VM 17.0.11+7-LTS-207
```

これでAPEXの管理画面に以下URLよりアクセスできます。
http://your_public_ip

アクセスすると以下のようにORDSのトップ画面が表示されます。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33182/fb86efea-6e79-f95a-362c-cca90b712fcd.jpeg)
Oracle APEXの「実行」ボタンを押下すると、APEX管理のログイン画面へ遷移します。
![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33182/ad0329b9-e460-b5aa-4f36-d76cae431f9a.jpeg)

最後にORDSの自動起動を設定しておきます。

```bash
sudo su -
systemctl enable ords
systemctl stop ords
systemctl start ords
```

## アプリに使うスキーマの作成

FREEPDB1にログインし、SYSユーザで実施します。
まずは表領域を作成します。

```sql
SQ> CREATE BIGFILE TABLESPACE tbs2
DATAFILE 'bigtbs_f2.dbf' 
SIZE 1G AUTOEXTEND ON
NEXT 32M MAXSIZE UNLIMITED
EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;

SQL> CREATE UNDO TABLESPACE undots2
 DATAFILE 'undotbs_2a.dbf'
 SIZE 1G AUTOEXTEND ON
 RETENTION GUARANTEE;

SQL> CREATE TEMPORARY TABLESPACE temp_demo
TEMPFILE 'temp02.dbf' SIZE 1G REUSE AUTOEXTEND ON
NEXT 32M MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M;
```

DBユーザ「vector」を作成し、必要な権限を付与します。

```sql
SQL> CREATE USER vector IDENTIFIED BY vector
DEFAULT TABLESPACE tbs2 
QUOTA UNLIMITED ON tbs2;

SQL> GRANT DB_DEVELOPER_ROLE to vector;
SQL> GRANT ctxapp, create credential to vector;
SQL> GRANT create mining model TO vector;
```

REAT API実行に必要なネットワークACLを設定します。

```sql
SQL> BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
 host => '*',
 ace => xs$ace_type(privilege_list => xs$name_list('connect'),
 principal_name => 'vector',
 principal_type => xs_acl.ptype_db));
END;
/

SQL> BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
 host => '*',
 ace => xs$ace_type(privilege_list => xs$name_list('connect'),
 principal_name => 'APEX_230200',
 principal_type => xs_acl.ptype_db));
END;
/
```

(オプション) DB内Embedding (ONNX) を試される場合は、ディレクトリ・オブジェクトを作成します。

```sql
SQL> CREATE OR REPLACE DIRECTORY VEC_DUMP AS '/home/oracle';
SQL> GRANT READ, WRITE ON DIRECTORY VEC_DUMP TO vector;
SQL> COMMIT;
```

tnsnames.oraにサービスを追加します。

```bash
$ vim $ORACLE_HOME/network/admin/tnsnames.ora
FREEPDB1 =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = your_host_name)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = freepdb1)
    )
  )
```

vector ユーザによるDBログインをテストします。

```
$ sqlplus vector/vector@freepdb1
```

## Cohere向け資格証明の設定

Cohereを利用するために必要な資格証明をDBオブジェクトとして作成しておきます。
事前に下記Cohere公式サイトにてAPIキーを取得してください。
https://cohere.com/
ちなみにサービスの制約はありますが、Trialキーであれば無償です。

APIキーを取得したら、vector ユーザでDBにログインし、資格証明を作成します。

```sql
SQL> DECLARE
  jo json_object_t;
BEGIN
  jo := json_object_t();
  jo.put('access_token','your api key');
  dbms_vector_chain.create_credential(
    credential_name   => 'COHERE_CRED',
    params            => json(jo.to_string));
end;
/
```

## (オプション) ONNX利用のためのOML4Pyのセットアップ

Oracle Databaseに学習済みモデルをONNXフォーマットでimportするには、OML4Pyを使ったONNXのexportが必要です。
OML4Py以外でexportされたONNXはOracle Databaseにimportできません。
そのため、まずはOML4Pyをインストールします。
手順は下記マニュアルを参考にしました。
[Install OML4Py for On-Premises Databases](https://docs.oracle.com/en/database/oracle/machine-learning/oml4py/2/mlugp/install-oml4py-premises-database.html#GUID-84012E3D-9179-43D6-8085-EE46D503C159)

手始めに必要なOSパッケージをインストールします。

```bash
$ sudo su -
## 不足パッケージの確認
$ rpm -qa perl-Env
$ rpm -qa libffi-devel
$ rpm -qa openssl 
$ rpm -qa openssl-devel
$ rpm -qa tk-devel
$ rpm -qa xz-devel
$ rpm -qa zlib-devel
$ rpm -qa bzip2-devel
$ rpm -qa readline-devel
$ rpm -qa libuuid-devel
$ rpm -qa ncurses-devel

## 不足分をインストール
$ yum install perl-Env libffi-devel tk-devel bzip2-devel readline-devel libuuid-devel ncurses-devel
```

OML4PyをインストールするためのPython仮想環境を用意します。
仮想環境の管理にはAnacondaを使います。

```bash
## Anacondaインストール
$ mkdir -p ~/miniconda3
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
$ bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3

## 不要ファイル削除
$ rm -rf ~/miniconda3/miniconda.sh

## Anaconda初期セットアップ
$ ~/miniconda3/bin/conda init bash
```

Python仮想環境を新規作成します。
記事執筆時点のOML4Pyは Python 3.12 で稼働するため、バージョンは 3.12 を指定します。

```bash
$ conda create -n rag python=3.12
## 仮想環境「rag」のアクティベート
$ conda activate rag
```

pipを最新化します。

```bash
$ python3 -m pip install --upgrade pip
```

必要なPythonパッケージをインストールします。

```bash
$ pip install pandas
$ pip install setuptools
$ pip install scipy
$ pip install matplotlib
$ pip install oracledb
$ pip install joblib
$ pip install scikit-learn
$ pip install numpy
$ pip install onnxruntime
$ pip install onnxruntime-extensions
$ pip install onnx
$ pip install --extra-index-url "https://download.pytorch.org/whl/cpu" torch
$ pip install transformers
$ pip install sentencepiece
```

以下サイトから最新のOML4Pyをダウンロードし、サーバに配置します。
https://www.oracle.com/database/technologies/oml4py-downloads.html

zipファイルを解凍し、Perlスクリプトを使ってインストールします。

```bash
$ mkdir oml4py
$ cd oml4py
## oml4py-client-linux-x86_64-2.0.zip を oml4py ディレクトリに移動
$ unzip oml4py-client-linux-x86_64-2.0.zip
$ perl -Iclient client/client.pl

Oracle Machine Learning for Python 2.0 Client.

Copyright (c) 2018, 2024 Oracle and/or its affiliates. All rights reserved.
Checking platform .................. Pass
Checking Python .................... Pass
Checking dependencies .............. /home/oracle/oml4py/check_deps.py:2: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import WorkingSet, VersionConflict, DistributionNotFound
Pass
Checking OML4P version ............. Pass
Current configuration
  Python Version ................... 3.12.3
  PYTHONHOME ....................... /home/oracle/miniconda3/envs/rag
  Existing OML4P module version .... None

  Operation ........................ Install/Upgrade

Proceed? [yes]

Processing ./client/oml-2.0-cp312-cp312-linux_x86_64.whl
Installing collected packages: oml
Successfully installed oml-2.0

Done
```

## (オプション) ONNXのexport/import

Pythonのインタラクティブ・シェルを起動し、exportします。
今回はMultilingual対応している `google-bert/bert-base-multilingual-cased` を例に使いましたが、Hugging Face上にあるモデルを任意にご利用ください。
なおexportできるモデルのサイズは仕様上 1GB までと制限されていますのでご注意ください。
下記例も `quantize_model=True` を設定し、Quantizeすることでサイズを1GBに収めてexportしています。

```bash
$ python3
```

```python
>>> from oml.utils import EmbeddingModel, EmbeddingModelConfig
>>> config = EmbeddingModelConfig.from_template("text",max_seq_length=512,quantize_model=True)
>>> em = EmbeddingModel(model_name="google-bert/bert-base-multilingual-cased", config=config)
>>> em.export2file("bert-base-multilingual-cased",output_dir=".")
```

exportした結果「bert-base-multilingual-cased.onnx」というファイルが出力されています。
こちらをディレクトリ・オブジェクトの指定フォルダに配置し、DBにimportします。
import時は vector ユーザでDBログインし、プロシージャを実行します。

```sql
EXECUTE DBMS_VECTOR.LOAD_ONNX_MODEL( 'VEC_DUMP', 'bert-base-multilingual-cased.onnx', 'doc_model', JSON('{"function" : "embedding", "embeddingOutput" : "embedding", "input": {"input": ["DATA"]}}'));
```

やや長かったですが、以上が事前準備でした。
次回はAPEXでファイルのアップロードとEmbeddingを実装していきます。
[Oracle Database 23ai FreeとAPEXでRAGを使った生成AIアプリをローコード開発してみた (アプリ実装 前編)](https://qiita.com/ssfujita/items/c53579bbb3eed4145942)