Jev-Modell von TypeSafe AI mit AlloyDB AI-Funktionen für schnelle KI-Abfragen verwenden

1. Einführung

In diesem Codelab verbinden Sie das Jev-Modell von TypeSafe AI mit AlloyDB AI. Dazu verwenden Sie die nativen KI-Funktionen von AlloyDB (ai.if, ai.analyze_sentiment und ml_predict_row). So können Sie effiziente Batch-Inferenz mit dem Jev-Modell direkt für Ihre Betriebsdaten in AlloyDB ausführen, ohne Ihre Daten zu verschieben oder komplexen anwendungsseitigen Code zu schreiben.

Aufgaben

  • Private Service Access (PSA) und einen AlloyDB for PostgreSQL-Cluster und eine primäre Instanz bereitstellen
  • VPC-Firewallregel erstellen, die Cloud Shell- und interne Verbindungen zulässt
  • E‑Commerce-Beispieldataset mit gcloud alloydb clusters import laden
  • Google Secret Manager und die google_ml_integration-Erweiterung von AlloyDB aktivieren
  • TypeSafe AI-API-Schlüssel in Secret Manager speichern und Zugriff darauf gewähren
  • PL/pgSQL-Transformationsfunktionen für Ein- und Ausgabe für die Jev-Primitive noul (boolesch) und choice (Sentiment) erstellen
  • Benutzerdefinierten jev-model-Modellendpunkt in AlloyDB registrieren
  • Skalare und Array-Batch-Semantikabfragen (ai.if und ai.analyze_sentiment) direkt in SQL ausführen
  • Kundenrezensionen nach Sentiment klassifizieren lassen mit ai.analyze_sentiment
  • (Bonus) Registrieren Sie einen generischen Endpunkt (jev-systemone) und bewerten Sie die kontinuierliche Intensität der Kundenzufriedenheit mit dem score-Primitive von Jev.

Voraussetzungen

  • Ein Webbrowser wie Chrome
  • Ein Google Cloud-Projekt mit aktivierter Abrechnungsfunktion
  • Ein TypeSafe AI-API-Schlüssel (von TypeSafe AI)

2. Hinweis

Google Cloud-Projekt wählen

Wählen Sie in der Google Cloud Console das Google Cloud-Projekt aus, das Sie verwenden möchten, oder erstellen Sie es.

Cloud Shell starten

Klicken Sie oben rechts in der Google Cloud Console auf Cloud Shell aktivieren.

Prüfen Sie, ob Ihre Cloud Shell-Sitzung authentifiziert ist:

gcloud auth list

Legen Sie Ihre Projekt-ID und Umgebungsvariablen fest:

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"

Erforderliche Google Cloud APIs aktivieren

Führen Sie diesen Befehl aus, um alle erforderlichen Google Cloud-Dienst-APIs zu aktivieren:

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

3. AlloyDB-Cluster und primäre Instanz bereitstellen

In diesem Schritt weisen Sie Ihrem VPC-Netzwerk einen IP-Adressbereich für den Zugriff auf private Dienste zu, richten privates Peering ein und stellen für Ihren AlloyDB-Cluster und Ihre primäre Instanz ausgehenden Internetzugriff bereit.

1. IP-Bereich für den Zugriff auf private Dienste erstellen

Für AlloyDB ist eine Zuweisung eines privaten IP-Bereichs in Ihrem VPC-Netzwerk (Virtual Private Cloud) erforderlich. Angenommen, Sie verwenden das default-VPC-Netzwerk:

Zuweisung des privaten IP-Bereichs erstellen:

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

Private VPC-Peering-Verbindung herstellen:

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

2. AlloyDB-Cluster erstellen

Generieren Sie ein sicheres Datenbankpasswort für den ersten postgres-Administrator:

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

So erstellen Sie einen AlloyDB-Cluster im kostenlosen Testzeitraum:

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

3. Primäre Instanz mit KI-Kennzeichnungen und ausgehender Verbindung erstellen

AlloyDB stellt über ausgehendes HTTPS eine direkte Verbindung zum sicheren SaaS-Endpunkt von TypeSafe AI (https://api.typesafe.ai/v1/systemone) her. Daher müssen Sie --outbound-public-ip angeben. Konfigurieren Sie außerdem die AlloyDB AI-Datenbank-Flags für die Umgebung:

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. E-Commerce-Beispieldaten laden

Wenn Sie realistische semantische Anfragen testen möchten, importieren Sie ein E-Commerce-Beispieldataset mit Produktkatalogen und Kundenrezensionen direkt aus 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. TypeSafe AI-API-Schlüssel in Secret Manager speichern

Die Verwaltung von AlloyDB-Modellendpunkten ist nativ in Google Secret Manager integriert, um externe API-Aufrufe zu authentifizieren, ohne Klartextanmeldedaten im Datenbankcode oder in Konfigurationslogs offenzulegen.

1. Erstellen Sie das Secret

Erstellen Sie in Cloud Shell ein neues Secret mit dem Namen typesafe-jev-api-key:

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

Fügen Sie Ihren TypeSafe AI API-Schlüssel als Secret-Version hinzu:

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

2. Zugriff auf den AlloyDB-Dienst-Agent gewähren

AlloyDB verwendet den Dienst-Agent des Projekts, um während der Ausführung von Abfragen Secrets abzurufen. So finden Sie Ihre Projektnummer und gewähren die Rolle „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"

Sie sollten eine Ausgabe sehen, die bestätigt, dass der Dienst-Agent roles/secretmanager.secretAccessor erhalten hat.

5. Über AlloyDB Studio eine Verbindung zu AlloyDB herstellen und Datenbankerweiterungen initialisieren

Wenn Sie direkt über Ihren Browser mit Ihrer AlloyDB-Datenbank interagieren möchten, ohne lokale Clienttools oder Proxy-Tunnel zu konfigurieren, verwenden Sie AlloyDB Studio in der Google Cloud Console.

1. AlloyDB Studio öffnen

  1. Rufen Sie in der Google Cloud Console AlloyDB for PostgreSQL > Cluster auf.
  2. Klicken Sie auf Ihren Cluster (my-alloydb-cluster).
  3. Klicken Sie im linken Navigationsmenü auf AlloyDB Studio.
  4. Bei der Datenbank authentifizieren:
    • Datenbank: postgres
    • Nutzer: postgres
    • Passwort: Geben Sie das $PGPASSWORD ein, das während der Clustererstellung generiert wurde (z.B. durch Ausführen von echo $PGPASSWORD in Cloud Shell).
  5. Klicken Sie auf Authentifizieren.

Sie befinden sich jetzt im interaktiven SQL-Abfrageeditor von AlloyDB Studio.

2. Datenbankerweiterungen und ‑flags aktivieren

Fügen Sie im Abfrageeditor von AlloyDB Studio die folgenden Anweisungen ein und führen Sie sie aus, um die Erweiterung google_ml_integration zu aktivieren und Laufzeiteinstellungen zu konfigurieren:

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

Klicken sie auf Run (Ausführen), um die Abfrage auszuführen.

3. Registrieren Sie das Secret in AlloyDB MEM.

Teilen Sie AlloyDB mit, wo sich Ihr TypeSafe AI API-Schlüssel befindet:

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-Transformationsfunktionen erstellen

Die System One API von TypeSafe AI akzeptiert strukturiertes JSON mit unterschiedlichen Reasoning-Primitiven (noul für boolesche Einschränkungen, choice für die Klassifizierung mit mehreren Klassen).

Die Modellendpunktverwaltung von AlloyDB verwendet vier Transformationsfunktionen (skalare Eingabe, skalare Ausgabe, Batcheingabe, Batchausgabe), um Standard-PostgreSQL-ai.*-Funktionssignaturen an das Jev-REST-API-Format anzupassen.

1. Skalare Eingabetransformation

Fügen Sie die folgende Funktion hinzu, um ai.if- und ai.analyze_sentiment-Aufrufe mit einer einzelnen Zeile in Jev-Anfrage-Payloads zu konvertieren:

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. Skalare Ausgabetransformation

Fügen Sie die Funktion hinzu, um die JSON-Antwort von Jev wieder in ein PostgreSQL-TEXT-Ergebnis zu entpacken:

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. Batch-Eingabetransformation

Jev kann Dutzende von Fragen gleichzeitig in einem einzigen HTTP-Roundtrip beantworten, ohne dass die generativen Funktionen beeinträchtigt werden.

Fügen Sie die Batch-Eingabetransformierung hinzu, um PostgreSQL-prompts TEXT[]-Arrays in parallele q_1 .. q_N-Jev-Fragen zu konvertieren:

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. Batch-Ausgabetransformation

Fügen Sie die Funktion zum Extrahieren von Antworten in der richtigen 1..N-Arrayindexreihenfolge hinzu:

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. Benutzerdefinierten Modellendpunkt in AlloyDB registrieren

Jetzt binden Sie die Transformationsfunktionen, die geheimen Anmeldedaten und den TypeSafe AI-REST-Endpunkt in einem registrierten Modell mit dem Namen jev-model zusammen.

1. jev-model registrieren

Fügen Sie im Abfrageeditor von AlloyDB Studio Folgendes ein und führen Sie es aus:

-- 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. Registrierung bestätigen

Fragen Sie die Modellregistrierungsansicht ab, um sicherzustellen, dass jev-model aktiv ist und erkannt wird:

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

Die Ausgabe sollte etwa so aussehen:

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

8. Testabfragen für Jev ausführen

Nach der Registrierung von jev-model können Sie semantische Vorgänge direkt in Standard-PostgreSQL-Abfragen ausführen.

1. Skalare boolesche Filterung testen (ai.if)

Einzelne Textanweisung mit ai.if bewerten:

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;

Die Ausgabe sollte etwa so aussehen:

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

2. Skalare Sentimentanalyse testen (ai.analyze_sentiment)

Kundenfeedback in ein kategorisches Label einordnen (positive, negative oder 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;

Die Ausgabe sollte etwa so aussehen:

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

3. Array-Batch-Filterung mit booleschen Werten testen

Sie können mehrere Elemente in einer einzelnen Anfrage auswerten, indem Sie ein Array von Prompts übergeben:

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;

Die Ausgabe sollte etwa so aussehen:

                             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. Tabellenabfragen mit Array-Batching testen

Fragen Sie nun die Tabelle ecomm.products ab, die zuvor während der Clusterbereitstellung geladen wurde, und verwenden Sie „ai.if“ für eine Gruppe von Artikeln, um zu prüfen, welche der Produkte im Katalog für kaltes Wetter geeignet sind.

Wenn Sie semantische Filterung mit hohem Durchsatz für Tabellendaten ausführen möchten (z.B. 50 Zeilen pro Batch), verwenden Sie die PostgreSQL-Fensterfunktion row_number(), um Zeilen in Batches aufzuteilen:

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

Die Ausgabe sollte etwa so aussehen:

  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. Sentiment von Kundenrezensionen abfragen

Analysieren Sie nun Kundenrezensionen aus der Tabelle ecomm.product_reviews mit ai.analyze_sentiment, unterstützt durch das choice-Primitive von 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;

Die Ausgabe sollte etwa so aussehen:

 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: Kontinuierliche Sentimentbewertung mit Jev-Score

Während die KI-Funktionen von AlloyDB wie ai.analyze_sentiment kategorische Bereiche (positive, negative, neutral) zurückgeben, bewertet das score-Primitive von TypeSafe AI Nuancen anhand eines geordneten Bewertungsschemas und gibt eine kontinuierliche, erwartungsgewichtete Bewertung von 0 bis 100 zurück.

Da score numerische Metadaten anstelle eines Labels für die Textklassifizierung zurückgibt, können Sie einen benutzerdefinierten generic-Modellendpunkt (jev-systemone) registrieren und ihn mit google_ml.predict_row aufrufen.

1. Allgemeinen Endpunkt registrieren

Registrieren Sie in AlloyDB Studio jev-systemone mit 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. Multi-Task-Evaluierung ausführen (boolescher + kontinuierlicher Wert)

Sowohl eine boolesche Prüfung auf Fehler (noul) als auch die kontinuierliche Sentimentintensität (score) gleichzeitig in einem einzelnen HTTP-Aufruf auswerten:

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;

Die Ausgabe sollte in etwa so aussehen (Ihre Ergebnisse können abweichen):

{
  "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 wurde als 11 / 100 bewertet. Das bedeutet, dass der Kunde trotz der Anerkennung, dass der Stoff weich war, insgesamt eine überwiegend negative Erfahrung gemacht hat.

10. Bereinigen

Um laufende Gebühren für Ressourcen zu vermeiden, die während dieses Codelabs erstellt wurden, bereinigen Sie das Secret und die Datenbankobjekte und löschen Sie den AlloyDB-Cluster.

1. Secret Manager-Ressourcen löschen

Löschen Sie in Cloud Shell das Secret, das für den TypeSafe AI-API-Schlüssel erstellt wurde:

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

2. Primäre AlloyDB-Instanz und -Cluster löschen

Löschen Sie zuerst die primäre Instanz:

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

Löschen Sie den Cluster, nachdem das Löschen der Instanz abgeschlossen ist:

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

11. Glückwunsch

Glückwunsch! Sie haben einen Google Cloud AlloyDB-Cluster bereitgestellt und in TypeSafe AI System One (Jev) integriert.

Das haben Sie gelernt

  • So richten Sie den Zugriff auf private Dienste (Private Service Access, PSA) ein und stellen einen AlloyDB for PostgreSQL-Cluster und eine primäre Instanz bereit.
  • So aktivieren Sie --outbound-public-ip, damit AlloyDB externe HTTPS-SaaS-APIs erreichen kann.
  • So speichern Sie Anmeldedaten von Drittanbietern für KI-Anbieter sicher in Google Secret Manager und binden sie an AlloyDB.
  • So schreiben Sie PL/pgSQL-Transformationsfunktionen, die Standard-PostgreSQL-KI-Funktionen (ai.if und ai.analyze_sentiment) mit externen REST APIs verbinden.
  • So registrieren Sie benutzerdefinierte LLM-Endpunkte in AlloyDB mit google_ml.create_model.
  • So führen Sie sowohl skalare als auch Batch-Semantik-SQL-Abfragen mit hohem Durchsatz direkt in PostgreSQL aus.
  • So analysieren Sie echte Kundenrezensionen nach kategorischem Sentiment.
  • So registrieren Sie einen allgemeinen Modellendpunkt und werten kontinuierliche Kundenzufriedenheitswerte (0..100) über google_ml.predict_row aus.

Nächste Schritte

Referenzdokumente