Crea un agente dati utilizzando HTTP e Python

Questa pagina ti guida nell'utilizzo di Python per effettuare richieste HTTP all'API Conversational Analytics (accessibile tramite geminidataanalytics.googleapis.com).

Il codice Python di esempio in questa pagina mostra come completare le seguenti attività:

Configura le impostazioni iniziali e l'autenticazione

Il seguente codice Python di esempio esegue queste attività:

  • Importa le librerie Python richieste.
  • Ottiene un token di accesso per l'autenticazione HTTP utilizzando Google Cloud CLI.
  • Definisce le variabili per il progetto di fatturazione, la località e le istruzioni di sistema.
  • Imposta l'endpoint API in base alla variabile location.
import json
import json as json_lib
import textwrap

import altair as alt
import google.auth
from google.auth.transport.requests import Request
import IPython
from IPython.display import display, HTML
import pandas as pd
from pygments import highlight, lexers, formatters
import requests

from google.colab import auth
auth.authenticate_user()

access_token = !gcloud auth application-default print-access-token
headers = {
        "Authorization": f"Bearer {access_token[0]}",
        "Content-Type": "application/json",
        "x-server-timeout": "300", # Custom timeout up to 600s
}

billing_project = "BILLING_PROJECT"
location = "LOCATION"
system_instruction = "SYSTEM_INSTRUCTIONS"

# Set the base URL based on location.
if not location or location == "global":
  base_url = "https://geminidataanalytics.googleapis.com"
elif "-" in location:
  # Regional endpoints
  base_url = f"https://geminidataanalytics-{location}.googleapis.com"
else:
  # Multi-regional endpoints
  base_url = f"https://geminidataanalytics.{location}.rep.googleapis.com"

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto Google Cloud in cui hai abilitato le API richieste.
  • LOCATION: la località in cui sono archiviate le risorse. Per utilizzare l'endpoint globale, specifica global. Per soddisfare i requisiti di residenza dei dati, specifica una singola regione supportata (ad esempio us-east4) o una multiregione (ad esempio eu o us). Per ulteriori informazioni, consulta Residenza dei dati.

  • SYSTEM_INSTRUCTIONS: istruzioni di sistema per guidare il comportamento dell'agente e personalizzarlo in base alle tue esigenze di dati. Ad esempio, puoi utilizzare le istruzioni di sistema per definire termini aziendali, controllare la lunghezza della risposta o impostare la formattazione dei dati. Idealmente, definisci le istruzioni di sistema utilizzando il formato YAML consigliato in Scrivi istruzioni di sistema efficaci per fornire indicazioni dettagliate e strutturate.

Autenticati in Looker

Se prevedi di connetterti a un'origine dati di Looker, dovrai eseguire l'autenticazione nell'istanza di Looker.

Utilizzo di chiavi API

Il seguente esempio di codice Python mostra come autenticare l'agente in un'istanza di Looker utilizzando le chiavi API.

looker_credentials = {
    "oauth": {
        "secret": {
            "client_id": "CLIENT_ID",
            "client_secret": "CLIENT_SECRET",
        }
    }
}

Sostituisci i valori di esempio come segue:

  • CLIENT_ID: l'ID client della chiave API Looker generata.
  • CLIENT_SECRET: il client secret della chiave API Looker generata.

Utilizzo dei token di accesso

Il seguente esempio di codice Python mostra come autenticare l'agente in un'istanza di Looker utilizzando i token di accesso.

looker_credentials = {
    "oauth": {
        "token": {
            "access_token": "ACCESS_TOKEN",
        }
    }
}

Sostituisci i valori di esempio come segue:

  • ACCESS_TOKEN: il valore access_token che generi per l'autenticazione in Looker.

Autenticati in AlloyDB per PostgreSQL

Se prevedi di connetterti a un'origine dati AlloyDB, utilizza gcloud CLI per autenticarti nell'istanza AlloyDB.

  1. Abilita l'autenticazione IAM (Identity and Access Management) su AlloyDB attivando il flag alloydb.iam_authentication sull'istanza AlloyDB.
  2. Concedere ruoli IAM. L'entità (utente o account di servizio) che chiama l'API Conversational Analytics deve disporre delle autorizzazioni IAM appropriate nel tuo progettoGoogle Cloud . In genere, sono inclusi ruoli come alloydb.databaseUser.
  3. Crea un utente del database corrispondente. Crea un utente AlloyDB che rispecchi l'entità IAM, utilizzando l'indirizzo email dell'utente o del account di servizio come nome utente.

Per saperne di più, consulta Autenticazione database IAM.

Esegui l'autenticazione in Cloud SQL per MySQL e Cloud SQL per PostgreSQL

Se prevedi di connetterti a un'origine dati Cloud SQL per MySQL o Cloud SQL per PostgreSQL, devi eseguire l'autenticazione nell'istanza Cloud SQL.

  1. Abilita l'autenticazione database IAM. Assicurati che il flag cloudsql.iam_authentication sia impostato su on nell'istanza Cloud SQL per MySQL. Puoi aggiungerlo quando crei un'istanza o quando applichi una patch a un'istanza esistente.

    gcloud sql instances patch INSTANCE_NAME --database-flags
    cloudsql.iam_authentication=on
    
  2. Concedi i ruoli IAM richiesti.

    L'entità (utente o account di servizio) che tenta di connettersi deve disporre delle autorizzazioni IAM cloudsql.instances.login e cloudsql.instances.connect sul progetto. Per concedere questi ruoli e autorizzazioni, esegui una delle seguenti operazioni:

    1. Concedi il ruolo roles/cloudsql.instanceUser. Sono incluse le autorizzazioni per accedere all'istanza (cloudsql.instances.login) e connettersi utilizzando il proxy (cloudsql.instances.connect).
    2. In alternativa, concedi un ruolo personalizzato contenente almeno cloudsql.instances.login e cloudsql.instances.connect.
  3. Aggiungi l'entità IAM come utente del database. Crea un utente nell'istanza Cloud SQL che corrisponda all'indirizzo email dell'entità IAM.

    Per un account di servizio, esegui questo comando:

    gcloud sql users create SERVICE_ACCOUNT_EMAIL --instance=INSTANCE_NAME
    --type=cloud_iam_service_account
    

    Per un account utente, esegui questo comando:

    gcloud sql users create USER_EMAIL --instance=INSTANCE_NAME
    --type=cloud_iam_user
    
  4. Concedi i privilegi del database. La connessione con IAM autentica l'utente nel database, ma non concede automaticamente le autorizzazioni nel database. Devi utilizzare i comandi PostgreSQL standard, come GRANT, per concedere a questo nuovo utente del database le autorizzazioni su oggetti specifici come tabelle e schemi.

  5. Connettiti come super utente, ad esempio l'utente postgres predefinito, ed esegui i seguenti comandi:

    -- Example: Connect using psql as the 'postgres' user
    
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO
    "user-or-service-account@example.com";
    
  6. Connettiti utilizzando l'autenticazione IAM.

    I client in genere si connettono tramite il proxy di autenticazione Cloud SQL o una libreria di connettori, che gestisce lo scambio di token. Il nome utente del database è l'indirizzo email dell'entità IAM. Le password non vengono utilizzate. Viene invece utilizzato un token OAuth 2.0, solitamente gestito automaticamente dal proxy di autenticazione Cloud SQL o da Google Cloud CLI.

    L'esempio seguente utilizza psql e gcloud CLI per generare un token:

    PGPASSWORD=$(gcloud sql generate-login-token) psql --host=HOST_IP \
    --username=IAM_PRINCIPAL_EMAIL --dbname=DATABASE_NAME\
    

    Per saperne di più, consulta Autenticazione IAM.

    Sostituisci i valori di esempio come segue:

    • INSTANCE_NAME: l'ID dell'istanza Cloud SQL di cui vuoi applicare la patch per attivare l'autenticazione IAM del database.
    • SERVICE_ACCOUNT_EMAIL: l'indirizzo email del account di servizio.
    • USER_EMAIL: l'indirizzo email dell'account utente.
    • HOST_IP: l'indirizzo IP dell'istanza Cloud SQL.
    • IAM_PRINCIPAL_EMAIL: l'indirizzo email dell'entità IAM, ad esempio un account di servizio o un utente.
    • DATABASE_NAME: il nome del database a cui connettersi.

Autenticati in Spanner

Se prevedi di connetterti a un'origine dati Spanner, devi eseguire l'autenticazione nell'istanza Spanner.

  1. Concedere ruoli IAM. L'entità (utente o account di servizio) che chiama l'API Conversational Analytics deve disporre delle autorizzazioni IAM appropriate nel tuo progettoGoogle Cloud . In genere, sono inclusi ruoli come databaseUser.
  2. Crea ruoli database astratti corrispondenti in Spanner utilizzando il Data Definition Language (DDL).
  3. Utilizza le policy IAM per consentire alle entità IAM di assumere questi ruoli database.

Per saperne di più, consulta Privilegi di controllo dell'accesso granulare.

Connetti a un'origine dati

Le sezioni seguenti mostrano come definire i dettagli di connessione per le origini dati dell'agente. L'agente può connettersi ai dati nei seguenti modi:

Connettiti ai dati di Looker

Il seguente codice campione definisce una connessione a un'esplorazione di Looker. Per stabilire una connessione con un'istanza di Looker, verifica di aver generato le chiavi API Looker, come descritto in Autenticati e connettiti a un'origine dati. Con l'API Conversational Analytics puoi connetterti a un massimo di cinque esplorazioni di Looker alla volta.

looker_instance_uri = "INSTANCE_URI"
looker_data_source = {
    "looker": {
        "explore_references": [
            {
                "looker_instance_uri": looker_instance_uri,
                "lookml_model": "MODEL",
                "explore": "EXPLORE",
            },
            {
                "looker_instance_uri": looker_instance_uri,
                "lookml_model": "MODEL_2",
                "explore": "EXPLORE_2",
            },
            # Add up to 5 total Explore references
        ],
    }
}

Sostituisci i valori di esempio come segue:

  • INSTANCE_URI: l'URL completo dell'istanza di Looker (ad esempio https://mycompany.looker.com).
  • MODEL: il nome del modello LookML che include l'esplorazione a cui vuoi connetterti.
  • EXPLORE: il nome dell'esplorazione di Looker su cui vuoi che l'agente per i dati esegua query.
  • MODEL_2: il nome del secondo modello LookML che include l'esplorazione a cui vuoi connetterti. Puoi ripetere questa variabile per altri modelli per un massimo di cinque esplorazioni.
  • EXPLORE_2: il nome dell'esplorazione di Looker aggiuntiva su cui vuoi che l'agente per i dati esegua query. Puoi ripetere questa variabile per includere fino a cinque esplorazioni.

Per saperne di più sulla connessione alle esplorazioni di Looker, inclusi i ruoli richiesti, consulta Connettiti a Looker.

Connettiti ai dati di BigQuery

Le sezioni seguenti mostrano come connettersi ai dati di BigQuery utilizzando riferimenti a tabelle, riferimenti a grafici o entrambi. Per saperne di più sulla connessione a tabelle e grafici, inclusi i ruoli richiesti, consulta Connettiti a BigQuery.

Connettiti alle tabelle BigQuery

Il seguente codice campione definisce una connessione a più tabelle BigQuery e include esempi di campi di contesto strutturati facoltativi.

bigquery_data_sources = {
    "bq": {
        "tableReferences": [
            {
                "projectId": "PROJECT_ID",
                "datasetId": "DATASET_ID",
                "tableId": "TABLE_ID",
                "schema": {
                    "description": "TABLE_DESCRIPTION",
                    "fields": [{
                        "name": "COLUMN_NAME",
                        "description": "COLUMN_DESCRIPTION"
                    }]
                }
            },
            {
                "projectId": "PROJECT_ID_2",
                "datasetId": "DATASET_ID_2",
                "tableId": "TABLE_ID_2"
            },
            {
                "projectId": "PROJECT_ID_3",
                "datasetId": "DATASET_ID_3",
                "tableId": "TABLE_ID_3"
            },
        ]
    }
}

Sostituisci i valori di esempio come segue:

  • PROJECT_ID: l'ID del progetto Google Cloud che contiene il set di dati e la tabella BigQuery a cui vuoi connetterti. Per connetterti a un set di dati pubblico, specifica bigquery-public-data.
  • DATASET_ID: l'ID del set di dati BigQuery.
  • TABLE_ID: l'ID della tabella BigQuery.
  • TABLE_DESCRIPTION: una descrizione facoltativa dei contenuti e dello scopo della tabella.
  • COLUMN_NAME: il nome di una colonna della tabella per cui stai fornendo una descrizione facoltativa.
  • COLUMN_DESCRIPTION: una descrizione facoltativa dei contenuti e dello scopo della colonna.

Connettiti a BigQuery Graph

Puoi anche connetterti ai grafi utilizzando BigQuery Graph. Fornisci uno o più riferimenti al grafico nel campo propertyGraphReferences.

Per informazioni sui requisiti delle versioni di BigQuery e sulle limitazioni delle query sui grafi, consulta Connettiti a BigQuery Graph.

bigquery_data_sources = {
    "bq": {
        "propertyGraphReferences": [
          {
            "projectId": "GRAPH_PROJECT_ID",
            "datasetId": "GRAPH_DATASET_ID",
            "propertyGraphId": "GRAPH_ID"
          }
        ]
    }
}

Sostituisci i valori di esempio come segue:

  • GRAPH_PROJECT_ID: l'ID del progetto Google Cloud che contiene il grafo BigQuery.
  • GRAPH_DATASET_ID: l'ID del set di dati BigQuery che contiene il grafo.
  • GRAPH_ID: l'ID del grafo BigQuery.

Per eseguire query sia su tabelle che su grafici con lo stesso agente per i dati, includi sia tableReferences che propertyGraphReferences nell'oggetto bq.

Connettiti ai dati di Data Studio

Il seguente codice campione definisce una connessione a un'origine dati di Data Studio.

looker_studio_data_source = {
    "studio":{
        "studio_references": [
            {
              "studio_datasource_id": "studio_datasource_id"
            }
        ]
    }
}

Sostituisci studio_datasource_id con l'ID origine dati.

Connettiti ai dati di AlloyDB

L'API Conversational Analytics utilizza un campo database_reference nel campo alloydb per connettersi al cluster AlloyDB.

L'esempio seguente definisce una connessione a un database AlloyDB.

alloydb_data_source = {
    "alloydb": {
        "database_reference":
          {
            "project_id":"PROJECT_ID",
            "region":"REGION",
            "cluster_id":"CLUSTER_ID",
            "instance_id":"INSTANCE_ID",
            "database_id":"DATABASE",
            "table_ids":["TABLE_1_ID", "TABLE_2_ID"]
          }
          # Optional: Include this if you have pre-authored context for the agent
          # "agent_context_reference": {
          #     "context_set_id": f"projects/billing_project/locations/location/contextSets/your_context_set_id"
          # }

    }
}

Sostituisci i valori di esempio come segue:

  • PROJECT_ID: l'ID del progetto Google Cloud che contiene il cluster AlloyDB.
  • REGION: la regione in cui si trova il cluster AlloyDB, ad esempio us-central1.
  • CLUSTER_ID: l'ID del cluster AlloyDB.
  • INSTANCE_ID: l'ID dell'istanza AlloyDB.
  • DATABASE: il nome del database di destinazione, ad esempio financial.
  • TABLE_1_ID, TABLE_2_ID: facoltativo. Un elenco delle tabelle nel database che l'agente per i dati dovrebbe utilizzare, ad esempio "loan", "client", "disp".
  • billing_project: l'ID del progetto di fatturazione in cui hai abilitato le API richieste.
  • location: la località in cui si trova il set di contesto, ad esempio global.
  • your_context_set_id: se hai creato un contesto avanzato per l'agente, l'ID del set di contesti.

Connettiti ai dati di Cloud SQL per MySQL e Cloud SQL per PostgreSQL

L'API Conversational Analytics utilizza un campo database_reference nel campo sql per connettersi all'istanza Cloud SQL.

L'esempio seguente definisce una connessione a un database Cloud SQL per MySQL o Cloud SQL per PostgreSQL.

sql_data_source = {
    "cloud_sql_reference": {
        "database_reference":
          {
            "project_id":"PROJECT_ID",
            "region":"REGION",
            "cluster_id":"CLUSTER_ID",
            "instance_id":"INSTANCE_ID",
            "database_id":"DATABASE_ID",
            "table_ids":["TABLE_1_ID", "TABLE_2_ID"]
          }
          # Optional: Include this if you have pre-authored context for the agent
          # "agent_context_reference": {
          #     "context_set_id": f"projects/billing_project/locations/location/contextSets/your_context_set_id"
          # }
    }
}

Sostituisci i valori di esempio come segue:

  • PROJECT_ID: l'ID del progetto Google Cloud che contiene l'istanza Cloud SQL.
  • REGION: la regione in cui si trova l'istanza Cloud SQL, ad esempio us-central1.
  • CLUSTER_ID: l'ID del cluster Cloud SQL.
  • INSTANCE_ID: l'ID dell'istanza Cloud SQL.
  • DATABASE_ID: il nome del database di destinazione, ad esempio financial.
  • TABLE_1_ID, TABLE_2_ID: facoltativo. Un elenco delle tabelle nel database che l'agente per i dati dovrebbe utilizzare, ad esempio "loan", "client", "disp".
  • billing_project: l'ID del progetto di fatturazione in cui hai abilitato le API richieste.
  • location: la località in cui si trova il set di contesto, ad esempio global.
  • your_context_set_id: se hai creato un contesto avanzato per l'agente, l'ID del set di contesti.

Connettiti ai dati di Spanner

L'API Conversational Analytics utilizza un campo database_reference nel campo spanner per connettersi alla tua istanza Spanner.

L'esempio seguente definisce una connessione a un database Spanner.

spanner_data_sources = {
    "spanner_reference": {
        "database_reference": {
            "project_id": "PROJECT_ID",
            "region": location,
            "engine": GOOGLE_SQL,
            "instance_id": "INSTANCE_ID",
            "database_id": "DATABASE",
            "table_ids":["TABLE_1_ID", "TABLE_2_ID"]
        },
        # Optional: Include this if you have pre-authored context for the agent
        # "agent_context_reference": {
        #     "context_set_id": f"projects/billing_project/locations/location/contextSets/your_context_set_id"
        # }
    }
}

Sostituisci i valori di esempio come segue:

  • PROJECT_ID: l'ID del progetto Google Cloud che contiene l'istanza Spanner.
  • INSTANCE_ID: l'ID dell'istanza Spanner.
  • DATABASE: il nome del database di destinazione, ad esempio financial.
  • TABLE_1_ID, TABLE_2_ID: un elenco delle tabelle nel database che l'agente per i dati dovrebbe utilizzare, ad esempio "loan", "client", "disp".
  • billing_project: l'ID del progetto di fatturazione in cui hai abilitato le API richieste.
  • location: la località in cui si trova il set di contesto, ad esempio global.
  • your_context_set_id: se hai creato un contesto avanzato per l'agente, l'ID del set di contesti.

Crea un agente per i dati

Il seguente codice campione mostra come creare l'agente per i dati in modo sincrono o asincrono inviando una richiesta HTTP POST all'endpoint di creazione dell'agente per i dati. Il payload della richiesta include i seguenti dettagli:

Facoltativamente, puoi proteggere l'agente per i dati con chiavi di crittografia gestite dal cliente (CMEK) includendo il campo kms_key nel payload della richiesta quando crei l'agente per i dati. Per saperne di più, consulta Chiavi di crittografia gestite dal cliente (CMEK).

Se vuoi, puoi anche attivare l'analisi avanzata con Python includendo il parametro options nel payload della richiesta. Per saperne di più sul parametro options e sulle opzioni che puoi configurare per la conversazione, consulta Risorsa REST: projects.locations.dataAgents.

Sincrona

data_agent_url = f"https://geminidataanalytics.googleapis.com/v1beta/projects/{billing_project}/locations/{location}/dataAgents:createSync"

data_agent_id = "DATA_AGENT_ID"

# Optional: If using CMEK, replace the empty strings with your KMS key details.
kms_project_id = ""  # KMS_PROJECT_ID (Defaults to billing_project if empty)
key_ring_name = ""   # KEY_RING_NAME
key_name = ""        # KEY_NAME
key_location = ""    # KEY_LOCATION (Defaults to location if empty; except eu)

data_agent_payload = {
      "name": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}", # Optional
      "description": "This is the description of the data agent.", # Optional
      "data_analytics_agent": {
          "published_context": {
              "datasource_references": bigquery_data_sources,
              "system_instruction": system_instruction,
              "options": {
                  # Optional: To enable advanced analysis with Python
                  "analysis": {
                      "python": {
                          "enabled": True
                      }
                  },
                  # Optional: To limit query costs to 100MiB
                  "datasource": {
                      "bigQueryMaxBilledBytes": "104857600"
                  }
              }
          }
      }
  }

# If key details are provided, construct and add the kms_key field.
if key_ring_name and key_name:
  if not kms_project_id:
    kms_project_id = billing_project
  if not key_location:
    key_location = location
  data_agent_payload["kms_key"] = f"projects/{kms_project_id}/locations/{key_location}/keyRings/{key_ring_name}/cryptoKeys/{key_name}"

params = {"data_agent_id": data_agent_id} # Optional

data_agent_response = requests.post(
    data_agent_url, params=params, json=data_agent_payload, headers=headers
)

if data_agent_response.status_code == 200:
    print("Data Agent created successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error creating Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Asincrona

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents"

data_agent_id = "DATA_AGENT_ID"

# Optional: If using CMEK, replace the empty strings with your KMS key details.
kms_project_id = ""  # KMS_PROJECT_ID (Defaults to billing_project if empty)
key_ring_name = ""   # KEY_RING_NAME
key_name = ""        # KEY_NAME
key_location = ""    # KEY_LOCATION (Defaults to location if empty; except eu)

data_agent_payload = {
      "name": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}", # Optional
      "description": "This is the description of the data agent.", # Optional
      "data_analytics_agent": {
          "published_context": {
              "datasource_references": bigquery_data_sources,
              "system_instruction": system_instruction,
              "options": {
                  # Optional: To enable advanced analysis with Python
                  "analysis": {
                      "python": {
                          "enabled": True
                      }
                  },
                  # Optional: To limit query costs to 100MiB
                  "datasource": {
                      "bigQueryMaxBilledBytes": "104857600"
                  }
              }
          }
      }
  }

# If key details are provided, construct and add the kms_key field.
if key_ring_name and key_name:
  if not kms_project_id:
    kms_project_id = billing_project
  if not key_location:
    key_location = location
  data_agent_payload["kms_key"] = f"projects/{kms_project_id}/locations/{key_location}/keyRings/{key_ring_name}/cryptoKeys/{key_name}"

params = {"data_agent_id": data_agent_id} # Optional

data_agent_response = requests.post(
    data_agent_url, params=params, json=data_agent_payload, headers=headers
)

if data_agent_response.status_code == 200:
    print("Data Agent created successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error creating Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Sostituisci i valori di esempio come segue:

  • DATA_AGENT_ID: un identificatore univoco per l'agente per i dati. Questo valore viene utilizzato nel nome della risorsa dell'agente e come parametro di query dell'URL data_agent_id.
  • KMS_PROJECT_ID: Se si utilizza CMEK, l'ID progetto in cui è ospitata la chiave. Se non viene fornito, il valore predefinito è il progetto di fatturazione.
  • KEY_RING_NAME: se utilizzi CMEK, il nome della tua raccolta di chiavi Cloud KMS.
  • KEY_NAME: se utilizzi CMEK, il nome della chiave Cloud KMS.
  • KEY_LOCATION: se utilizzi CMEK, la posizione delle chiavi automatizzate. Per la multi-regione eu, utilizza europe. Per tutte le altre località, utilizza la stessa località dell'agente per i dati. Se non viene fornita, per impostazione predefinita viene utilizzata la località dell'agente per i dati, che funziona per tutte le località, ad eccezione della multiregione eu. Per saperne di più, consulta Requisiti per la località delle chiavi.
  • This is the description of the data agent.: una descrizione dell'agente per i dati.

Crea una conversazione

Il seguente codice campione mostra come creare una conversazione con l'agente per i dati.

Se vuoi, puoi proteggere la conversazione con CMEK includendo il campo kms_key nel payload della richiesta quando crei la conversazione. Per saperne di più, consulta Chiavi di crittografia gestite dal cliente (CMEK).

conversation_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/conversations"

data_agent_id = "DATA_AGENT_ID"
conversation_id = "CONVERSATION_ID"

# Optional: If using CMEK, replace the empty strings with your KMS key details.
kms_project_id = ""  # KMS_PROJECT_ID (Defaults to billing_project if empty)
key_ring_name = ""   # KEY_RING_NAME
key_name = ""        # KEY_NAME
key_location = ""    # KEY_LOCATION (Defaults to location if empty; single regions only)

conversation_payload = {
    "agents": [
        f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}"
    ],
    "name": f"projects/{billing_project}/locations/{location}/conversations/{conversation_id}",
}

# If key details are provided, construct and add the kms_key field.
if key_ring_name and key_name:
  if not kms_project_id:
    kms_project_id = billing_project
  if not key_location:
    key_location = location
  conversation_payload["kms_key"] = f"projects/{kms_project_id}/locations/{key_location}/keyRings/{key_ring_name}/cryptoKeys/{key_name}"

params = {
    "conversation_id": conversation_id
}

conversation_response = requests.post(conversation_url, headers=headers, params=params, json=conversation_payload)

if conversation_response.status_code == 200:
    print("Conversation created successfully!")
    print(json.dumps(conversation_response.json(), indent=2))
else:
    print(f"Error creating Conversation: {conversation_response.status_code}")
    print(conversation_response.text)

Sostituisci i valori di esempio come segue:

  • DATA_AGENT_ID: l'ID dell'agente per i dati, come definito nel blocco di codice campione in Crea un agente per i dati.
  • CONVERSATION_ID: un identificatore univoco della conversazione.
  • KMS_PROJECT_ID: Se si utilizza CMEK, l'ID progetto in cui è ospitata la chiave. Se non viene fornito, il valore predefinito è il progetto di fatturazione.
  • KEY_RING_NAME: se utilizzi CMEK, il nome della tua raccolta di chiavi Cloud KMS.
  • KEY_NAME: se utilizzi CMEK, il nome della chiave Cloud KMS.
  • KEY_LOCATION: se utilizzi CMEK, la posizione delle chiavi automatizzate. Per la multi-regione us, utilizza us-central1. Per la multi-regione eu, utilizza europe-west1. Per una singola regione, utilizza la stessa regione della conversazione. Se non viene fornita, per impostazione predefinita viene utilizzata la località della conversazione, che funziona solo per singole regioni. Per saperne di più, consulta Requisiti per la località delle chiavi.

Gestisci gli agenti per i dati e le conversazioni

I seguenti esempi di codice mostrano come gestire gli agenti per i dati e le conversazioni utilizzando l'API Conversational Analytics. Puoi eseguire le seguenti attività:

Ottieni un agente per i dati

Il seguente codice campione mostra come recuperare un agente per i dati esistente inviando una richiesta HTTP GET all'URL della risorsa dell'agente per i dati.

data_agent_id = "DATA_AGENT_ID"
data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}"

data_agent_response = requests.get(
    data_agent_url, headers=headers
)

if data_agent_response.status_code == 200:
    print("Fetched Data Agent successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error: {data_agent_response.status_code}")
    print(data_agent_response.text)

Nell'esempio precedente, sostituisci DATA_AGENT_ID con l'ID dell'agente per i dati che vuoi recuperare.

Elenca gli agenti per i dati

Il codice seguente mostra come elencare tutti gli agenti per i dati per un determinato progetto inviando una richiesta HTTP GET all'endpoint dataAgents.

Per elencare tutti gli agenti, devi disporre dell'autorizzazione geminidataanalytics.dataAgents.list per il progetto. Per saperne di più su quali ruoli IAM includono questa autorizzazione, consulta l'elenco dei ruoli predefiniti.

billing_project = "BILLING_PROJECT"
data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents"

data_agent_response = requests.get(
    data_agent_url, headers=headers
)

if data_agent_response.status_code == 200:
    print("Data Agents Listed successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Listing Data Agents: {data_agent_response.status_code}")

Sostituisci BILLING_PROJECT con l'ID del tuo progetto di fatturazione.

Elenca gli agenti per i dati accessibili

Il codice seguente mostra come elencare tutti gli agenti per i dati accessibili per un determinato progetto inviando una richiesta HTTP GET all'endpoint dataAgents:listAccessible.

billing_project = "BILLING_PROJECT"
creator_filter = "CREATOR_FILTER"
data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents:listAccessible"

params = {
    "creator_filter": creator_filter
}

data_agent_response = requests.get(
    data_agent_url, headers=headers, params=params
)

if data_agent_response.status_code == 200:
    print("Accessible Data Agents Listed successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Listing Accessible Data Agents: {data_agent_response.status_code}")

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • CREATOR_FILTER: il filtro da applicare in base al creator dell'agente per i dati. I valori possibili includono NONE (predefinito), CREATOR_ONLY e NOT_CREATOR_ONLY.

Aggiorna un agente per i dati

Il seguente codice campione mostra come aggiornare un agente per i dati in modo sincrono o asincrono inviando una richiesta HTTP PATCH all'URL della risorsa dell'agente per i dati. Il payload della richiesta include i nuovi valori per i campi che vuoi modificare e i parametri della richiesta includono un parametro updateMask, che specifica i campi da aggiornare.

Sincrona

data_agent_id = "DATA_AGENT_ID"
billing_project = "BILLING_PROJECT"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}:updateSync"

payload = {
    "description": "Updated description of the data agent.",
    "data_analytics_agent": {
        "published_context": {
            "datasource_references": bigquery_data_sources,
            "system_instruction": system_instruction
        }
    },
}

fields = ["description", "data_analytics_agent"]
params = {
    "updateMask": ",".join(fields)
}

data_agent_response = requests.patch(
    data_agent_url, headers=headers, params=params, json=payload
)

if data_agent_response.status_code == 200:
    print("Data Agent updated successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Updating Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Asincrona

data_agent_id = "DATA_AGENT_ID"
billing_project = "BILLING_PROJECT"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}"

payload = {
    "description": "Updated description of the data agent.",
    "data_analytics_agent": {
        "published_context": {
            "datasource_references": bigquery_data_sources,
            "system_instruction": system_instruction
        }
    },
}

fields = ["description", "data_analytics_agent"]
params = {
    "updateMask": ",".join(fields)
}

data_agent_response = requests.patch(
    data_agent_url, headers=headers, params=params, json=payload
)

if data_agent_response.status_code == 200:
    print("Data Agent updated successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Updating Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Sostituisci i valori di esempio come segue:

  • DATA_AGENT_ID: l'ID dell'agente per i dati che vuoi aggiornare.
  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • Updated description of the data agent.: una nuova descrizione per l'agente per i dati.

Ottieni la policy IAM per un agente per i dati

Il seguente codice campione mostra come recuperare la policy IAM per un agente per i dati inviando una richiesta HTTP POST all'URL dell'agente per i dati. Il payload della richiesta include il percorso dell'agente per i dati.

billing_project = "BILLING_PROJECT"
data_agent_id = "DATA_AGENT_ID"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}:getIamPolicy"

# Request body
payload = {
    "resource": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}"
}

data_agent_response = requests.post(
    data_agent_url, headers=headers, json=payload
)

if data_agent_response.status_code == 200:
    print("IAM Policy fetched successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error fetching IAM policy: {data_agent_response.status_code}")
    print(data_agent_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • DATA_AGENT_ID: l'ID dell'agente per i dati per cui vuoi ottenere la policy IAM.

Imposta la policy IAM per un agente per i dati

Per condividere un agente, puoi utilizzare il metodo setIamPolicy per assegnare ruoli IAM agli utenti su un agente specifico. Il seguente codice campione mostra come effettuare una chiamata POST all'URL dell'agente per i dati con un payload che include le associazioni. L'associazione specifica quali ruoli devono essere assegnati a quali utenti.

billing_project = "BILLING_PROJECT"
data_agent_id = "DATA_AGENT_ID"
role = "roles/geminidataanalytics.dataAgentEditor"
users = "222larabrown@gmail.com, cloudysanfrancisco@gmail.com"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}:setIamPolicy"

# Request body
payload = {
    "policy": {
        "bindings": [
            {
                "role": role,
                "members": [
                    f"user:{i.strip()}" for i in users.split(",")
                ]
            }
        ]
    }
}

data_agent_response = requests.post(
    data_agent_url, headers=headers, json=payload
)

if data_agent_response.status_code == 200:
    print("IAM Policy set successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error setting IAM policy: {data_agent_response.status_code}")
    print(data_agent_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • DATA_AGENT_ID: l'ID dell'agente per i dati per cui vuoi impostare la policy IAM.
  • 222larabrown@gmail.com, cloudysanfrancisco@gmail.comconcedere il ruolo.

Elimina un agente per i dati

Il seguente codice campione mostra come eliminare un agente per i dati in modo sincrono o asincrono inviando una richiesta HTTP DELETE all'URL della risorsa dell'agente per i dati. Quando elimini un agente per i dati, questo entra in un periodo di eliminazione temporanea di 30 giorni durante il quale non può essere recuperato. Per saperne di più, consulta Conservazione ed eliminazione dei dati.

Sincrona

billing_project = "BILLING_PROJECT"
data_agent_id = "DATA_AGENT_ID"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}:deleteSync"

data_agent_response = requests.delete(
    data_agent_url, headers=headers
)

if data_agent_response.status_code == 200:
    print("Data Agent deleted successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Deleting Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Asincrona

billing_project = "BILLING_PROJECT"
data_agent_id = "DATA_AGENT_ID"

data_agent_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}"

data_agent_response = requests.delete(
    data_agent_url, headers=headers
)

if data_agent_response.status_code == 200:
    print("Data Agent deleted successfully!")
    print(json.dumps(data_agent_response.json(), indent=2))
else:
    print(f"Error Deleting Data Agent: {data_agent_response.status_code}")
    print(data_agent_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • DATA_AGENT_ID: l'ID dell'agente per i dati che vuoi eliminare.

Recupera una conversazione

Il seguente codice campione mostra come recuperare una conversazione esistente inviando una richiesta HTTP GET all'URL della risorsa della conversazione.

billing_project = "BILLING_PROJECT"
conversation_id = "CONVERSATION_ID"

conversation_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/conversations/{conversation_id}"

conversation_response = requests.get(conversation_url, headers=headers)

# Handle the response
if conversation_response.status_code == 200:
    print("Conversation fetched successfully!")
    print(json.dumps(conversation_response.json(), indent=2))
else:
    print(f"Error while fetching conversation: {conversation_response.status_code}")
    print(conversation_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • CONVERSATION_ID: l'ID della conversazione che vuoi recuperare.

Elenca conversazioni

Il seguente codice campione mostra come elencare le conversazioni per un determinato progetto inviando una richiesta HTTP GET all'endpoint conversations.

Per impostazione predefinita, questo metodo restituisce le conversazioni che hai creato. Gli amministratori (utenti con il ruolo IAM cloudaicompanion.topicAdmin) possono visualizzare tutte le conversazioni all'interno del progetto.

billing_project = "BILLING_PROJECT"
conversation_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/conversations"

conversation_response = requests.get(conversation_url, headers=headers)

# Handle the response
if conversation_response.status_code == 200:
    print("Conversation fetched successfully!")
    print(json.dumps(conversation_response.json(), indent=2))
else:
    print(f"Error while fetching conversation: {conversation_response.status_code}")
    print(conversation_response.text)

Sostituisci BILLING_PROJECT con l'ID del progetto di fatturazione in cui hai abilitato le API richieste.

Elenca i messaggi di una conversazione

Il seguente codice campione mostra come elencare tutti i messaggi di una conversazione inviando una richiesta HTTP GET all'endpoint messages della conversazione.

Per elencare i messaggi, devi disporre dell'autorizzazione cloudaicompanion.topics.get per la conversazione.

billing_project = "BILLING_PROJECT"

conversation_id = "CONVERSATION_ID"

conversation_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/conversations/{conversation_id}/messages"

conversation_response = requests.get(conversation_url, headers=headers)

# Handle the response
if conversation_response.status_code == 200:
    print("Conversation fetched successfully!")
    print(json.dumps(conversation_response.json(), indent=2))
else:
    print(f"Error while fetching conversation: {conversation_response.status_code}")
    print(conversation_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • CONVERSATION_ID: l'ID della conversazione per cui vuoi elencare i messaggi.

Eliminare una conversazione

Il seguente codice campione mostra come eliminare una conversazione inviando una richiesta HTTP DELETE all'URL della risorsa della conversazione. Gli amministratori (utenti con il ruolo Identity and Access Management cloudaicompanion.topicAdmin) o gli utenti con l'autorizzazione Identity and Access Management cloudaicompanion.topics.delete possono eliminare le conversazioni all'interno del progetto.

billing_project = "BILLING_PROJECT"
conversation_id = "CONVERSATION_ID"

conversation_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}/conversations/{conversation_id}"

conversation_response = requests.delete(conversation_url, headers=headers)

# Handle the response
if conversation_response.status_code == 200:
    print("Conversation deleted successfully!")
    print(json.dumps(conversation_response.json(), indent=2))
else:
    print(f"Error while deleting conversation: {conversation_response.status_code}")
    print(conversation_response.text)

Sostituisci i valori di esempio come segue:

  • BILLING_PROJECT: l'ID del progetto di fatturazione.
  • CONVERSATION_ID: l'ID della conversazione che vuoi eliminare.

Utilizza l'API per porre domande

Dopo aver creato un agente per i dati e, per la chat stateful, una conversazione, puoi inviare query all'agente.

Quando invii una query, l'API restituisce uno stream di oggetti Message. Questo stream può contenere diversi tipi di messaggi, tra cui testo, tabelle di dati e grafici. I messaggi di testo possono fornire insight sul ragionamento dell'agente, segnalare i suoi progressi o dare la risposta finale. Lo scopo di ogni messaggio è indicato dal relativo valore TextType:

  • THOUGHT: mostra il processo di pensiero interno dell'agente mentre pianifica come rispondere alla tua query. I messaggi THOUGHT forniscono informazioni dettagliate sul ragionamento e sul processo decisionale dell'agente e contengono due parti: parts[0] è il riepilogo del pensiero, che riassume brevemente il testo completo del pensiero, e parts[1] è il testo completo del pensiero.
  • PROGRESS: segnala l'avanzamento dell'agente in un'azione, ad esempio il recupero dei dati o uno strumento che viene richiamato. Questo valore viene restituito solo per le origini dati di Looker e contiene due parti: parts[0] è il riepilogo e parts[1] è il testo completo dell'avanzamento.
  • FINAL_RESPONSE: fornisce la risposta finale alla tua query.

Gli esempi nella sezione seguente utilizzano le funzioni helper definite in Funzioni Python helper per lo streaming delle risposte della chat per elaborare e visualizzare ogni messaggio nella risposta in streaming dell'API. Per indicazioni su come visualizzare questi messaggi in un'interfaccia utente quando utilizzi le origini dati di Looker, consulta Visualizza le risposte dell'agente per le origini dati di Looker.

Fai domande con la chat stateful e stateless

Puoi interagire con l'API nelle seguenti modalità principali:

  • Chat stateful: Google Cloud archivia e gestisce la cronologia delle conversazioni. La chat stateful è intrinsecamente a più turni, poiché l'API conserva il contesto dei messaggi precedenti. Devi inviare solo il messaggio corrente per ogni turno.
  • Chat stateless: la tua applicazione gestisce la cronologia delle conversazioni. Devi includere i messaggi precedenti pertinenti in ogni nuovo messaggio. Per esempi dettagliati su come gestire le conversazioni multi-turn in modalità stateless, consulta Crea una conversazione multi-turn stateless.

Gli esempi seguenti mostrano come utilizzare l'API per la chat stateful e stateless inviando una richiesta POST all'endpoint :chat.

Chat stateful

Invia una richiesta di chat stateful con un riferimento alla conversazione

Il seguente codice campione mostra come porre domande all'API utilizzando la conversazione definita nei passaggi precedenti. Questo esempio utilizza una funzione helper get_stream per trasmettere la risposta in streaming.

chat_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}:chat"

data_agent_id = "DATA_AGENT_ID"
conversation_id = "CONVERSATION_ID"

# Construct the payload
chat_payload = {
    "parent": f"projects/{billing_project}/locations/{location}",
    # "credentials": looker_credentials,
    "messages": [
        {
            "userMessage": {
                "text": "Make a bar graph for the top 5 states by the total number of airports"
            }
        }
    ],
    "conversation_reference": {
        "conversation": f"projects/{billing_project}/locations/{location}/conversations/{conversation_id}",
        "data_agent_context": {
            "data_agent": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}",
        }
    }
}

# Call the get_stream function to stream the response
get_stream(chat_url, chat_payload)

Sostituisci i valori di esempio come segue:

  • DATA_AGENT_ID: l'ID dell'agente per i dati, come definito nel blocco di codice campione in Crea un agente per i dati.
  • CONVERSATION_ID: un identificatore univoco della conversazione.
  • Make a bar graph for the top 5 states by the total number of airports è stato utilizzato come prompt di esempio.

Chat stateless

Gli esempi seguenti mostrano come inviare richieste stateless utilizzando un riferimento all'agente per i dati o un contesto incorporato.

Invia una richiesta di chat stateless con un riferimento all'agente per i dati

Il seguente codice campione mostra come porre all'API una domanda stateless utilizzando l'agente per i dati definito nei passaggi precedenti. Questo esempio utilizza una funzione helper get_stream per trasmettere la risposta in streaming.

chat_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}:chat"

data_agent_id = "DATA_AGENT_ID"

# Construct the payload
chat_payload = {
    "parent": f"projects/{billing_project}/locations/{location}",
    # "credentials": looker_credentials,
    "messages": [
        {
            "userMessage": {
                "text": "Make a bar graph for the top 5 states by the total number of airports"
            }
        }
    ],
    "data_agent_context": {
        "data_agent": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}",
    }
}

# Call the get_stream function to stream the response
get_stream(chat_url, chat_payload)

Sostituisci i valori di esempio come segue:

  • DATA_AGENT_ID: l'ID dell'agente per i dati, come definito nel blocco di codice campione in Crea un agente per i dati.
  • Make a bar graph for the top 5 states by the total number of airports è stato utilizzato come prompt di esempio.

Invia una richiesta di chat stateless con contesto incorporato

Il seguente codice campione mostra come porre all'API una domanda stateless utilizzando il contesto in linea. Questo esempio utilizza una funzione helper get_stream per riprodurre in streaming la risposta e utilizza un'origine dati BigQuery come esempio.

Se vuoi, puoi anche attivare l'analisi avanzata con Python includendo il parametro options nel payload della richiesta. Per ulteriori informazioni sul parametro options e sulle opzioni che puoi configurare per la conversazione, consulta la pagina Risorsa REST: projects.locations.dataAgents.

chat_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}:chat"

# Construct the payload
chat_payload = {
    "parent": f"projects/{billing_project}/locations/{location}",
    # "credentials": looker_credentials,
    "messages": [
        {
            "userMessage": {
                "text": "Make a bar graph for the top 5 states by the total number of airports"
            }
        }
    ],
    "inline_context": {
        "datasource_references": bigquery_data_sources,
          # Optional: To enable advanced analysis with Python, include the following options block:
          "options": {
              "analysis": {
                  "python": {
                      "enabled": True
                  }
              }
          }
    }
}

# Call the get_stream function to stream the response
get_stream(chat_url, chat_payload)

Il seguente codice campione mostra come porre all'API una domanda stateless utilizzando il contesto incorporato e un'origine dati AlloyDB come esempio.

chat_url = f"https://geminidataanalytics.googleapis.com/v1/projects/{billing_project}/locations/{location}:chat"

# The natural language question to ask the data agent
user_prompt = "What is the average loan amount in the US?"  # Replace with your question

# Construct the payload
chat_payload = {
    "parent": f"projects/{billing_project}/locations/{location}",
    # "credentials": looker_credentials,
    "messages": [
        {
            "userMessage": {
                "text": user_prompt
            }
        }
    ],
    "data_agent_context": {
          "data_agent": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}",
    }
}

print(f"Sending prompt to :chat: '{user_prompt}'")
print(f"Endpoint: {chat_url}")
print(f"Payload: {json.dumps(chat_payload, indent=2)}")

get_stream(chat_url, chat_payload)

Crea una conversazione multi-turno stateless

Per porre domande aggiuntive in una conversazione stateless, l'applicazione deve gestire il contesto della conversazione inviando l'intera cronologia dei messaggi con ogni nuova richiesta. Le conversazioni a più turni ti consentono di inviare domande aggiuntive che si basano sui turni di conversazione precedenti.

L'esempio seguente definisce e chiama una funzione multi_turn_conversation per gestire il contesto della conversazione archiviando i messaggi in un elenco. La funzione multi_turn_conversation chiama la funzione get_stream_multi_turn per analizzare la risposta dell'API di streaming e aggiornare l'elenco conversation_messages. Questo processo conserva il contesto per i turni successivi. Per il codice di get_stream_multi_turn e di altre funzioni helper richieste, consulta Funzioni helper per la chat in streaming.

chat_url = f"{base_url}/v1/projects/{billing_project}/locations/{location}:chat"

# List that is used to track previous turns and is reused across requests
conversation_messages = []

data_agent_id = "DATA_AGENT_ID"

# Helper function for calling the API
def multi_turn_conversation(msg):

  userMessage = {
      "userMessage": {
          "text": msg
      }
  }

  # Send a multi-turn request by including previous turns and the new message
  conversation_messages.append(userMessage)

  # Construct the payload
  chat_payload = {
      "parent": f"projects/{billing_project}/locations/{location}",
      # "credentials": looker_credentials,
      "messages": conversation_messages,
      # Use a data agent reference
      "data_agent_context": {
          "data_agent": f"projects/{billing_project}/locations/{location}/dataAgents/{data_agent_id}",
      },
      # Use inline context
      # "inline_context": {
      #     "datasource_references": bigquery_data_sources,
      # }
  }

  # Call the get_stream_multi_turn helper function to stream the response
  get_stream_multi_turn(chat_url, chat_payload, conversation_messages)

Nell'esempio precedente, sostituisci DATA_AGENT_ID con l'ID dell'agente per i dati, come definito nel blocco di codice campione in Crea un agente per i dati.

Puoi chiamare la funzione helper multi_turn_conversation per ogni turno della conversazione. Il seguente codice campione mostra come inviare una richiesta iniziale e poi una richiesta di follow-up basata sulla risposta precedente:

# Send first-turn request
multi_turn_conversation("Which species of tree is most prevalent?")

# Send follow-up-turn request
multi_turn_conversation("Can you show me the results as a bar chart?")

Nell'esempio precedente, sostituisci i valori di esempio come segue:

  • Which species of tree is most prevalent?: una domanda in linguaggio naturale da inviare all'agente per i dati.
  • Can you show me the results as a bar chart?: una domanda aggiuntiva che si basa sulla domanda precedente o la perfeziona.

Definisci le funzioni helper

La sezione seguente contiene le definizioni delle funzioni helper utilizzate negli esempi di codice precedenti per analizzare le risposte dell'API e visualizzare i risultati.

Funzioni helper di chat in streaming

Le seguenti funzioni analizzano e visualizzano la risposta in streaming dall'API per le richieste di chat standard (a turno singolo).

Mostra le funzioni helper per le risposte della chat in streaming

    def is_json(str):
      try:
          json_object = json_lib.loads(str)
      except ValueError as e:
          return False
      return True

    def handle_text_response(resp):
      parts = resp['parts']
      full_text = "".join(parts)
      if "\n" not in full_text and len(full_text) > 80:
        wrapped_text = textwrap.fill(full_text, width=80)
        print(wrapped_text)
      else:
        print(full_text)

    def get_property(data, field_name, default = ''):
      return data[field_name] if field_name in data else default

    def display_schema(data):
      fields = data['fields']
      df = pd.DataFrame({
        "Column": map(lambda field: get_property(field, 'name'), fields),
        "Type": map(lambda field: get_property(field, 'type'), fields),
        "Description": map(lambda field: get_property(field, 'description', '-'), fields),
        "Mode": map(lambda field: get_property(field, 'mode'), fields)
      })
      display(df)

    def display_section_title(text):
      display(HTML('<h2>{}</h2>'.format(text)))

    def format_bq_table_ref(table_ref):
      return '{}.{}.{}'.format(table_ref['projectId'], table_ref['datasetId'], table_ref['tableId'])

    def format_looker_table_ref(table_ref):
      return 'lookmlModel: {}, explore: {}, lookerInstanceUri: {}'.format(table_ref['lookmlModel'], table_ref['explore'], table_ref['lookerInstanceUri'])

    def display_datasource(datasource):
      source_name = ''

      if 'studioDatasourceId' in datasource:
        source_name = datasource['studioDatasourceId']
      elif 'lookerExploreReference' in datasource:
        source_name = format_looker_table_ref(datasource['lookerExploreReference'])
      else:
        source_name = format_bq_table_ref(datasource['bigqueryTableReference'])

      print(source_name)
      display_schema(datasource['schema'])

    def handle_schema_response(resp):
      if 'query' in resp:
        print(resp['query']['question'])
      elif 'result' in resp:
        display_section_title('Schema resolved')
        print('Data sources:')
        for datasource in resp['result']['datasources']:
          display_datasource(datasource)

    def handle_data_response(resp):
      if 'query' in resp:
        query = resp['query']
        display_section_title('Retrieval query')
        print('Query name: {}'.format(query['name']))
        if 'question' in query:
          print('Question: {}'.format(query['question']))
        if 'datasources' in query:
          print('Data sources:')
          for datasource in query['datasources']:
            display_datasource(datasource)
      elif 'generatedSql' in resp:
        display_section_title('SQL generated')
        print(resp['generatedSql'])
      elif 'result' in resp:
        display_section_title('Data retrieved')

        fields = map(lambda field: get_property(field, 'name'), resp['result']['schema']['fields'])
        dict = {}

        for field in fields:
          dict[field] = map(lambda el: get_property(el, field), resp['result']['data'])

        display(pd.DataFrame(dict))

    def handle_chart_response(resp):
      if 'query' in resp:
        print(resp['query']['instructions'])
      elif 'result' in resp:
        vegaConfig = resp['result']['vegaConfig']
        alt.Chart.from_json(json_lib.dumps(vegaConfig)).display();

    def handle_error(resp):
      display_section_title('Error')
      print('Code: {}'.format(resp['code']))
      print('Message: {}'.format(resp['message']))

    def get_stream(url, json):
      s = requests.Session()

      acc = ''

      with s.post(url, json=json, headers=headers, stream=True) as resp:
        for line in resp.iter_lines():
          if not line:
            continue

          decoded_line = str(line, encoding='utf-8')

          if decoded_line == '[{':
            acc = '{'
          elif decoded_line == '}]':
            acc += '}'
          elif decoded_line == ',':
            continue
          else:
            acc += decoded_line

          if not is_json(acc):
            continue

          data_json = json_lib.loads(acc)

          if not 'systemMessage' in data_json:
            if 'error' in data_json:
                handle_error(data_json['error'])
            continue

          if 'text' in data_json['systemMessage']:
            handle_text_response(data_json['systemMessage']['text'])
          elif 'schema' in data_json['systemMessage']:
            handle_schema_response(data_json['systemMessage']['schema'])
          elif 'data' in data_json['systemMessage']:
            handle_data_response(data_json['systemMessage']['data'])
          elif 'chart' in data_json['systemMessage']:
            handle_chart_response(data_json['systemMessage']['chart'])
          else:
            colored_json = highlight(acc, lexers.JsonLexer(), formatters.TerminalFormatter())
            print(colored_json)
            print('\n')
            acc = ''

    def get_stream_multi_turn(url, json, conversation_messages):
        s = requests.Session()

        acc = ''

        with s.post(url, json=json, headers=headers, stream=True) as resp:
            for line in resp.iter_lines():
                if not line:
                    continue

                decoded_line = str(line, encoding='utf-8')

                if decoded_line == '[{':
                    acc = '{'
                elif decoded_line == '}]':
                    acc += '}'
                elif decoded_line == ',':
                    continue
                else:
                    acc += decoded_line

                if not is_json(acc):
                    continue

                data_json = json_lib.loads(acc)
                # Store the response that will be used in the next iteration
                conversation_messages.append(data_json)

                if not 'systemMessage' in data_json:
                    if 'error' in data_json:
                        handle_error(data_json['error'])
                    continue

                if 'text' in data_json['systemMessage']:
                    handle_text_response(data_json['systemMessage']['text'])
                elif 'schema' in data_json['systemMessage']:
                    handle_schema_response(data_json['systemMessage']['schema'])
                elif 'data' in data_json['systemMessage']:
                    handle_data_response(data_json['systemMessage']['data'])
                elif 'chart' in data_json['systemMessage']:
                    handle_chart_response(data_json['systemMessage']['chart'])
                else:
                    colored_json = highlight(acc, lexers.JsonLexer(), formatters.TerminalFormatter())
                    print(colored_json)
                print('\n')
                acc = ''