Korzystanie z modelu Jev od TypeSafe AI z funkcjami AI AlloyDB do szybkiego wykonywania zapytań AI

1. Wprowadzenie

W tym ćwiczeniu połączysz model Jev od TypeSafe AI z AlloyDB AI za pomocą natywnych funkcji AI AlloyDB (ai.if, ai.analyze_sentiment i ml_predict_row). Umożliwi Ci to wydajne wnioskowanie wsadowe przy użyciu modelu Jev bezpośrednio na danych operacyjnych w AlloyDB bez przenoszenia danych ani pisania złożonego kodu po stronie aplikacji.

Jakie zadania wykonasz

  • Udostępnianie dostępu do usług prywatnych (PSA) oraz klastra i instancji głównej AlloyDB for PostgreSQL
  • Tworzenie reguły zapory sieciowej VPC zezwalającej na Cloud Shell i połączenia wewnętrzne
  • Wczytywanie przykładowego zbioru danych e-commerce za pomocą narzędzia gcloud alloydb clusters import
  • Włącz Google Secret Manager i rozszerzenie google_ml_integration AlloyDB
  • Przechowywanie klucza interfejsu TypeSafe AI API w usłudze Secret Manager i przyznawanie do niego dostępu
  • Tworzenie funkcji transformacji danych wejściowych i wyjściowych PL/pgSQL dla typów pierwotnych Jev noul (wartość logiczna) i choice (sentyment)
  • Zarejestruj niestandardowy punkt końcowy modelu jev-model w AlloyDB
  • Uruchamianie skalarnych i tablicowych zapytań semantycznych (ai.if i ai.analyze_sentiment) bezpośrednio w SQL
  • Wyszukiwanie opinii o produktach dodanych przez prawdziwych klientów w celu klasyfikacji sentymentu za pomocą ai.analyze_sentiment
  • (Bonus) Zarejestruj ogólny punkt końcowy (jev-systemone) i oceniaj ciągłą intensywność zadowolenia klientów za pomocą score typu pierwotnego Jev

Czego potrzebujesz

  • przeglądarka, np. Chrome;
  • Projekt Google Cloud z włączonymi płatnościami
  • Klucz interfejsu API TypeSafe AI (z TypeSafe AI)

2. Zanim zaczniesz

Wybór projektu Google Cloud

W konsoli Google Cloud wybierz lub utwórz projekt w chmurze Google Cloud, którego chcesz użyć.

Uruchamianie Cloud Shell

W prawym górnym rogu konsoli Google Cloud kliknij Aktywuj Cloud Shell.

Sprawdź, czy sesja Cloud Shell jest uwierzytelniona:

gcloud auth list

Ustaw identyfikator projektu i zmienne środowiskowe:

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"

Włączanie wymaganych interfejsów Google Cloud API

Aby włączyć wszystkie niezbędne interfejsy API usług Google Cloud, uruchom to polecenie:

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

3. Aprowizowanie klastra AlloyDB i instancji głównej

W tym kroku przydzielisz zakres adresów IP prywatnego dostępu do usług w sieci VPC, nawiążesz prywatne połączenie równorzędne i udostępnisz klaster AlloyDB oraz instancję podstawową z dostępem do internetu wychodzącego.

1. Tworzenie zakresu adresów IP prywatnego dostępu do usług

AlloyDB wymaga przydzielenia prywatnego zakresu adresów IP w sieci VPC. Załóżmy, że używasz sieci VPC default:

Utwórz przydział zakresu prywatnych adresów IP:

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

Nawiąż prywatne połączenie równorzędne VPC:

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

2. Tworzenie klastra AlloyDB

Wygeneruj bezpieczne hasło do bazy danych dla początkowego postgres użytkownika z dostępem administracyjnym:

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

Utwórz klaster próbny AlloyDB:

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

3. Tworzenie instancji głównej z flagami AI i łącznością wychodzącą

AlloyDB łączy się bezpośrednio z bezpiecznym punktem końcowym SaaS TypeSafe AI (https://api.typesafe.ai/v1/systemone) za pomocą wychodzącego protokołu HTTPS. Dlatego musisz podać --outbound-public-ip. Dodatkowo skonfiguruj flagi bazy danych AlloyDB AI dla środowiska:

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. Wczytywanie przykładowych danych e-commerce

Aby przetestować realistyczne zapytania semantyczne, zaimportuj przykładowy zbiór danych e-commerce zawierający katalogi produktów i opinie klientów bezpośrednio z 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. Przechowywanie klucza interfejsu TypeSafe AI API w usłudze Secret Manager

Zarządzanie punktami końcowymi modelu AlloyDB jest natywnie zintegrowane z usługą Google Secret Manager, co umożliwia uwierzytelnianie zewnętrznych wywołań interfejsu API bez ujawniania danych logowania w tekście w kodzie bazy danych ani w dziennikach konfiguracji.

1. Tworzenie obiektu tajnego

W Cloud Shell utwórz nowy obiekt tajny o nazwie typesafe-jev-api-key:

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

Dodaj klucz interfejsu TypeSafe AI API jako wersję obiektu tajnego:

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

2. Przyznawanie dostępu agentowi usługi AlloyDB

AlloyDB używa agenta usługi projektu do pobierania obiektów tajnych podczas wykonywania zapytań. Znajdź numer projektu i przyznaj rolę uzyskującego dostęp do obiektu tajnego:

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"

Powinno pojawić się potwierdzenie, że agent usługi otrzymał roles/secretmanager.secretAccessor.

5. Łączenie się z AlloyDB za pomocą AlloyDB Studio i inicjowanie rozszerzeń bazy danych

Aby wchodzić w interakcje z bazą danych AlloyDB bezpośrednio z przeglądarki bez konfigurowania lokalnych narzędzi klienta ani tuneli proxy, użyj AlloyDB Studio w konsoli Google Cloud.

1. Otwieranie AlloyDB Studio

  1. W konsoli Google Cloud otwórz AlloyDB for PostgreSQL > Klastry.
  2. Kliknij klaster (my-alloydb-cluster).
  3. W menu nawigacyjnym po lewej stronie kliknij AlloyDB Studio.
  4. Uwierzytelnij się w bazie danych:
    • Baza danych: postgres
    • Użytkownik: postgres
    • Password (Hasło): wpisz $PGPASSWORD wygenerowane podczas tworzenia klastra (np. uruchom echo $PGPASSWORD w Cloud Shell, aby je wyświetlić).
  5. Kliknij Uwierzytelnij.

Otworzy się interaktywny edytor zapytań SQL w AlloyDB Studio.

2. Włączanie rozszerzeń i flag bazy danych

W edytorze zapytań AlloyDB Studio wklej i uruchom te instrukcje, aby włączyć rozszerzenie google_ml_integration i skonfigurować ustawienia środowiska wykonawczego:

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

Aby uruchomić zapytanie, kliknij Uruchom.

3. Rejestrowanie obiektu tajnego w AlloyDB MEM

Poinformuj AlloyDB, gdzie znaleźć klucz interfejsu TypeSafe AI API:

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. Tworzenie funkcji przekształcenia SQL

Interfejs System One API od TypeSafe AI akceptuje uporządkowany kod JSON z odrębnymi elementami rozumowania (noul w przypadku ograniczeń logicznych, choice w przypadku klasyfikacji wieloklasowej).

Zarządzanie punktami końcowymi modeli w AlloyDB korzysta z 4 funkcji przekształcania (dane wejściowe skalarne, dane wyjściowe skalarne, dane wejściowe wsadowe, dane wyjściowe wsadowe), aby połączyć standardowe sygnatury funkcji PostgreSQL ai.* z formatem interfejsu Jev REST API.

1. Przekształcenie danych wejściowych skalarnych

Dodaj tę funkcję, aby przekształcać wywołania ai.if i ai.analyze_sentiment w ładunki żądań 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. Przekształcenie danych wyjściowych skalarnych

Dodaj funkcję, która rozpakuje odpowiedź JSON z Jeva z powrotem do wyniku 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. Przekształcenie danych wejściowych zbiorczych

Jev może oceniać dziesiątki pytań jednocześnie w ramach jednej podróży w obie strony HTTP bez pogorszenia jakości generowania.

Dodaj transformację danych wejściowych wsadowych, aby przekonwertować tablice prompts TEXT[] PostgreSQL na równoległe pytania 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. Przekształcenie danych wyjściowych zbiorczych

Dodaj funkcję wyodrębniania odpowiedzi w odpowiedniej kolejności indeksu 1..N tablicy:

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. Rejestrowanie niestandardowego punktu końcowego modelu w AlloyDB

Teraz połączesz funkcje przekształcania, tajne dane logowania i punkt końcowy REST API TypeSafe AI w zarejestrowany model o nazwie jev-model.

1. Zarejestruj jev-model

W edytorze zapytań AlloyDB Studio wklej i uruchom to zapytanie:

-- 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. Weryfikacja rejestracji

Sprawdź widok rejestru modeli, aby upewnić się, że jev-model jest aktywny i rozpoznawany:

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

Dane wyjściowe powinny być podobne do tych:

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

8. Uruchamianie zapytań testowych w Jev

Po zarejestrowaniu jev-model możesz wykonywać operacje semantyczne bezpośrednio w standardowych zapytaniach PostgreSQL.

1. Testowanie filtrowania skalarnego wartości logicznych (ai.if)

Ocena pojedynczego stwierdzenia tekstowego za pomocą funkcji 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;

Dane wyjściowe powinny być podobne do tych:

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

2. Testowanie skalarnej analizy nastawienia (ai.analyze_sentiment)

Ocena opinii klientów za pomocą etykiety kategorii (positive, negative lub 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;

Dane wyjściowe powinny być podobne do tych:

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

3. Testowanie filtrowania logicznego w przypadku tablicy z grupowaniem

Oceniaj wiele elementów w jednym zapytaniu, przekazując tablicę promptów:

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;

Dane wyjściowe powinny być podobne do tych:

                             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. Testowanie zapytań do tabeli za pomocą przetwarzania wsadowego tablic

Teraz wyślij zapytanie do tabeli ecomm.products wczytanej wcześniej podczas udostępniania klastra, używając funkcji ai.if w przypadku partii produktów, aby sprawdzić, które z nich są przeznaczone na zimną pogodę.

Aby przeprowadzić semantyczne filtrowanie danych w tabeli o wysokiej przepustowości (np. 50 wierszy na partię), użyj funkcji okna row_number() PostgreSQL, aby podzielić wiersze na partie:

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

Dane wyjściowe powinny być podobne do tych:

  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. Wysyłanie zapytań o opinię klientów o produktach

Teraz przeanalizuj opinie klientów z tabeli ecomm.product_reviews za pomocą funkcji ai.analyze_sentiment opartej na funkcji 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;

Dane wyjściowe powinny być podobne do tych:

 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: ciągłe ocenianie sentymentu za pomocą funkcji Jev score

Funkcje AI AlloyDB, takie jak ai.analyze_sentiment, zwracają kategorie (positive, negative, neutral), a funkcja score TypeSafe AI ocenia niuanse w ramach uporządkowanych kryteriów oceny i zwraca ciągłą, ważoną oczekiwaniami ocenę w zakresie 0–100.

Ponieważ score zwraca metadane numeryczne, a nie etykietę klasyfikacji tekstu, możesz zarejestrować niestandardowy punkt końcowy modelu generic (jev-systemone) i wywołać go za pomocą google_ml.predict_row.

1. Rejestrowanie ogólnego punktu końcowego

W AlloyDB Studio zarejestruj jev-systemone za pomocą 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. Przeprowadzanie oceny wielozadaniowej (wartość logiczna + wynik ciągły)

Oceniaj jednocześnie logiczną weryfikację wady (noul) i ciągłą intensywność sentymentu (score) w ramach jednego wywołania 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;

Dane wyjściowe powinny być podobne do tych (Twoje wyniki mogą się różnić):

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

Zwróć uwagę, że satisfaction_score zostało ocenione jako 11 / 100, co dokładnie odzwierciedla fakt, że klient miał w większości negatywne wrażenia, mimo że przyznał, że materiał był miękki.

10. Czyszczenie danych

Aby uniknąć obciążenia konta bieżącymi opłatami za zasoby utworzone podczas tego ćwiczenia, zwalniaj miejsce, usuwając klucz tajny i obiekty bazy danych, a także usuń klaster AlloyDB.

1. Usuwanie zasobów usługi Secret Manager

W Cloud Shell usuń klucz tajny utworzony dla klucza interfejsu TypeSafe AI API:

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

2. Usuwanie instancji głównej i klastra AlloyDB

Najpierw usuń instancję podstawową:

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

Po zakończeniu usuwania instancji usuń klaster:

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

11. Gratulacje

Gratulacje! Udało Ci się utworzyć klaster Google Cloud AlloyDB i zintegrować go z TypeSafe AI System One (Jev).

Czego się dowiesz

  • Jak skonfigurować prywatny dostęp do usług (PSA) i udostępnić klaster AlloyDB for PostgreSQL oraz instancję główną.
  • Jak włączyć --outbound-public-ip, aby AlloyDB mógł uzyskiwać dostęp do zewnętrznych interfejsów API SaaS HTTPS.
  • Jak bezpiecznie przechowywać dane logowania dostawcy AI innej firmy w Google Secret Manager i powiązać je z AlloyDB.
  • Jak pisać funkcje przekształcania PL/pgSQL, które łączą standardowe funkcje AI PostgreSQL (ai.if i ai.analyze_sentiment) z zewnętrznymi interfejsami API REST.
  • Jak rejestrować niestandardowe punkty końcowe LLM w AlloyDB za pomocą google_ml.create_model.
  • Jak wykonywać w PostgreSQL zarówno skalarne, jak i wsadowe zapytania semantyczne SQL o wysokiej przepustowości.
  • Jak analizować prawdziwe opinie klientów o produktach pod kątem nastroju.
  • Jak zarejestrować punkt końcowy modelu ogólnego i oceniać ciągłe wyniki zadowolenia klientów (0..100) za pomocą google_ml.predict_row.

Dalsze kroki

Dokumentacja