Menggunakan model Jev TypeSafe AI dengan Fungsi AI AlloyDB untuk Kueri AI Berkecepatan Tinggi

1. Pengantar

Dalam codelab ini, Anda akan menghubungkan model Jev TypeSafe AI ke AlloyDB AI menggunakan fungsi AI native AlloyDB (ai.if, ai.analyze_sentiment, dan ml_predict_row). Dengan demikian, Anda dapat menjalankan inferensi batch yang efisien menggunakan model Jev langsung pada data operasional di AlloyDB, tanpa memindahkan data atau menulis kode sisi aplikasi yang kompleks.

Yang akan Anda lakukan

  • Menyediakan Private Service Access (PSA) serta cluster dan instance utama AlloyDB untuk PostgreSQL
  • Buat aturan firewall VPC yang mengizinkan Cloudshell dan konektivitas internal
  • Memuat set data sampel e-commerce menggunakan gcloud alloydb clusters import
  • Mengaktifkan ekstensi google_ml_integration Google Secret Manager dan AlloyDB
  • Menyimpan dan memberikan akses ke kunci API TypeSafe AI Anda di Secret Manager
  • Buat fungsi transformasi input dan output PL/pgSQL untuk primitif noul (boolean) dan choice (sentimen) Jev
  • Mendaftarkan endpoint model jev-model kustom di AlloyDB
  • Menjalankan kueri semantik skalar dan batch array (ai.if dan ai.analyze_sentiment) langsung di SQL
  • Kueri ulasan produk pelanggan asli untuk klasifikasi sentimen menggunakan ai.analyze_sentiment
  • (Bonus) Mendaftarkan endpoint generik (jev-systemone) dan mengevaluasi intensitas kepuasan pelanggan berkelanjutan menggunakan primitif score Jev

Yang Anda butuhkan

  • Browser web seperti Chrome
  • Project Google Cloud yang mengaktifkan penagihan
  • Kunci API TypeSafe AI (dari TypeSafe AI)

2. Sebelum memulai

Pilih project Google Cloud Anda

Di Konsol Google Cloud, pilih atau buat project Google Cloud yang ingin Anda gunakan.

Mulai Cloud Shell

Klik Activate Cloud Shell di kanan atas Konsol Google Cloud.

Pastikan sesi Cloud Shell Anda diautentikasi:

gcloud auth list

Tetapkan project ID dan variabel lingkungan Anda:

export PROJECT_ID=$(gcloud config get-value project)
gcloud config set project $PROJECT_ID

export REGION="us-west4"
export ADBCLUSTER="my-alloydb-cluster"
export ADBINSTANCE="my-alloydb-primary"

Mengaktifkan Google Cloud API yang Diperlukan

Jalankan perintah ini untuk mengaktifkan semua API layanan Google Cloud yang diperlukan:

gcloud services enable \
  alloydb.googleapis.com \
  servicenetworking.googleapis.com \
  secretmanager.googleapis.com \
  compute.googleapis.com

3. Menyediakan Cluster AlloyDB dan Instance Utama

Pada langkah ini, Anda akan mengalokasikan rentang IP Akses Layanan Pribadi di jaringan VPC, membuat peering pribadi, serta menyediakan cluster dan instance utama AlloyDB dengan akses internet keluar.

1. Membuat Rentang IP Akses Layanan Pribadi (PSA)

AlloyDB memerlukan alokasi rentang IP pribadi di jaringan Virtual Private Cloud (VPC) Anda. Dengan asumsi Anda menggunakan jaringan VPC default:

Buat alokasi rentang IP pribadi:

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

Buat koneksi peering VPC pribadi:

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

2. Buat Cluster AlloyDB

Buat sandi database yang aman untuk pengguna administratif postgres awal:

export PGPASSWORD="$(openssl rand -hex 8)@1aA"
echo "Your generated AlloyDB postgres password is: $PGPASSWORD"

Buat cluster Uji Coba Gratis AlloyDB:

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

3. Buat Instance Utama dengan Flag AI dan Konektivitas Keluar

AlloyDB terhubung langsung ke endpoint SaaS aman TypeSafe AI (https://api.typesafe.ai/v1/systemone) melalui HTTPS keluar. Oleh karena itu, Anda harus menentukan --outbound-public-ip. Selain itu, konfigurasi flag database AI AlloyDB untuk lingkungan:

gcloud alloydb instances create $ADBINSTANCE \
    --instance-type=PRIMARY \
    --cpu-count=2 \
    --region=$REGION \
    --cluster=$ADBCLUSTER \
    --outbound-public-ip \
    --ssl-mode=ALLOW_UNENCRYPTED_AND_ENCRYPTED \
    --database-flags=\
google_ml_integration.enable_model_support=on,\
google_ml_integration.enable_ai_query_engine=on,\
google_ml_integration.enable_ai_function_acceleration=on,\
google_ml_integration.enable_cost_optimized_ai_functions=on,\
parameterized_views.enabled=on,\
password.enforce_complexity=on,\
password.min_uppercase_letters=1,\
password.min_numerical_chars=1,\
password.min_pass_length=10

4. Memuat Data E-Commerce Sampel

Untuk menguji kueri semantik yang realistis, impor contoh set data e-commerce yang berisi katalog produk dan ulasan pelanggan langsung dari Cloud Storage:

gcloud alloydb clusters import $ADBCLUSTER \
    --region=$REGION \
    --project=$PROJECT_ID \
    --gcs-uri="gs://sample-data-and-media/ecomm-retail/ecom_generic.sql" \
    --sql \
    --database=postgres \
    --user=postgres

4. Menyimpan Kunci API TypeSafe AI di Secret Manager

Pengelolaan Endpoint Model AlloyDB terintegrasi secara native dengan Google Secret Manager untuk mengautentikasi panggilan API eksternal tanpa memaparkan kredensial teks biasa dalam kode database atau log konfigurasi.

1. Buat Secret

Di Cloud Shell, buat secret baru bernama typesafe-jev-api-key:

gcloud secrets create typesafe-jev-api-key \
  --replication-policy="automatic"

Tambahkan kunci API TypeSafe AI Anda sebagai versi rahasia:

echo -n "<YOUR_TYPESAFE_API_KEY>" | \
  gcloud secrets versions add typesafe-jev-api-key --data-file=-

2. Memberikan Akses ke Agen Layanan AlloyDB

AlloyDB menggunakan agen layanan project-nya untuk mengambil secret selama eksekusi kueri. Temukan nomor project Anda dan berikan peran Secret Accessor:

PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
ALLOYDB_SA="service-${PROJECT_NUMBER}@gcp-sa-alloydb.iam.gserviceaccount.com"

gcloud secrets add-iam-policy-binding typesafe-jev-api-key \
  --member="serviceAccount:${ALLOYDB_SA}" \
  --role="roles/secretmanager.secretAccessor"

Anda akan melihat output yang mengonfirmasi bahwa agen layanan telah menerima roles/secretmanager.secretAccessor.

5. Menghubungkan ke AlloyDB melalui AlloyDB Studio dan Menginisialisasi Ekstensi Database

Untuk berinteraksi dengan database AlloyDB langsung dari browser tanpa mengonfigurasi alat klien lokal atau tunnel proxy, gunakan AlloyDB Studio di Konsol Google Cloud.

1. Membuka AlloyDB Studio

  1. Di Konsol Google Cloud, buka AlloyDB untuk PostgreSQL > Clusters.
  2. Klik cluster Anda (my-alloydb-cluster).
  3. Di menu navigasi sebelah kiri, klik AlloyDB Studio.
  4. Lakukan autentikasi ke database:
    • Database: postgres
    • Pengguna: postgres
    • Password: Masukkan $PGPASSWORD yang dibuat selama pembuatan cluster (misalnya, jalankan echo $PGPASSWORD di Cloud Shell untuk melihatnya).
  5. Klik Autentikasikan.

Sekarang Anda berada di editor kueri SQL interaktif AlloyDB Studio.

2. Mengaktifkan Ekstensi & Flag Database

Di editor kueri AlloyDB Studio, tempel dan jalankan pernyataan berikut untuk mengaktifkan ekstensi google_ml_integration dan mengonfigurasi setelan runtime:

-- Enable the AlloyDB AI integration extension
CREATE EXTENSION IF NOT EXISTS google_ml_integration;

-- Enable preview AI functions (ai.analyze_sentiment, ai.classify)
SET google_ml_integration.enable_preview_ai_functions = 'on';

-- Disable async batching for the session to use custom transform functions directly
SET google_ml_integration.enable_async_operation = 'off';

Klik Run untuk menjalankan kueri.

3. Mendaftarkan Secret di AlloyDB MEM

Memberi tahu AlloyDB tempat menemukan kunci API TypeSafe AI Anda:

CALL google_ml.create_sm_secret(
    secret_id => 'jev_api_key',
    secret_path => 'projects/<YOUR_PROJECT_ID>/secrets/typesafe-jev-api-key/versions/latest'
);

6. Membuat Fungsi Transformasi SQL

System One API TypeSafe AI menerima JSON terstruktur dengan primitif penalaran yang berbeda (noul untuk batasan Boolean, choice untuk klasifikasi kelas jamak).

Pengelolaan Endpoint Model AlloyDB menggunakan empat fungsi transformasi (input skalar, output skalar, input batch, output batch) untuk menjembatani tanda tangan fungsi ai.* PostgreSQL standar ke format Jev REST API.

1. Transformasi Input Skalar

Tambahkan fungsi berikut untuk mengonversi panggilan ai.if dan ai.analyze_sentiment baris tunggal menjadi payload permintaan Jev:

CREATE OR REPLACE FUNCTION public.jev_model_input_transform(
    model_id VARCHAR(100),
    input_text TEXT,
    generation_config JSON,
    system_instruction TEXT
) RETURNS JSON
LANGUAGE plpgsql IMMUTABLE AS $$
DECLARE
    full_instruction TEXT;
    enum_json JSON;
    criteria_obj JSONB := '{}'::JSONB;
    elem TEXT;
    q_obj JSON;
BEGIN
    -- Combine optional system instructions with the input prompt
    IF system_instruction IS NOT NULL AND length(trim(system_instruction)) > 0 THEN
        full_instruction := system_instruction || E'\n\n' || input_text;
    ELSE
        full_instruction := input_text;
    END IF;

    -- Inspect generation_config to determine whether caller expects a multi-class choice or boolean
    enum_json := COALESCE(
        generation_config->'generationConfig'->'responseSchema'->'enum',
        generation_config->'responseSchema'->'enum'
    );

    IF enum_json IS NOT NULL AND json_typeof(enum_json) = 'array' THEN
        -- Multi-class classification (ai.analyze_sentiment) -> Jev choice primitive
        FOR elem IN SELECT json_array_elements_text(enum_json) LOOP
            criteria_obj := criteria_obj || jsonb_build_object(elem, 'Category: ' || elem);
        END LOOP;
        q_obj := json_build_object(
            'type', 'choice',
            'instructions', full_instruction,
            'criteria', criteria_obj::JSON
        );
    ELSE
        -- Boolean filtering (ai.if) -> Jev noul primitive
        q_obj := json_build_object(
            'type', 'noul',
            'instructions', full_instruction
        );
    END IF;

    RETURN json_build_object(
        'model', 'jev-latest',
        'state', COALESCE(generation_config->>'state', 'Evaluate the question accurately based on the provided text.'),
        'questions', json_build_object('q_1', q_obj)
    );
END;
$$;

2. Transformasi Output Skalar

Tambahkan fungsi untuk mengurai respons JSON Jev kembali menjadi hasil TEXT PostgreSQL:

CREATE OR REPLACE FUNCTION public.jev_model_output_transform(
    model_id VARCHAR(100),
    response_json JSON
) RETURNS TEXT
LANGUAGE plpgsql IMMUTABLE AS $$
DECLARE
    q_ans JSON := response_json->'answers'->'q_1';
    ans_type TEXT := q_ans->>'type';
BEGIN
    IF ans_type = 'choice' THEN
        RETURN q_ans->>'choice';
    ELSIF ans_type = 'noul' THEN
        -- Convert probability score (0.00 to 1.00) to boolean text
        RETURN CASE WHEN (q_ans->>'noul')::FLOAT >= 0.50 THEN 'true' ELSE 'false' END;
    ELSE
        RAISE EXCEPTION 'Unexpected Jev response payload: %', response_json::TEXT;
    END IF;
END;
$$;

3. Transformasi Input Batch

Jev dapat mengevaluasi puluhan pertanyaan secara bersamaan dalam satu round-trip HTTP tanpa penurunan generatif.

Tambahkan transformasi input batch untuk mengonversi array prompts TEXT[] PostgreSQL menjadi pertanyaan Jev q_1 .. q_N paralel:

CREATE OR REPLACE FUNCTION public.jev_model_batch_input_transform(
    model_id VARCHAR(100),
    prompts TEXT[],
    generation_config JSON,
    system_instructions JSON
) RETURNS JSON
LANGUAGE plpgsql IMMUTABLE AS $$
DECLARE
    questions_obj JSONB := '{}'::JSONB;
    enum_json JSON;
    criteria_obj JSONB := '{}'::JSONB;
    elem TEXT;
    is_choice BOOLEAN := FALSE;
    i INT;
BEGIN
    enum_json := COALESCE(
        generation_config->'generationConfig'->'responseSchema'->'items'->'enum',
        generation_config->'generationConfig'->'responseSchema'->'enum',
        generation_config->'responseSchema'->'items'->'enum',
        generation_config->'responseSchema'->'enum'
    );

    IF enum_json IS NOT NULL AND json_typeof(enum_json) = 'array' THEN
        IF NOT (enum_json::JSONB = '["true", "false"]'::JSONB OR enum_json::JSONB = '["false", "true"]'::JSONB) THEN
            is_choice := TRUE;
            FOR elem IN SELECT json_array_elements_text(enum_json) LOOP
                criteria_obj := criteria_obj || jsonb_build_object(elem, 'Category: ' || elem);
            END LOOP;
        END IF;
    END IF;

    -- Construct parallel questions for every prompt in the array
    FOR i IN 1 .. COALESCE(array_length(prompts, 1), 0) LOOP
        IF is_choice THEN
            questions_obj := questions_obj || jsonb_build_object(
                'q_' || i::TEXT,
                jsonb_build_object(
                    'type', 'choice',
                    'instructions', prompts[i],
                    'criteria', criteria_obj
                )
            );
        ELSE
            questions_obj := questions_obj || jsonb_build_object(
                'q_' || i::TEXT,
                jsonb_build_object(
                    'type', 'noul',
                    'instructions', prompts[i]
                )
            );
        END IF;
    END LOOP;

    RETURN json_build_object(
        'model', 'jev-latest',
        'state', COALESCE(generation_config->>'state', 'Evaluate each question independently based on the record data.'),
        'questions', questions_obj::JSON
    );
END;
$$;

4. Transformasi Output Batch

Tambahkan fungsi untuk mengekstrak jawaban dalam urutan indeks array 1..N yang tepat:

CREATE OR REPLACE FUNCTION public.jev_model_batch_output_transform(
    model_id VARCHAR(100),
    response JSON
) RETURNS TEXT[]
LANGUAGE plpgsql IMMUTABLE AS $$
DECLARE
    results TEXT[] := ARRAY[]::TEXT[];
    answers JSON := response->'answers';
    i INT := 1;
    q_ans JSON;
    ans_type TEXT;
BEGIN
    LOOP
        q_ans := answers->('q_' || i::TEXT);
        EXIT WHEN q_ans IS NULL;
        ans_type := q_ans->>'type';
        IF ans_type = 'choice' THEN
            results := array_append(results, q_ans->>'choice');
        ELSE
            results := array_append(results, CASE WHEN (q_ans->>'noul')::FLOAT >= 0.50 THEN 'true' ELSE 'false' END);
        END IF;
        i := i + 1;
    END LOOP;
    RETURN results;
END;
$$;

7. Mendaftarkan Endpoint Model Kustom di AlloyDB

Sekarang Anda akan mengikat fungsi transformasi, kredensial rahasia, dan endpoint REST AI TypeSafe menjadi model terdaftar bernama jev-model.

1. Mendaftarkan jev-model

Di editor kueri AlloyDB Studio, tempel dan jalankan:

-- Drop previous registration if updating
DO $$
BEGIN
    IF EXISTS (SELECT 1 FROM google_ml.model_info_view WHERE model_id = 'jev-model') THEN
        CALL google_ml.drop_model('jev-model');
    END IF;
END $$;

-- Register custom LLM endpoint
CALL google_ml.create_model(
    model_id => 'jev-model',
    model_request_url => 'https://api.typesafe.ai/v1/systemone',
    model_provider => 'custom',
    model_type => 'llm',
    model_qualified_name => 'jev-latest',
    model_auth_type => 'secret_manager',
    model_auth_id => 'jev_api_key',
    model_in_transform_fn => 'jev_model_input_transform',
    model_out_transform_fn => 'jev_model_output_transform',
    model_batch_in_transform_fn => 'jev_model_batch_input_transform',
    model_batch_out_transform_fn => 'jev_model_batch_output_transform'
);

2. Verifikasi Pendaftaran

Buat kueri tampilan registri model untuk memastikan jev-model aktif dan dikenali:

SELECT model_id, model_type, model_provider, model_auth_type 
FROM google_ml.model_info_view 
WHERE model_id = 'jev-model';

Anda akan melihat output yang mirip dengan:

 model_id | model_type | model_provider | model_auth_type 
----------+------------+----------------+-----------------
 jev-model  | llm        | custom         | secret_manager
(1 row)

8. Menjalankan Kueri Pengujian Terhadap Jev

Setelah jev-model terdaftar, Anda kini dapat menjalankan operasi semantik langsung di dalam kueri PostgreSQL standar.

1. Menguji Pemfilteran Boolean Skalar (ai.if)

Mengevaluasi satu pernyataan teks menggunakan ai.if:

SELECT ai.if(
    prompt => 'Is the product "North Face Waterproof Gore-Tex Hiking Jacket ($249)" suitable for rainy outdoor conditions?',
    model_id => 'jev-model'
) AS is_suitable;

Anda akan melihat output yang mirip dengan:

 is_suitable 
-------------
 true
(1 row)

2. Uji Analisis Sentimen Skalar (ai.analyze_sentiment)

Mengevaluasi masukan pelanggan ke dalam label kategoris (positive, negative, atau neutral):

SET google_ml_integration.enable_preview_ai_functions = 'on';
SELECT ai.analyze_sentiment(
    input => 'The stitching on this jacket tore on the second day and the zipper jammed completely.',
    model_id => 'jev-model'
) AS sentiment;

Anda akan melihat output yang mirip dengan:

 sentiment 
-----------
 negative
(1 row)

3. Menguji Pemfilteran Boolean yang Dikelompokkan Array

Mengevaluasi beberapa item dalam satu kueri dengan meneruskan array perintah:

SET google_ml_integration.enable_async_operation = 'off';
SELECT unnest(prompts) AS product_prompt,
       unnest(ai.if(prompts => prompts, model_id => 'jev-model')) AS is_cold_weather
FROM (
    SELECT ARRAY[
        'Is "Arctic Expedition Down Parka (-30F)" cold-weather winter outerwear?',
        'Is "Men''s Boardshorts Beach Swim Trunk" cold-weather winter outerwear?',
        'Is "Merino Wool Thermal Base Layer" cold-weather winter outerwear?'
    ] AS prompts
) b;

Anda akan melihat output yang mirip dengan:

                             product_prompt                              | is_cold_weather 
-------------------------------------------------------------------------+-----------------
 Is "Arctic Expedition Down Parka (-30F)" cold-weather winter outerwear? | true
 Is "Men's Boardshorts Beach Swim Trunk" cold-weather winter outerwear?  | false
 Is "Merino Wool Thermal Base Layer" cold-weather winter outerwear?      | false
(3 rows)

4. Menguji Kueri Tabel dengan Batching Array

Sekarang, kueri tabel ecomm.products yang dimuat sebelumnya selama penyediaan cluster, menggunakan ai.if pada batch item untuk memeriksa produk dalam katalog yang merupakan perlengkapan cuaca dingin.

Untuk menjalankan pemfilteran semantik throughput tinggi pada data tabel (misalnya, 50 baris per batch), gunakan fungsi jendela row_number() PostgreSQL untuk mengelompokkan baris ke dalam batch:

-- Evaluate a 50-row batch of real catalog items from ecomm.products
WITH numbered AS (
    SELECT 
        id, 
        name, 
        category,
        product_description,
        ((row_number() OVER (ORDER BY id) - 1) / 50) AS batch_id
    FROM ecomm.products
    ORDER BY id DESC
    LIMIT 50
),
batched AS (
    SELECT 
        batch_id,
        array_agg(id ORDER BY id) AS ids,
        array_agg(name ORDER BY id) AS names,
        array_agg(category ORDER BY id) AS categories,
        array_agg(product_description ORDER BY id) AS descs,
        ai.if(
            prompts => array_agg('Is "' || name || '" designed for cold weather winter outerwear?' ORDER BY id),
            model_id => 'jev-model'
        ) AS decisions
    FROM numbered
    GROUP BY batch_id
),
unrolled AS (
    SELECT 
        b.batch_id,
        u.id,
        u.name,
        u.category,
        u.product_description,
        u.decision AS cold_weather_gear
    FROM batched b
    CROSS JOIN LATERAL unnest(b.ids, b.names, b.categories, b.descs, b.decisions) 
      AS u(id, name, category, product_description, decision)
)
SELECT id, name, category, product_description, cold_weather_gear
FROM unrolled
WHERE cold_weather_gear = TRUE
LIMIT 5;

Anda akan melihat output yang mirip dengan:

  id   |                                 name                                 |  category   |                                                product_description                                                 | cold_weather_gear 
-------+----------------------------------------------------------------------+-------------+--------------------------------------------------------------------------------------------------------------------+-------------------
 29071 | Winter Striped Beanie with Pom                                       | Accessories | Brave the chill in style with the SoleStyle Winter Striped Beanie! This cozy beanie adds a pop of personality...  | true
 29077 | Knit Collegiate Rugby Stripe Winter Scarf & Beanie Hat Set           | Accessories | Stay cozy and show off your sporty side with our Knit Collegiate Rugby Stripe Scarf & Beanie Set...               | true
 29083 | Junction Finds Men's Muscle Wool Blend Trapper Hat                   | Accessories | Brave the elements in style with the Junction Finds Trapper Hat! This wool-blend hat will keep you warm...        | true
 29086 | Mens Soft Thermal Insulated Wrist Length Leather Gloves - Black      | Accessories | Brave the chill in style with these supple leather gloves from Gavel Goods! Lined with a soft, thermal knit...    | true
 29090 | Long Beanie-Red W16S24E                                              | Accessories | Stay cozy and stylish all season long with this vibrant red beanie from Enchant! This isn't just any hat...       | true
(5 rows)

5. Mengirim Kueri Ulasan Produk Pelanggan untuk Sentimen

Sekarang, analisis ulasan pelanggan dari tabel ecomm.product_reviews menggunakan ai.analyze_sentiment yang didukung oleh primitif choice Jev:

SET google_ml_integration.enable_preview_ai_functions = 'on'
SELECT 
    r.id,
    p.name AS product_name,
    r.rating AS customer_star_rating,
    substring(r.review_text FROM 1 FOR 70) || '...' AS review_snippet,
    ai.analyze_sentiment(
        input => r.review_text,
        model_id => 'jev-model'
    ) AS detected_sentiment
FROM ecomm.product_reviews r
JOIN ecomm.products p ON r.product_id = p.id
ORDER BY r.id
LIMIT 5;

Anda akan melihat output yang mirip dengan:

 id |                  product_name                  | customer_star_rating |                             review_snippet                              | detected_sentiment 
----+------------------------------------------------+----------------------+-------------------------------------------------------------------------+--------------------
  1 | Hugs & Kisses Juniors Peplum Skirt             |                    1 | This skirt was poorly made and the fabric felt extremely cheap for for...| negative
  2 | Bonkers Larry Full Length Pull on Pants        |                    1 | These pants are way too expensive for the terrible quality you get. Th...| negative
  3 | Gifts and Garb Brah Bra Extenders              |                    3 | These extenders are okay but nothing special. They do add a bit of ext...| neutral
  4 | Auto Forge Men's Tall Duck Traditional Coat    |                    1 | This coat is terribly stiff and heavy, making it very uncomfortable to...| negative
  5 | Weaver's Way Men's Shetland Zip Neck Sweater   |                    2 | This sweater is just okay and not really worth the high price tag. The...| negative
(5 rows)

9. Bonus: Pemberian Skor Sentimen Berkelanjutan dengan skor Jev

Meskipun fungsi AI AlloyDB seperti ai.analyze_sentiment menampilkan bucket kategoris (positive, negative, neutral), primitif score TypeSafe AI mengevaluasi nuansa di seluruh rubrik yang diurutkan dan menampilkan rating berkelanjutan yang diberi bobot ekspektasi dari 0 hingga 100.

Karena score menampilkan metadata numerik, bukan label klasifikasi teks, Anda dapat mendaftarkan endpoint model generic kustom (jev-systemone) dan memanggilnya menggunakan google_ml.predict_row.

1. Mendaftarkan Endpoint Generik

Di AlloyDB Studio, daftarkan jev-systemone dengan model_type => 'generic':

DO $$
BEGIN
    IF EXISTS (SELECT 1 FROM google_ml.model_info_view WHERE model_id = 'jev-systemone') THEN
        CALL google_ml.drop_model('jev-systemone');
    END IF;
EXCEPTION WHEN OTHERS THEN
    NULL;
END $$;

CALL google_ml.create_model(
    model_id => 'jev-systemone',
    model_request_url => 'https://api.typesafe.ai/v1/systemone',
    model_provider => 'custom',
    model_type => 'generic',
    model_qualified_name => 'jev-latest',
    model_auth_type => 'secret_manager',
    model_auth_id => 'jev_api_key'
);

2. Menjalankan Evaluasi Multi-Task (Skor Boolean + Berkelanjutan)

Mengevaluasi pemeriksaan boolean kecacatan (noul) dan intensitas sentimen berkelanjutan (score) secara bersamaan dalam satu panggilan HTTP:

SELECT jsonb_pretty(google_ml.predict_row(
    model_id => 'jev-systemone',
    request_body => json_build_object(
        'model', 'jev-latest',
        'state', 'Review for North Face Parka: "The zipper broke on day 3 and customer service refused an exchange, though the fabric itself is very soft."',
        'questions', json_build_object(
            'has_defect', json_build_object(
                'type', 'noul',
                'instructions', 'Does this review report a physical product defect or failure?'
            ),
            'satisfaction_score', json_build_object(
                'type', 'score',
                'instructions', 'Rate the customer sentiment and satisfaction on a 1-5 scale.',
                'criteria', json_build_array(
                    '1: Extremely dissatisfied / defect failure',
                    '2: Dissatisfied',
                    '3: Mixed or neutral',
                    '4: Satisfied',
                    '5: Delighted'
                )
            )
        )
    )
)::jsonb) AS jev_analysis;

Anda akan melihat output yang mirip dengan (hasil Anda mungkin berbeda):

{
  "model": "jev-1.13.0",
  "usage": {
    "input_tokens": 388,
    "output_tokens": 39
  },
  "answers": {
    "has_defect": {
      "noul": 0.98,
      "type": "noul"
    },
    "satisfaction_score": {
      "type": "score",
      "score": 0.11,
      "legend": {
        "0": "1: Extremely dissatisfied / defect failure",
        "1": "2: Dissatisfied",
        "2": "3: Mixed or neutral",
        "3": "4: Satisfied",
        "4": "5: Delighted"
      },
      "confidence": 0.91,
      "probabilities": {
        "0": 0.9,
        "1": 0.08,
        "2": 0.02,
        "3": 0.0,
        "4": 0.0
      }
    }
  }
}

Perhatikan bahwa satisfaction_score dievaluasi menjadi 11 / 100, yang secara akurat menunjukkan bahwa pelanggan memiliki pengalaman yang sebagian besar negatif meskipun mengakui bahwa kainnya lembut.

10. Pembersihan

Untuk menghindari timbulnya biaya berkelanjutan untuk resource yang dibuat selama codelab ini, bersihkan objek rahasia dan database, lalu hapus cluster AlloyDB.

1. Menghapus Resource Secret Manager

Di Cloud Shell, hapus secret yang dibuat untuk kunci API TypeSafe AI:

gcloud secrets delete typesafe-jev-api-key --quiet

2. Hapus Instance Utama dan Cluster AlloyDB

Hapus instance utama terlebih dahulu:

gcloud alloydb instances delete $ADBINSTANCE \
  --cluster=$ADBCLUSTER \
  --region=$REGION \
  --quiet

Setelah penghapusan instance selesai, hapus cluster:

gcloud alloydb clusters delete $ADBCLUSTER \
  --region=$REGION \
  --quiet

11. Selamat

Selamat! Anda telah berhasil menyediakan cluster AlloyDB Google Cloud dan mengintegrasikannya dengan TypeSafe AI System One (Jev).

Yang telah Anda pelajari

  • Cara membuat Akses Layanan Pribadi (PSA) dan menyediakan cluster serta instance utama AlloyDB untuk PostgreSQL.
  • Cara mengaktifkan --outbound-public-ip sehingga AlloyDB dapat menjangkau API SaaS HTTPS eksternal.
  • Cara menyimpan kredensial penyedia AI pihak ketiga dengan aman di Google Secret Manager dan mengikatnya ke AlloyDB.
  • Cara menulis fungsi transformasi PL/pgSQL yang menghubungkan fungsi AI PostgreSQL standar (ai.if dan ai.analyze_sentiment) ke REST API eksternal.
  • Cara mendaftarkan endpoint LLM kustom di AlloyDB menggunakan google_ml.create_model.
  • Cara menjalankan kueri SQL semantik batch throughput tinggi dan skalar secara langsung di PostgreSQL.
  • Cara menganalisis ulasan produk pelanggan asli untuk mengetahui sentimen kategoris.
  • Cara mendaftarkan endpoint model generik dan mengevaluasi skor kepuasan pelanggan berkelanjutan (0..100) melalui google_ml.predict_row.

Langkah berikutnya

Dokumen referensi