透過 AlloyDB AI 開始使用向量嵌入功能

1. 簡介

在這個程式碼研究室中,您將瞭解如何透過結合向量搜尋與 Vertex AI 嵌入項目,使用 AlloyDB AI。

17e86406ab251142.png

必要條件

  • 具備 Google Cloud 控制台的基本知識
  • 指令列介面和 Google Shell 的基本技能

課程內容

  • 如何部署 AlloyDB 叢集和主要執行個體
  • 如何從 Google Compute Engine VM 連線至 AlloyDB
  • 如何建立資料庫並啟用 AlloyDB AI
  • 如何將資料載入資料庫
  • 如何在 AlloyDB 中使用 Vertex AI 嵌入模型
  • 如何使用 Vertex AI 生成式模型充實結果
  • 如何利用向量索引提升效能

軟硬體需求

  • Google Cloud 帳戶和 Google Cloud 專案
  • 網路瀏覽器,例如 Chrome

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • 「Project name」是這個專案參與者的顯示名稱。這是 Google API 未使用的字元字串。您隨時可以更新。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生專屬字串,您通常不需要特別在意。在大多數程式碼研究室中,您都需要參照專案 ID (通常會以 PROJECT_ID 表示)。如果您不喜歡產生的 ID,可以產生另一個隨機 ID。或者,您也可以自行嘗試,看看是否支援。這項設定在這個步驟後就無法變更,並會在整個專案期間維持不變。
  • 提醒您,有些 API 會使用第三個值「專案編號」。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用帳單功能,才能使用 Cloud 資源/API。執行本程式碼研究室不會產生任何費用 (如果有的話)。如要關閉資源,以免產生本教學課程結束後產生的費用,您可以刪除自己建立的資源或刪除專案。新使用者符合 $300 美元免費試用計畫的資格。

啟動 Cloud Shell

雖然 Google Cloud 可以從筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是一種在 Cloud 中執行的指令列環境。

Google Cloud 控制台,按一下右上方的工具列上的 Cloud Shell 圖示:

55efc1aaa7a4d3ad.png

佈建並連線至環境的作業需要一些時間才能完成。完成後,您應該會看到如下的畫面:

7ffe5cbb04455448.png

這個虛擬機器會載入您需要的所有開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,因此能大幅提升網路效能和驗證效率。本程式碼研究室的所有工作都可以在瀏覽器中完成。您不需要安裝任何東西。

3. 事前準備

啟用 API

輸出:

在 Cloud Shell 中,請確認您已設定專案 ID:

gcloud config set project [YOUR-PROJECT-ID]

設定環境變數 PROJECT_ID:

PROJECT_ID=$(gcloud config get-value project)

啟用所有必要服務:

gcloud services enable alloydb.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       aiplatform.googleapis.com

預期的輸出內容:

student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417
Updated property [core/project].
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-14650]
student@cloudshell:~ (test-project-001-402417)$ 
student@cloudshell:~ (test-project-001-402417)$ gcloud services enable alloydb.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       aiplatform.googleapis.com
Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.

設定預設區域以使用 Vertex AI 嵌入模型。進一步瞭解 Vertex AI 可用地區。本範例使用 us-central1 區域。

gcloud config set compute/region us-central1

4. 部署 AlloyDB

建立 AlloyDB 叢集之前,我們需要虛擬私有雲中的可用私人 IP 範圍,供日後的 AlloyDB 執行個體使用。如果沒有,我們需要建立,並指派給內部 Google 服務使用,之後才能建立叢集和執行個體。

建立私人 IP 範圍

我們必須在虛擬私有雲中,為 AlloyDB 設定私人服務存取權設定。這裡假設使用的是「default」這個專案會用於所有動作。

建立私人 IP 範圍:

gcloud compute addresses create psa-range \
    --global \
    --purpose=VPC_PEERING \
    --prefix-length=24 \
    --description="VPC private service access" \
    --network=default

使用分配的 IP 範圍建立私人連線:

gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=psa-range \
    --network=default

預期的控制台輸出內容:

student@cloudshell:~ (test-project-402417)$ gcloud compute addresses create psa-range \
    --global \
    --purpose=VPC_PEERING \
    --prefix-length=24 \
    --description="VPC private service access" \
    --network=default
Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/global/addresses/psa-range].

student@cloudshell:~ (test-project-402417)$ gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=psa-range \
    --network=default
Operation "operations/pssn.p24-4470404856-595e209f-19b7-4669-8a71-cbd45de8ba66" finished successfully.

student@cloudshell:~ (test-project-402417)$

建立 AlloyDB 叢集

在 us-central1 區域中建立 AlloyDB 叢集。

定義 postgres 使用者的密碼。您可以自行定義密碼,也可以使用隨機函式產生密碼

export PGPASSWORD=`openssl rand -hex 12`

預期的控制台輸出內容:

student@cloudshell:~ (test-project-402417)$ export PGPASSWORD=`openssl rand -hex 12`

請記下 PostgreSQL 密碼,以供日後使用:

echo $PGPASSWORD

預期的控制台輸出內容:

student@cloudshell:~ (test-project-402417)$ echo $PGPASSWORD
bbefbfde7601985b0dee5723

定義區域和 AlloyDB 叢集名稱,我們將使用 us-central1 區域和 alloydb-aip-01 做為叢集名稱:

export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01

執行指令來建立叢集:

gcloud alloydb clusters create $ADBCLUSTER \
    --password=$PGPASSWORD \
    --network=default \
    --region=$REGION

預期的控制台輸出內容:

export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
gcloud alloydb clusters create $ADBCLUSTER \
    --password=$PGPASSWORD \
    --network=default \
    --region=$REGION
Operation ID: operation-1697655441138-6080235852277-9e7f04f5-2012fce4
Creating cluster...done.                                                                                                                                                                                                                                                           

建立 AlloyDB 主要執行個體

在同一個 Cloud Shell 工作階段中,為叢集建立 AlloyDB 主要執行個體。如果連線中斷,您必須重新定義地區和叢集名稱環境變數。

gcloud alloydb instances create $ADBCLUSTER-pr \
    --instance-type=PRIMARY \
    --cpu-count=2 \
    --region=$REGION \
    --cluster=$ADBCLUSTER

預期的控制台輸出內容:

student@cloudshell:~ (test-project-402417)$ gcloud alloydb instances create $ADBCLUSTER-pr \
    --instance-type=PRIMARY \
    --cpu-count=2 \
    --region=$REGION \
    --availability-type ZONAL \
    --cluster=$ADBCLUSTER
Operation ID: operation-1697659203545-6080315c6e8ee-391805db-25852721
Creating instance...done.                                                                                                                                                                                                                                                     

5. 連線至 AlloyDB

AlloyDB 是透過僅限私人連線部署,因此必須安裝 PostgreSQL 用戶端的 VM,才能與資料庫搭配運作。

部署 GCE VM

在 AlloyDB 叢集所在的區域和虛擬私有雲中建立 GCE VM。

請在 Cloud Shell 中執行下列指令:

export ZONE=us-central1-a
gcloud compute instances create instance-1 \
    --zone=$ZONE \
    --create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \
    --scopes=https://www.googleapis.com/auth/cloud-platform

預期的主控台輸出內容:

student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a
student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a
gcloud compute instances create instance-1 \
    --zone=$ZONE \
    --create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \
    --scopes=https://www.googleapis.com/auth/cloud-platform

Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/zones/us-central1-a/instances/instance-1].
NAME: instance-1
ZONE: us-central1-a
MACHINE_TYPE: n1-standard-1
PREEMPTIBLE: 
INTERNAL_IP: 10.128.0.2
EXTERNAL_IP: 34.71.192.233
STATUS: RUNNING

安裝 Postgres 用戶端

在已部署的 VM 上安裝 PostgreSQL 用戶端軟體

連線至 VM:

gcloud compute ssh instance-1 --zone=us-central1-a

預期的控制台輸出內容:

student@cloudshell:~ (test-project-402417)$ gcloud compute ssh instance-1 --zone=us-central1-a
Updating project ssh metadata...working..Updated [https://www.googleapis.com/compute/v1/projects/test-project-402417].                                                                                                                                                         
Updating project ssh metadata...done.                                                                                                                                                                                                                                              
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.5110295539541121102' (ECDSA) to the list of known hosts.
Linux instance-1.us-central1-a.c.gleb-test-short-001-418811.internal 6.1.0-18-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
student@instance-1:~$ 

在 VM 中安裝執行指令的軟體:

sudo apt-get update
sudo apt-get install --yes postgresql-client

預期的控制台輸出內容:

student@instance-1:~$ sudo apt-get update
sudo apt-get install --yes postgresql-client
Get:1 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable InRelease [5146 B]
Get:2 https://packages.cloud.google.com/apt cloud-sdk-bullseye InRelease [6406 B]   
Hit:3 https://deb.debian.org/debian bullseye InRelease  
Get:4 https://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:5 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable/main amd64 Packages [1930 B]
Get:6 https://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
Get:7 https://deb.debian.org/debian bullseye-backports InRelease [49.0 kB]
...redacted...
update-alternatives: using /usr/share/postgresql/13/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode
Setting up postgresql-client (13+225) ...
Processing triggers for man-db (2.9.4-2) ...
Processing triggers for libc-bin (2.31-13+deb11u7) ...

連線至執行個體

使用 psql 從 VM 連線至主要執行個體。

在同一個 Cloud Shell 分頁中,開啟與 instance-1 VM 的 SSH 工作階段。

使用上述 AlloyDB 密碼 (PGPASSWORD) 值和 AlloyDB 叢集 ID,透過 GCE VM 連線至 AlloyDB:

export PGPASSWORD=<Noted password>
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)")
psql "host=$INSTANCE_IP user=postgres sslmode=require"

預期的控制台輸出內容:

student@instance-1:~$ export PGPASSWORD=CQhOi5OygD4ps6ty
student@instance-1:~$ ADBCLUSTER=alloydb-aip-01
student@instance-1:~$ REGION=us-central1
student@instance-1:~$ INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)")
gleb@instance-1:~$ psql "host=$INSTANCE_IP user=postgres sslmode=require"
psql (15.6 (Debian 15.6-0+deb12u1), server 15.5)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.

postgres=>

關閉 psql 工作階段:

exit

6. 準備資料庫

我們需要建立資料庫、啟用 Vertex AI 整合功能、建立資料庫物件,然後匯入資料。

將必要權限授予 AlloyDB

將 Vertex AI 權限新增至 AlloyDB 服務代理。

使用頂端的「+」符號開啟另一個 Cloud Shell 分頁。

4ca978f5142bb6ce.png

在新的 Cloud Shell 分頁中執行:

PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"

預期的主控台輸出內容:

student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-11039]
student@cloudshell:~ (test-project-001-402417)$ gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"
Updated IAM policy for project [test-project-001-402417].
bindings:
- members:
  - serviceAccount:service-4470404856@gcp-sa-alloydb.iam.gserviceaccount.com
  role: roles/aiplatform.user
- members:
...
etag: BwYIEbe_Z3U=
version: 1
 

在分頁中執行「exit」指令,關閉分頁:

exit

建立資料庫

建立資料庫快速入門。

在 GCE VM 工作階段中,執行以下動作:

建立資料庫:

psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db"

預期的主控台輸出內容:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db"
CREATE DATABASE
student@instance-1:~$  

啟用 Vertex AI 整合功能

啟用資料庫中的 Vertex AI 整合功能和 pgvector 擴充功能。

在 GCE VM 中執行:

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE"
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector"

預期的控制台輸出內容:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE"
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector"
CREATE EXTENSION
CREATE EXTENSION
student@instance-1:~$ 

匯入資料

下載準備好的資料,然後匯入新資料庫。

在 GCE VM 中,執行下列指令:

gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header"

預期的控制台輸出內容:

student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
SET
SET
SET
SET
SET
 set_config 
------------
 
(1 row)
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE SEQUENCE
ALTER TABLE
ALTER SEQUENCE
ALTER TABLE
ALTER TABLE
ALTER TABLE
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header"
COPY 941
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header"
COPY 263861
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header"
COPY 4654
student@instance-1:~$

7. 計算嵌入

匯入資料後,我們在 cymbal_products 資料表中取得產品資料,這個目錄會在 cymbal_inventory 資料表中,顯示每間商店的可用產品數量,以及 cymbal_stores 表格中的商店清單。我們需要根據產品說明計算向量資料,因此會使用嵌入函式。我們將使用這個函式,透過 Vertex AI 整合功能,根據產品說明計算向量資料,並將其新增至資料表。如要進一步瞭解所用技術,請參閱說明文件

建立嵌入資料欄

使用 psql 連線至資料庫,並在 cymbal_products 資料表中使用嵌入函式,建立含有向量資料的虛擬欄。嵌入函式會根據透過 product_description 欄提供的資料,傳回 Vertex AI 的向量資料。

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"

在連線至資料庫後的 psql 工作階段中,執行以下動作:

ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED;

這項指令會建立虛擬欄,並以向量資料填入該欄。

預期的主控台輸出內容:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
psql (13.11 (Debian 13.11-0+deb11u1), server 14.7)
WARNING: psql major version 13, server major version 14.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

quickstart_db=> ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED;
ALTER TABLE
quickstart_db=> 

8. 執行相似度搜尋

我們現在可以根據系統針對說明計算出的向量值和我們針對要求所取得的向量值,使用相似度進行搜尋來執行搜尋作業。

您可以透過相同的 psql 指令列介面執行 SQL 查詢,也可以改用 AlloyDB Studio 執行。在 AlloyDB Studio 中,任何多列和複雜的輸出內容看起來可能會更好。

連線至 AlloyDB Studio

在下列章節中,所有需要連線至資料庫的 SQL 指令均可在 AlloyDB Studio 中執行。如要執行指令,請按一下主要執行個體,開啟 AlloyDB 叢集的 Web 控制台介面。

ef4bfbcf0ed2ef3a.png

接著按一下左側的 AlloyDB Studio:

5c155cbcd7d43a1.png

請選擇 quickstart_db 資料庫、使用者 postgres,並提供我們在建立叢集時記下的密碼。然後按一下 [驗證]按鈕。

432613065cac864f.png

系統會開啟 AlloyDB Studio 介面。如要在資料庫中執行指令,請按一下右側的「編輯器 1」分頁。

b36c28f8165119ca.png

您可以在此開啟介面,以便執行 SQL 指令

cf43aa20f292797e.png

如果想使用指令列 psql,請按照替代路徑,從 VM SSH 工作階段連線至資料庫,如同先前的章節所述。

從 psql 執行相似度搜尋

如果資料庫工作階段已中斷連線,請使用 psql 或 AlloyDB Studio 再次連線至資料庫。

連線至資料庫:

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"

執行查詢,取得與客戶要求最密切相關的可用產品清單。我們要傳送給 Vertex AI 以取得向量值的要求,聽起來就像「這裡適合種植哪一種果樹?」

您可以執行以下查詢,來選擇最符合要求的前 10 個項目:

SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        distance ASC
LIMIT 10;

以下是預期的輸出內容:

quickstart_db=> SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        distance ASC
LIMIT 10;
      product_name       |                                   description                                    | sale_price | zip_code |      distance       
-------------------------+----------------------------------------------------------------------------------+------------+----------+---------------------
 Cherry Tree             | This is a beautiful cherry tree that will produce delicious cherries. It is an d |      75.00 |    93230 | 0.43922018972266397
 Meyer Lemon Tree        | Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by  |         34 |    93230 |  0.4685112926118228
 Toyon                   | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e |      10.00 |    93230 |  0.4835677149651668
 California Lilac        | This is a beautiful lilac tree that can grow to be over 10 feet tall. It is an d |       5.00 |    93230 |  0.4947204525907498
 California Peppertree   | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e |      25.00 |    93230 |  0.5054166905547247
 California Black Walnut | This is a beautiful walnut tree that can grow to be over 80 feet tall. It is a d |     100.00 |    93230 |  0.5084219510932597
 California Sycamore     | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is  |     300.00 |    93230 |  0.5140519790508755
 Coast Live Oak          | This is a beautiful oak tree that can grow to be over 100 feet tall. It is an ev |     500.00 |    93230 |  0.5143126438081371
 Fremont Cottonwood      | This is a beautiful cottonwood tree that can grow to be over 100 feet tall. It i |     200.00 |    93230 |  0.5174774727252058
 Madrone                 | This is a beautiful madrona tree that can grow to be over 80 feet tall. It is an |      50.00 |    93230 |  0.5227400803389093

9. 改善回應

您可以運用查詢結果提升回應用戶端應用程式的回應,並在 Vertex AI 生成式基礎語言模型的提示中,使用提供的查詢結果準備有意義的輸出內容。

為達成這個目標,我們打算產生含有向量搜尋結果的 JSON,然後使用產生的 JSON 做為 Vertex AI 文字 LLM 模型的提示,以便產生有意義的輸出內容。在第一步中,我們會產生 JSON,然後在 Vertex AI Studio 中進行測試,最後將 JSON 納入可在應用程式中使用的 SQL 陳述式。

以 JSON 格式產生輸出內容

修改查詢以產生 JSON 格式的輸出內容,且只傳回一個資料列來傳送至 Vertex AI

查詢範例如下:

WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

以下是輸出內容中預期的 JSON:

[{"product_name":"Cherry Tree","description":"This is a beautiful cherry tree that will produce delicious cherries. It is an d","sale_price":75.00,"zip_code":93230,"product_id":"d536e9e823296a2eba198e52dd23e712"}]

在 Vertex AI Studio 中執行提示

我們可以使用產生的 JSON,將其做為 Vertex AI Studio 中生成式 AI 文字模型提示的一部分

在 Cloud 控制台中開啟 Vertex AI Studio。

e514b176aef7945e.png

54712e5ade7121f.png

系統可能會要求您啟用其他 API,但您可以忽略這項要求。我們不需要任何其他 API 即可完成實驗室。

以下是要使用的提示:

你是親切的顧問,協助客戶根據需求找到合適的產品。

我們根據客戶的要求,載入了與搜尋字詞密切相關的產品清單。

JSON 格式的清單,其中包含值清單,例如:{"product_name":"name","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}

產品清單如下:

[填入 JSON 的地方]

客戶問:「這裡哪種樹木生長得最好?」

請務必提供產品、價格和補充資訊視為提示

使用 JSON 值執行提示並使用 gemini-1.5-flash 模型時,結果如下:

30e5072cd2975685.png

以下是我們在本例中從模型取得的答案。請注意,由於模型和參數會隨時間變更,因此您的答案可能會有所不同:

「我知道你正在尋找適合你所在地區的樹木,根據你的郵遞區號「93230」,櫻桃樹看起來是不錯的選擇!

它被描述為一種美麗的樹木,能結出美味的櫻桃。目前特價 $75.00 美元。

雖然我無法提供有關櫻花樹在你所在地區生長速度的詳細資訊,但我可以告訴你,櫻花樹通常喜歡排水良好的土壤和充足的陽光。

為確保獲得最佳結果,建議你諮詢當地的苗圃或園藝專家,他們可以根據你的所在位置和土壤狀況提供更適合的建議。這些專家也能協助您選擇最符合需求的方案,並提供有關植栽和照顧的提示。」

在 PSQL 中執行提示

我們可以使用 AlloyDB AI 與 Vertex AI 的整合功能,直接在資料庫中使用 SQL 取得生成式模型的相同回應。但如要使用 gemini-1.5-flash 模型,就必須先註冊該模型。

將擴充功能升級至 1.4.1 版 (如果目前版本較低)。如先前所示,透過 psql 連線至 quickstart_db 資料庫 (或使用 AlloyDB Studio),然後執行以下指令:

SELECT extversion from pg_extension where extname='google_ml_integration';

如果傳回的值小於 1.4.1,請執行以下操作:

ALTER EXTENSION google_ml_integration UPDATE TO '1.4.1';

接著,我們需要將 google_ml_integration.enable_model_support 資料庫旗標設為「開啟」。如要執行這項操作,您可以使用 AlloyDB 網路主控台介面,或執行下列 gcloud 指令。

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud beta alloydb instances update $ADBCLUSTER-pr \
  --database-flags google_ml_integration.enable_model_support=on \
  --region=$REGION \
  --cluster=$ADBCLUSTER \
  --project=$PROJECT_ID \
  --update-mode=FORCE_APPLY

這項指令會在背景執行大約 3 到 5 分鐘。接著,您就能在 psql 工作階段或使用 AlloyDB Studio 連線至 quickstart_db 資料庫中驗證新旗標。

show google_ml_integration.enable_model_support;

psql 工作階段的預期輸出內容為「on」:

postgres=> show google_ml_integration.enable_model_support;
 google_ml_integration.enable_model_support 
--------------------------------------------
 on
(1 row)

接著,我們需要註冊兩個模型。第一個是已使用的 text-embedding-004 模型。我們已啟用模型註冊功能,因此需要註冊。

如要註冊在 psql 或 AlloyDB Studio 中執行模型,請將下列程式碼:

CALL
  google_ml.create_model(
    model_id => 'text-embedding-004',
    model_provider => 'google',
    model_qualified_name => 'text-embedding-004',
    model_type => 'text_embedding',
    model_auth_type => 'alloydb_service_agent_iam',
    model_in_transform_fn => 'google_ml.vertexai_text_embedding_input_transform',
    model_out_transform_fn => 'google_ml.vertexai_text_embedding_output_transform');

下一個需要註冊的模型是 gemini-1.5-flash-002,用來產生使用者容易使用的輸出內容。

CALL
  google_ml.create_model(
    model_id => 'gemini-1.5-flash-002',
    model_request_url => 'https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/publishers/google/models/gemini-1.5-flash-002:streamGenerateContent',
    model_provider => 'google',
    model_auth_type => 'alloydb_service_agent_iam');

您可隨時從 google_ml.model_info_view 中選取資訊,以驗證已註冊模型清單。

select model_id,model_type from google_ml.model_info_view;

以下是輸出內容範例

quickstart_db=> select model_id,model_type from google_ml.model_info_view;
        model_id         |   model_type   
-------------------------+----------------
 textembedding-gecko     | text_embedding
 textembedding-gecko@001 | text_embedding
 text-embedding-004      | text_embedding
 gemini-1.5-flash-001    | generic
(4 rows)

我們現在可以使用在子查詢 JSON 中產生的生成內容,做為使用 SQL 生成式 AI 文字模型的提示的一部分。

在對資料庫的 psql 或 AlloyDB Studio 工作階段中執行查詢

WITH trees AS (
SELECT
        cp.product_name,
        cp.product_description AS description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id AS product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci ON
        ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON
        cs.store_id = ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004',
        'What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1),
prompt AS (
SELECT
        'You are a friendly advisor helping to find a product based on the customer''s needs.
Based on the client request we have loaded a list of products closely related to search.
The list in JSON format with list of values like {"product_name":"name","product_description":"some description","sale_price":10}
Here is the list of products:' || json_agg(trees) || 'The customer asked "What kind of fruit trees grow well here?"
You should give information about the product, price and some supplemental information' AS prompt_text
FROM
        trees),
response AS (
SELECT
        json_array_elements(google_ml.predict_row( model_id =>'gemini-1.5-flash-002',
        request_body => json_build_object('contents',
        json_build_object('role',
        'user',
        'parts',
        json_build_object('text',
        prompt_text)))))->'candidates'->0->'content'->'parts'->0->'text' AS resp
FROM
        prompt)
SELECT
        string_agg(resp::text,
        ' ')
FROM
        response;

以下是預期的輸出內容。輸出內容可能會依模型版本和參數而有所不同。

"That" "'s a great question! Based on your location (assuming you're" " in zip code 93230), I have a suggestion for a" " fruit tree that should thrive.\n\nWe have the **Cherry Tree** available.\n\n**Product Name:** Cherry Tree\n\n**Description:** This is a beautiful cherry" " tree that will produce delicious cherries. It's a deciduous tree (meaning it loses its leaves in the fall) growing to about 15 feet tall." " The leaves are dark green in summer, turning a beautiful red in the fall. Cherry trees are known for their beauty, shade, and privacy.\n\n**Sale Price:** $75.00\n\n**Important Considerations for Growing" " Cherry Trees:**\n\n* **Climate:** Cherry trees prefer a cool, moist climate, and 93230 falls within a suitable range (USDA zones 4-9). However, it's always a good idea to" " check the specific microclimate of your property (sun exposure, drainage etc.).\n* **Soil:** They do best in sandy soil. If your soil is different, you may need to amend it to improve drainage.\n* **Pollination:** Many cherry varieties require a second, compatible cherry tree for proper pollination" ". Check the specific pollination needs of this variety before purchase if you want a significant cherry yield.\n\nThis cherry tree is a beautiful addition to any yard and will provide you with delicious cherries if you can meet its needs. Would you like to know more about its pollination requirements, or perhaps see if we have any other" " fruit trees suitable for your area?\n" ""

10. 建立向量索引

我們的資料集非常短,回應時間主要取決於與 AI 模型的互動。但如果您有數百萬個向量,向量搜尋部分可能會占用大量回應時間,並對系統造成高負載。為了改善這個問題,我們可以建立向量索引。

建立 ScaNN 索引

如要建構 SCANN 索引,我們需要啟用另一個擴充功能。擴充功能 alloydb_scann 提供介面,可使用 Google ScaNN 演算法處理 ANN 類型的向量索引。

CREATE EXTENSION IF NOT EXISTS alloydb_scann;

預期輸出內容:

quickstart_db=> CREATE EXTENSION IF NOT EXISTS alloydb_scann;
CREATE EXTENSION
Time: 27.468 ms
quickstart_db=> 

現在我們可以建立索引。在以下範例中,我將大多數參數設為預設值,只為索引提供分區數量 (num_leaves):

CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products
  USING scann (embedding cosine)
  WITH (num_leaves=31, max_num_levels = 2);

如要瞭解如何調整索引參數,請參閱說明文件

預期輸出內容:

quickstart_db=> CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products
  USING scann (embedding cosine)
  WITH (num_leaves=31, max_num_levels = 2);
CREATE INDEX
quickstart_db=>

比較回覆

我們現在可以以 EXPLAIN 模式執行向量搜尋查詢,並驗證是否已使用索引。

EXPLAIN (analyze) 
WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

預期輸出內容:

Aggregate (cost=16.59..16.60 rows=1 width=32) (actual time=2.875..2.877 rows=1 loops=1)
-> Subquery Scan on trees (cost=8.42..16.59 rows=1 width=142) (actual time=2.860..2.862 rows=1 loops=1)
-> Limit (cost=8.42..16.58 rows=1 width=158) (actual time=2.855..2.856 rows=1 loops=1)
-> Nested Loop (cost=8.42..6489.19 rows=794 width=158) (actual time=2.854..2.855 rows=1 loops=1)
-> Nested Loop (cost=8.13..6466.99 rows=794 width=938) (actual time=2.742..2.743 rows=1 loops=1)
-> Index Scan using cymbal_products_embeddings_scann on cymbal_products cp (cost=7.71..111.99 rows=876 width=934) (actual time=2.724..2.724 rows=1 loops=1)
Order By: (embedding <=> '[0.008864171,0.03693164,-0.024245683,-0.00355923,0.0055611245,0.015985578,...<redacted>...5685,-0.03914233,-0.018452475,0.00826032,-0.07372604]'::vector)
-> Index Scan using walmart_inventory_pkey on cymbal_inventory ci (cost=0.42..7.26 rows=1 width=37) (actual time=0.015..0.015 rows=1 loops=1)
Index Cond: ((store_id = 1583) AND (uniq_id = (cp.uniq_id)::text))

從輸出內容中,我們可以清楚看到查詢使用了「Index Scan using cymbal_products_embeddings_scann on cymbal_products」。

如果我們不執行 explain 查詢:

WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

預期輸出內容:

[{"product_name":"Meyer Lemon Tree","description":"Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by ","sale_price":34,"zip_code":93230,"product_id":"02056727942aeb714dc9a2313654e1b0"}]

我們可以看到結果略有不同,系統傳回的不是在未建立索引的情況下搜尋時位居頂端的櫻桃樹,而是第二個選項梅耶檸檬樹。因此,我們的指數雖然能反映效能,但依然足以提供良好結果。

您可以嘗試不同向量索引,以及說明文件頁面上提供的更多實驗室和範例,這些實驗室和範例已整合 Langchain。

11. 清除環境資源

完成實驗室後,請銷毀 AlloyDB 執行個體和叢集

刪除 AlloyDB 叢集和所有執行個體

叢集會使用強制選項進行銷毀,同時刪除屬於叢集的所有執行個體。

如果連線中斷,之前的所有設定都會遺失,請在 Cloud Shell 中定義專案和環境變數:

gcloud config set project <your project id>
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)

刪除叢集:

gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force

預期的控制台輸出內容:

student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
All of the cluster data will be lost when the cluster is deleted.

Do you want to continue (Y/n)?  Y

Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f
Deleting cluster...done.   

刪除 AlloyDB 備份

刪除叢集的所有 AlloyDB 備份:

for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done

預期的主控台輸出內容:

student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f
Deleting backup...done.                                                                                                                                                                                                                                                            

我們現在可以刪除 VM

刪除 GCE VM

請在 Cloud Shell 中執行下列指令:

export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
    --zone=$ZONE \
    --quiet

預期的主控台輸出內容:

student@cloudshell:~ (test-project-001-402417)$ export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
    --zone=$ZONE \
    --quiet
Deleted 

12. 恭喜

恭喜您完成本程式碼研究室。

涵蓋內容

  • 如何部署 AlloyDB 叢集和主要執行個體
  • 如何從 Google Compute Engine VM 連線至 AlloyDB
  • 如何建立資料庫並啟用 AlloyDB AI
  • 如何將資料載入資料庫
  • 如何在 AlloyDB 中使用 Vertex AI 嵌入模型
  • 如何使用 Vertex AI 生成式模型充實結果
  • 如何使用向量索引提升效能

13. 問卷調查

輸出:

您要如何使用這個教學課程?

只能閱讀 閱讀並完成練習