การใช้โมเดล Jev ของ TypeSafe AI กับฟังก์ชัน AI ของ AlloyDB เพื่อการค้นหา AI ความเร็วสูง

1. บทนำ

ใน Codelab นี้ คุณจะได้เชื่อมต่อโมเดล Jev ของ TypeSafe AI กับ AlloyDB AI โดยใช้ฟังก์ชัน AI ดั้งเดิมของ AlloyDB (ai.if, ai.analyze_sentiment และ ml_predict_row) ซึ่งจะช่วยให้คุณเรียกใช้การอนุมานแบบเป็นกลุ่มได้อย่างมีประสิทธิภาพโดยใช้โมเดล Jev โดยตรงกับข้อมูลการดำเนินงานใน AlloyDB โดยไม่ต้องย้ายข้อมูลหรือเขียนโค้ดฝั่งแอปพลิเคชันที่ซับซ้อน

สิ่งที่คุณจะทำ

  • จัดสรร Private Service Access (PSA) และคลัสเตอร์ AlloyDB สำหรับ PostgreSQL รวมถึงอินสแตนซ์หลัก
  • สร้างกฎไฟร์วอลล์ VPC ที่อนุญาต Cloud Shell และการเชื่อมต่อภายใน
  • โหลดชุดข้อมูลตัวอย่างอีคอมเมิร์ซโดยใช้ gcloud alloydb clusters import
  • เปิดใช้ Google Secret Manager และส่วนขยาย google_ml_integration ของ AlloyDB
  • จัดเก็บและให้สิทธิ์เข้าถึงคีย์ API ของ TypeSafe AI ใน Secret Manager
  • สร้างฟังก์ชันการแปลงอินพุตและเอาต์พุต PL/pgSQL สำหรับไพรมิตีฟ noul (บูลีน) และ choice (ความรู้สึก) ของ Jev
  • ลงทะเบียนปลายทางโมเดล jev-model ที่กำหนดเองใน AlloyDB
  • เรียกใช้การค้นหาเชิงความหมายแบบสเกลาร์และแบบอาร์เรย์ (ai.if และ ai.analyze_sentiment) โดยตรงใน SQL
  • ค้นหารีวิวสินค้าจริงจากลูกค้าเพื่อการจัดประเภทความรู้สึกโดยใช้ ai.analyze_sentiment
  • (โบนัส) ลงทะเบียนปลายทางทั่วไป (jev-systemone) และประเมินความหนักของความพึงพอใจของลูกค้าอย่างต่อเนื่องโดยใช้ score Primitive ของ Jev

สิ่งที่คุณต้องมี

  • เว็บเบราว์เซอร์ เช่น Chrome
  • โปรเจ็กต์ Google Cloud ที่เปิดใช้การเรียกเก็บเงิน
  • คีย์ API ของ TypeSafe AI (จาก TypeSafe AI)

2. ก่อนเริ่มต้น

เลือกโปรเจ็กต์ Google Cloud

ในคอนโซล Google Cloud ให้เลือกหรือสร้างโปรเจ็กต์ที่อยู่ในระบบคลาวด์ Google Cloud ที่ต้องการใช้

เริ่มต้น Cloud Shell

คลิกเปิดใช้งาน Cloud Shell ที่ด้านขวาบนของคอนโซล Google Cloud

ตรวจสอบว่าเซสชัน Cloud Shell ได้รับการตรวจสอบสิทธิ์แล้ว

gcloud auth list

ตั้งค่ารหัสโปรเจ็กต์และตัวแปรสภาพแวดล้อม

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"

เปิดใช้ Google Cloud APIs ที่จำเป็น

เรียกใช้คำสั่งนี้เพื่อเปิดใช้ Google Cloud Service API ที่จำเป็นทั้งหมด

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

3. จัดสรรคลัสเตอร์และอินสแตนซ์หลักของ AlloyDB

ในขั้นตอนนี้ คุณจะจัดสรรช่วง IP ของการเข้าถึงบริการแบบส่วนตัวในเครือข่าย VPC, สร้างการ Peering แบบส่วนตัว และจัดสรรคลัสเตอร์ AlloyDB และอินสแตนซ์หลักที่มีสิทธิ์เข้าถึงอินเทอร์เน็ตขาออก

1. สร้างช่วง IP ของการเข้าถึงบริการส่วนตัว (PSA)

AlloyDB ต้องมีการจัดสรรช่วง IP ส่วนตัวในเครือข่าย Virtual Private Cloud (VPC) สมมติว่าคุณใช้defaultเครือข่าย VPC

สร้างการจัดสรรช่วง IP ส่วนตัว

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

สร้างการเชื่อมต่อการเพียร์ VPC ส่วนตัวโดยทำดังนี้

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

2. สร้างคลัสเตอร์ AlloyDB

สร้างรหัสผ่านฐานข้อมูลที่ปลอดภัยสำหรับpostgresผู้ใช้ที่เป็นผู้ดูแลระบบเริ่มต้น

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

สร้างคลัสเตอร์ AlloyDB Free Trial

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

3. สร้างอินสแตนซ์หลักด้วย Flag AI และการเชื่อมต่อขาออก

AlloyDB จะเชื่อมต่อโดยตรงกับปลายทาง SaaS ที่ปลอดภัยของ TypeSafe AI (https://api.typesafe.ai/v1/systemone) ผ่าน HTTPS ขาออก ดังนั้นคุณต้องระบุ --outbound-public-ip นอกจากนี้ ให้กำหนดค่าแฟล็กฐานข้อมูล AlloyDB AI สำหรับสภาพแวดล้อมดังนี้

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. โหลดข้อมูลอีคอมเมิร์ซตัวอย่าง

หากต้องการทดสอบการค้นหาเชิงความหมายที่สมจริง ให้นำเข้าชุดข้อมูลอีคอมเมิร์ซตัวอย่างที่มีแคตตาล็อกผลิตภัณฑ์และรีวิวจากลูกค้าโดยตรงจาก 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. จัดเก็บคีย์ API ของ TypeSafe AI ใน Secret Manager

การจัดการปลายทางของโมเดลของ AlloyDB ผสานรวมกับ Google Secret Manager โดยกำเนิดเพื่อตรวจสอบสิทธิ์การเรียก API ภายนอกโดยไม่ต้องเปิดเผยข้อมูลเข้าสู่ระบบข้อความธรรมดาในโค้ดฐานข้อมูลหรือบันทึกการกำหนดค่า

1. สร้างข้อมูลลับ

ใน Cloud Shell ให้สร้างข้อมูลลับใหม่ชื่อ typesafe-jev-api-key:

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

เพิ่มคีย์ TypeSafe AI API เป็นเวอร์ชันลับโดยทำดังนี้

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

2. ให้สิทธิ์เข้าถึง AlloyDB Service Agent

AlloyDB ใช้ตัวแทนบริการของโปรเจ็กต์เพื่อดึงข้อมูลลับในระหว่างการดำเนินการค้นหา ค้นหาหมายเลขโปรเจ็กต์และให้บทบาท 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"

คุณควรเห็นเอาต์พุตที่ยืนยันว่าตัวแทนบริการได้รับ roles/secretmanager.secretAccessor แล้ว

5. เชื่อมต่อกับ AlloyDB ผ่าน AlloyDB Studio และเริ่มต้นส่วนขยายฐานข้อมูล

หากต้องการโต้ตอบกับฐานข้อมูล AlloyDB โดยตรงจากเบราว์เซอร์โดยไม่ต้องกำหนดค่าเครื่องมือไคลเอ็นต์ในเครื่องหรือพร็อกซี ให้ใช้ AlloyDB Studio ในคอนโซล Google Cloud

1. เปิด AlloyDB Studio

  1. ใน คอนโซล Google Cloud ให้ไปที่ AlloyDB สำหรับ PostgreSQL > คลัสเตอร์
  2. คลิกคลัสเตอร์ (my-alloydb-cluster)
  3. คลิก AlloyDB Studio ในเมนูการนำทางด้านซ้าย
  4. ตรวจสอบสิทธิ์เข้าถึงฐานข้อมูล:
    • ฐานข้อมูล: postgres
    • ผู้ใช้: postgres
    • รหัสผ่าน: ป้อน$PGPASSWORDที่สร้างขึ้นระหว่างการสร้างคลัสเตอร์ (เช่น เรียกใช้ echo $PGPASSWORD ใน Cloud Shell เพื่อดู)
  5. คลิกตรวจสอบสิทธิ์

ตอนนี้คุณอยู่ในโปรแกรมแก้ไขการค้นหา SQL แบบอินเทอร์แอกทีฟของ AlloyDB Studio แล้ว

2. เปิดใช้ส่วนขยายและฟีเจอร์ของฐานข้อมูล

ในเครื่องมือแก้ไขคำค้นหา AlloyDB Studio ให้วางและเรียกใช้คำสั่งต่อไปนี้เพื่อเปิดใช้ส่วนขยาย google_ml_integration และกำหนดค่าการตั้งค่ารันไทม์

-- 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';

คลิกเรียกใช้เพื่อดำเนินการกับคำค้นหา

3. ลงทะเบียนข้อมูลลับใน MEM ของ AlloyDB

บอก AlloyDB ว่าจะดูคีย์ API ของ TypeSafe AI ได้ที่ไหน

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. สร้างฟังก์ชันการเปลี่ยนรูปแบบ SQL

API ของ System One ของ TypeSafe AI ยอมรับ JSON ที่มีโครงสร้างพร้อมด้วย Primitive การให้เหตุผลที่แตกต่างกัน (noul สำหรับข้อจำกัดบูลีน choice สำหรับการแยกประเภทแบบหลายคลาส)

การจัดการปลายทางโมเดลของ AlloyDB ใช้ฟังก์ชันการแปลง 4 ฟังก์ชัน (อินพุตสเกลาร์ เอาต์พุตสเกลาร์ อินพุตแบบกลุ่ม เอาต์พุตแบบกลุ่ม) เพื่อเชื่อมโยงลายเซ็นฟังก์ชัน ai.* ของ PostgreSQL มาตรฐานกับรูปแบบ Jev REST API

1. การแปลงอินพุตสเกลาร์

เพิ่มฟังก์ชันต่อไปนี้เพื่อแปลงการเรียก ai.if และ ai.analyze_sentiment แถวเดียวเป็นเพย์โหลดคำขอ 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. การแปลงเอาต์พุตสเกลาร์

เพิ่มฟังก์ชันเพื่อคลายการตอบกลับ JSON ของ Jev กลับไปเป็นผลลัพธ์ PostgreSQL TEXT

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. การเปลี่ยนรูปแบบอินพุตแบบกลุ่ม

Jev สามารถประเมินคำถามหลายสิบคำถามพร้อมกันภายใน HTTP Round Trip เดียวโดยไม่มีการเสื่อมถอยเชิงกำเนิด

เพิ่มการแปลงอินพุตแบบกลุ่มเพื่อแปลงอาร์เรย์ prompts TEXT[] PostgreSQL เป็นคำถาม q_1 .. q_N Jev แบบขนาน

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. การแปลงเอาต์พุตแบบกลุ่ม

เพิ่มฟังก์ชันเพื่อดึงคำตอบตาม1..Nลำดับดัชนีอาร์เรย์ที่เหมาะสม

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. ลงทะเบียนปลายทางโมเดลที่กำหนดเองใน AlloyDB

ตอนนี้คุณจะเชื่อมโยงฟังก์ชันการเปลี่ยนรูปแบบ ข้อมูลเข้าสู่ระบบลับ และปลายทาง REST ของ TypeSafe AI เข้าด้วยกันเป็นโมเดลที่ลงทะเบียนชื่อ jev-model

1. ลงทะเบียน jev-model

ในเครื่องมือแก้ไขการค้นหาของ AlloyDB Studio ให้วางและเรียกใช้คำสั่งต่อไปนี้

-- 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. ยืนยันการลงทะเบียน

ค้นหามุมมองรีจิสทรีโมเดลเพื่อให้แน่ใจว่า jev-model ใช้งานได้และระบบรู้จัก

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

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

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

8. เรียกใช้การทดสอบการค้นหาเทียบกับ Jev

เมื่อลงทะเบียน jev-model แล้ว คุณจะดำเนินการเชิงความหมายได้โดยตรงภายในคำค้นหา PostgreSQL มาตรฐาน

1. ทดสอบการกรองบูลีนสเกลาร์ (ai.if)

ประเมินข้อความเดียวโดยใช้ 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;

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

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

2. ทดสอบการวิเคราะห์ความรู้สึกแบบสเกลาร์ (ai.analyze_sentiment)

ประเมินความคิดเห็นของลูกค้าเป็นป้ายกำกับหมวดหมู่ (positive, negative หรือ 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;

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

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

3. ทดสอบการกรองบูลีนแบบอาร์เรย์

ประเมินหลายรายการในคำค้นหาเดียวโดยส่งอาร์เรย์ของพรอมต์

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;

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

                             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. ทดสอบการค้นหาตารางด้วยการจัดกลุ่มอาร์เรย์

ตอนนี้ให้ค้นหาตาราง ecomm.products ที่โหลดไว้ก่อนหน้านี้ในระหว่างการจัดสรรคลัสเตอร์ โดยใช้ ai.if กับรายการเป็นกลุ่มเพื่อตรวจสอบว่าผลิตภัณฑ์ใดในแคตตาล็อกเป็นอุปกรณ์สำหรับสภาพอากาศหนาว

หากต้องการเรียกใช้การกรองเชิงความหมายที่มีปริมาณงานสูงในข้อมูลตาราง (เช่น 50 แถวต่อกลุ่ม) ให้ใช้row_number()ฟังก์ชันสร้างกรอบข้อมูลของ PostgreSQL เพื่อแบ่งแถวออกเป็นกลุ่ม

-- 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;

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

  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. ค้นหารีวิวผลิตภัณฑ์ของลูกค้าเพื่อดูความรู้สึก

ตอนนี้คุณสามารถวิเคราะห์รีวิวของลูกค้าจากecomm.product_reviewsตารางโดยใช้ai.analyze_sentimentที่ขับเคลื่อนโดย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;

คุณควรเห็นเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้

 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. โบนัส: การให้คะแนนความรู้สึกอย่างต่อเนื่องด้วย Jev score

แม้ว่าฟังก์ชัน AI ของ AlloyDB เช่น ai.analyze_sentiment จะแสดงกลุ่มหมวดหมู่ (positive, negative, neutral) แต่ไพรมิทีฟ score ของ TypeSafe AI จะประเมินความแตกต่างในเกณฑ์การให้คะแนนที่เรียงลำดับแล้ว และแสดงคะแนนแบบต่อเนื่องที่ถ่วงน้ำหนักตามความคาดหวังตั้งแต่ 0 ถึง 100

เนื่องจาก score จะแสดงผลข้อมูลเมตาที่เป็นตัวเลขแทนป้ายกำกับการจัดประเภทข้อความ คุณจึงลงทะเบียนปลายทางโมเดล generic ที่กำหนดเอง (jev-systemone) และเรียกใช้โดยใช้ google_ml.predict_row ได้

1. ลงทะเบียนปลายทางทั่วไป

ใน AlloyDB Studio ให้ลงทะเบียน jev-systemone ด้วย 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. เรียกใช้การประเมินแบบหลายงาน (คะแนนบูลีน + คะแนนต่อเนื่อง)

ประเมินทั้งการตรวจสอบบูลีนข้อบกพร่อง (noul) และความเข้มของความรู้สึกอย่างต่อเนื่อง (score) พร้อมกันในการเรียกใช้ 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;

คุณควรเห็นเอาต์พุตที่คล้ายกับ (ผลลัพธ์ของคุณอาจแตกต่างกันไป)

{
  "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
      }
    }
  }
}

โปรดสังเกตว่า satisfaction_score ประเมินเป็น 11 / 100 ซึ่งแสดงให้เห็นอย่างถูกต้องว่าลูกค้าได้รับประสบการณ์ในเชิงลบเป็นส่วนใหญ่ แม้จะยอมรับว่าเนื้อผ้ามีความนุ่มก็ตาม

10. ล้างข้อมูล

หากไม่ต้องการให้มีการเรียกเก็บเงินอย่างต่อเนื่องสำหรับทรัพยากรที่สร้างขึ้นระหว่าง Codelab นี้ ให้ล้างข้อมูลลับและออบเจ็กต์ฐานข้อมูล แล้วลบคลัสเตอร์ AlloyDB

1. ลบทรัพยากร Secret Manager

ใน Cloud Shell ให้ลบข้อมูลลับที่สร้างขึ้นสำหรับคีย์ API ของ TypeSafe AI ดังนี้

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

2. ลบอินสแตนซ์หลักและคลัสเตอร์ AlloyDB

ลบอินสแตนซ์หลักก่อน โดยทำดังนี้

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

เมื่อการลบอินสแตนซ์เสร็จสมบูรณ์แล้ว ให้ลบคลัสเตอร์โดยทำดังนี้

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

11. ขอแสดงความยินดี

ยินดีด้วย คุณได้จัดสรรคลัสเตอร์ AlloyDB ของ Google Cloud และผสานรวมกับ TypeSafe AI System One (Jev) เรียบร้อยแล้ว

สิ่งที่คุณได้เรียนรู้

  • วิธีสร้างการเข้าถึงบริการส่วนตัว (PSA) และจัดสรรคลัสเตอร์ AlloyDB สำหรับ PostgreSQL และอินสแตนซ์หลัก
  • วิธีเปิดใช้ --outbound-public-ip เพื่อให้ AlloyDB เข้าถึง API ของ SaaS ที่ใช้ HTTPS ภายนอกได้
  • วิธีจัดเก็บข้อมูลเข้าสู่ระบบของผู้ให้บริการ AI บุคคลที่สามอย่างปลอดภัยใน Google Secret Manager และเชื่อมโยงข้อมูลดังกล่าวกับ AlloyDB
  • วิธีเขียนฟังก์ชันการแปลง PL/pgSQL ที่เชื่อมฟังก์ชัน AI มาตรฐานของ PostgreSQL (ai.if และ ai.analyze_sentiment) กับ REST API ภายนอก
  • วิธีลงทะเบียนปลายทาง LLM ที่กำหนดเองใน AlloyDB โดยใช้ google_ml.create_model
  • วิธีเรียกใช้ทั้งคำค้นหา SQL เชิงความหมายแบบสเกลาร์และแบบเป็นกลุ่มที่มีปริมาณงานสูงใน PostgreSQL โดยตรง
  • วิธีวิเคราะห์รีวิวผลิตภัณฑ์จริงของลูกค้าเพื่อดูความรู้สึกตามหมวดหมู่
  • วิธีลงทะเบียนปลายทางโมเดลทั่วไปและประเมินคะแนนความพึงพอใจของลูกค้าอย่างต่อเนื่อง (0..100) ผ่าน google_ml.predict_row

ขั้นตอนถัดไป

เอกสารอ้างอิง