פיתוח סוכן נתונים באמצעות HTTP ו-Python

בדף הזה מוסבר איך להשתמש ב-Python כדי לשלוח בקשות HTTP ל-Conversational Analytics API (דרך geminidataanalytics.googleapis.com).

קוד ה-Python לדוגמה שבדף הזה מראה איך לבצע את הפעולות הבאות:

קביעת הגדרות ראשוניות ואימות

הקוד הבא לדוגמה ב-Python מבצע את המשימות האלה:

  • מייבא את ספריות Python הנדרשות.
  • מקבל טוקן גישה לאימות HTTP באמצעות Google Cloud CLI.
  • הגדרת משתנים לפרויקט לחיוב, למיקום ולהוראות המערכת.
  • מגדירה את נקודת קצה ל-API על סמך המשתנה 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"

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט ב- Google Cloud שבו הפעלתם את ממשקי ה-API הנדרשים.
  • ‫LOCATION: המיקום שבו המשאבים מאוחסנים. כדי להשתמש בנקודת הקצה הגלובלית, מציינים את global. כדי לעמוד בדרישות של מיקום אחסון הנתונים, צריך לציין אזור נתמך אחד (כמו us-east4) או מספר אזורים (כמו eu או us). מידע נוסף זמין במאמר מיקום אחסון הנתונים.

  • ‫SYSTEM_INSTRUCTIONS: הוראות מערכת שמנחות את ההתנהגות של הסוכן ומתאימות אותו לצורכי הנתונים שלכם. לדוגמה, אתם יכולים להשתמש בהוראות למערכת כדי להגדיר מונחים עסקיים, לשלוט באורך התשובה או להגדיר פורמט נתונים. כדי לספק הנחיות מפורטות ומובנות, מומלץ להגדיר את הוראות המערכת באמצעות פורמט YAML שמומלץ במאמר כתיבת הוראות מערכת יעילות.

אימות ב-Looker

אם אתם מתכננים להתחבר למקור נתונים של Looker, תצטרכו לבצע אימות למכונה של Looker.

שימוש במפתחות API

דוגמת הקוד הבאה ב-Python ממחישה איך לאמת את הנציג שלכם במכונה של Looker באמצעות מפתחות API.

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

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫CLIENT_ID: מזהה הלקוח של מפתח Looker API שנוצר.
  • ‫CLIENT_SECRET: סוד הלקוח של מפתח ה-API שנוצר ב-Looker.

שימוש בטוקני גישה

דוגמת הקוד הבאה ב-Python ממחישה איך לאמת את הסוכן במכונה של Looker באמצעות טוקני גישה.

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

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫ACCESS_TOKEN: הערך של access_token שאתם יוצרים כדי לאמת את Looker.

אימות ב-AlloyDB ל-PostgreSQL

אם אתם מתכננים להתחבר למקור נתונים של AlloyDB, השתמשו ב-CLI של gcloud כדי לאמת את המכונה של AlloyDB.

  1. מפעילים אימות של ניהול זהויות והרשאות גישה (IAM) ב-AlloyDB על ידי הפעלת הדגל alloydb.iam_authentication במכונה של AlloyDB.
  2. להקצות תפקידי IAM. לחשבון המשתמש (המשתמש או חשבון השירות) ששולח קריאה ל-Conversational Analytics API צריכות להיות הרשאות IAM מתאימות בפרויקט ב-Google Cloud . בדרך כלל, התפקידים האלה כוללים את alloydb.databaseUser.
  3. יוצרים משתמש תואם במסד הנתונים. יוצרים משתמש ב-AlloyDB שמשקף את חשבון המשתמש ב-IAM, ומשתמשים בכתובת האימייל של המשתמש או של חשבון השירות בתור שם המשתמש.

מידע נוסף זמין במאמר אימות מסד נתונים של IAM.

אימות ב-Cloud SQL ל-MySQL וב-Cloud SQL ל-PostgreSQL

אם אתם מתכננים להתחבר למקור נתונים של Cloud SQL ל-MySQL או של Cloud SQL ל-PostgreSQL, אתם צריכים לאמת את המכונה של Cloud SQL.

  1. מפעילים אימות של מסד נתונים ב-IAM. מוודאים שהדגל cloudsql.iam_authentication מוגדר ל-on במכונה של Cloud SQL ל-MySQL. אפשר להוסיף את זה כשיוצרים מכונה או כשמתקנים מכונה קיימת.

    gcloud sql instances patch INSTANCE_NAME --database-flags
    cloudsql.iam_authentication=on
    
  2. מקצים את התפקידים הנדרשים ב-IAM.

    לחשבון המשתמש (משתמש או חשבון שירות) שמנסה להתחבר צריכות להיות הרשאות ה-IAM‏ cloudsql.instances.login ו-cloudsql.instances.connect בפרויקט. כדי להקצות את התפקידים וההרשאות האלה, צריך לבצע אחת מהפעולות הבאות:

    1. מקצים את התפקיד roles/cloudsql.instanceUser. ההרשאות האלה כוללות הרשאות כניסה למכונה (cloudsql.instances.login) והתחברות באמצעות שרת ה-proxy‏ (cloudsql.instances.connect).
    2. לחלופין, אפשר להקצות תפקיד בהתאמה אישית שכולל לפחות את ההרשאות cloudsql.instances.login ו-cloudsql.instances.connect.
  3. מוסיפים את חשבון המשתמש ב-IAM כמשתמש במסד הנתונים. יוצרים משתמש במכונה של Cloud SQL שתואם לכתובת האימייל של חשבון המשתמש ב-IAM.

    כדי להשתמש בחשבון שירות, מריצים את הפקודה הבאה:

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

    כדי להשתמש בחשבון משתמש, מריצים את הפקודה הבאה:

    gcloud sql users create USER_EMAIL --instance=INSTANCE_NAME
    --type=cloud_iam_user
    
  4. נותנים הרשאות למסד הנתונים. התחברות באמצעות IAM מאמתת את המשתמש במסד הנתונים, אבל לא מעניקה לו הרשאות באופן אוטומטי במסד הנתונים. כדי לתת למשתמש החדש במסד הנתונים הרשאות לאובייקטים ספציפיים כמו טבלאות וסכימות, צריך להשתמש בפקודות PostgreSQL רגילות, כמו GRANT.

  5. מתחברים כמשתמש-על, כמו משתמש ברירת המחדל של postgres, ומריצים את הפקודות הבאות:

    -- Example: Connect using psql as the 'postgres' user
    
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO
    "user-or-service-account@example.com";
    
  6. מתחברים באמצעות אימות IAM.

    בדרך כלל, לקוחות מתחברים באמצעות Cloud SQL Auth Proxy או ספריית מחברים שמטפלת בהחלפת האסימונים. שם המשתמש של מסד הנתונים הוא כתובת האימייל של חשבון המשתמש ב-IAM. לא משתמשים בסיסמאות. במקום זאת, משתמשים באסימון OAuth 2.0, שבדרך כלל מטופל באופן אוטומטי על ידי Cloud SQL Auth Proxy או על ידי Google Cloud CLI.

    בדוגמה הבאה משתמשים ב-psql וב-CLI של gcloud כדי ליצור טוקן:

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

    מידע נוסף מופיע במאמר אימות IAM.

    מחליפים את ערכי הדוגמה באופן הבא:

    • ‫INSTANCE_NAME: המזהה של המכונה ב-Cloud SQL שרוצים לתקן כדי להפעיל אימות של מסד נתונים ב-IAM.
    • ‫SERVICE_ACCOUNT_EMAIL: כתובת האימייל של חשבון השירות.
    • ‫USER_EMAIL: כתובת האימייל של חשבון המשתמש.
    • ‫HOST_IP: כתובת ה-IP של המכונה ב-Cloud SQL.
    • ‫IAM_PRINCIPAL_EMAIL: כתובת האימייל של חשבון המשתמש ב-IAM – לדוגמה, חשבון שירות או משתמש.
    • ‫DATABASE_NAME: שם מסד הנתונים שאליו רוצים להתחבר.

אימות ב-Spanner

אם אתם מתכננים להתחבר למקור נתונים של Spanner, אתם צריכים לאמת את המכונה של Spanner.

  1. להקצות תפקידי IAM. לחשבון המשתמש (המשתמש או חשבון השירות) ששולח קריאה ל-Conversational Analytics API צריכות להיות הרשאות IAM מתאימות בפרויקט ב-Google Cloud . בדרך כלל, התפקידים האלה כוללים את databaseUser.
  2. יוצרים תפקידים מופשטים תואמים במסד הנתונים ב-Spanner באמצעות שפת הגדרת נתונים (DDL).
  3. להשתמש בכללי מדיניות של IAM כדי לאפשר לחשבונות משתמשים ב-IAM לקבל את התפקידים האלה במסד הנתונים.

מידע נוסף זמין במאמר הרשאות לבקרת גישה מפורטת (FGAC).

חיבור של מקור נתונים

בקטעים הבאים מוסבר איך להגדיר את פרטי החיבור למקורות הנתונים של הנציג. הסוכן יכול להתחבר לנתונים בדרכים הבאות:

חיבור לנתונים ב-Looker

הקוד לדוגמה הבא מגדיר חיבור ל-Looker Explore. כדי ליצור חיבור למכונה של Looker, ודאו שיצרתם מפתחות Looker API, כמו שמתואר בקטע אימות והתחברות למקור נתונים. אתם יכולים להתחבר לעד חמישה חלונות חקירה של Looker בכל פעם באמצעות Conversational Analytics API.

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
        ],
    }
}

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫INSTANCE_URI: כתובת ה-URL המלאה של המכונה ב-Looker (לדוגמה, https://mycompany.looker.com).
  • ‫MODEL: השם של מודל LookML שכולל את ה-Explore שאליו רוצים להתחבר.
  • ‫EXPLORE: השם של חקירת Looker שרוצים שהסוכן לאינטראקציה עם נתונים ישלח אליה שאילתה.
  • ‫MODEL_2: השם של המודל השני ב-LookML שכולל את ה-Explore שאליו רוצים להתחבר. אפשר לחזור על המשתנה הזה במודלים נוספים, עד חמישה ניתוחים.
  • ‫EXPLORE_2: השם של חקירת Looker הנוספת שרוצים שהסוכן לאינטראקציה עם נתונים ישלח אליה שאילתות. אפשר לחזור על המשתנה הזה כדי לכלול עד חמישה ניתוחים.

למידע נוסף על התחברות ל-Looker Explores, כולל התפקידים הנדרשים, ראו התחברות ל-Looker.

חיבור לנתונים ב-BigQuery

בקטעים הבאים מוסבר איך להתחבר לנתוני BigQuery באמצעות הפניות לטבלאות, הפניות לתרשימים או שניהם. למידע נוסף על התחברות לטבלאות ולתרשימים, כולל התפקידים הנדרשים, קראו את המאמר התחברות ל-BigQuery.

התחברות לטבלאות ב-BigQuery

הקוד לדוגמה הבא מגדיר חיבור לכמה טבלאות ב-BigQuery וכולל דוגמאות לשדות הקשר מובנים אופציונליים.

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"
            },
        ]
    }
}

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫PROJECT_ID: המזהה של הפרויקט ב- Google Cloud שמכיל את קבוצת הנתונים והטבלה ב-BigQuery שאליהם רוצים להתחבר. כדי להתחבר למערך נתונים שגלוי לכולם, מציינים את bigquery-public-data.
  • ‫DATASET_ID: המזהה של מערך הנתונים ב-BigQuery.
  • ‫TABLE_ID: המזהה של הטבלה ב-BigQuery.
  • ‫TABLE_DESCRIPTION: תיאור אופציונלי של התוכן והמטרה של הטבלה.
  • ‫COLUMN_NAME: שם העמודה בטבלה שאתם מספקים לה תיאור אופציונלי.
  • ‫COLUMN_DESCRIPTION: תיאור אופציונלי של התוכן והמטרה של העמודה.

התחברות ל-BigQuery Graph

אפשר גם להתחבר לתרשימים באמצעות BigQuery Graph. צריך לספק הפניה אחת או יותר לתרשים בשדה propertyGraphReferences.

למידע על הדרישות של מהדורת BigQuery ועל המגבלות של שאילתות גרפים, ראו התחברות ל-BigQuery Graph.

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

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫GRAPH_PROJECT_ID: המזהה של הפרויקט ב- Google Cloud שמכיל את התרשים ב-BigQuery.
  • ‫GRAPH_DATASET_ID: המזהה של קבוצת הנתונים ב-BigQuery שמכילה את התרשים.
  • ‫GRAPH_ID: המזהה של התרשים ב-BigQuery.

כדי לשלוח שאילתות גם לטבלאות וגם לתרשימים באמצעות אותו סוכן לאינטראקציה עם נתונים, צריך לכלול גם את tableReferences וגם את propertyGraphReferences באובייקט bq.

חיבור לנתונים ב-Data Studio

הקוד לדוגמה הבא מגדיר חיבור למקור נתונים ב-Data Studio.

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

מחליפים את studio_datasource_id במזהה של מקור הנתונים.

חיבור לנתוני AlloyDB

‫Conversational Analytics API משתמש בשדה database_reference שבשדה alloydb כדי להתחבר לאשכול AlloyDB.

בדוגמה הבאה מוגדר חיבור למסד נתונים של 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"
          # }

    }
}

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫PROJECT_ID: המזהה של הפרויקט ב- Google Cloud שמכיל את אשכול AlloyDB.
  • ‫REGION: האזור שבו נמצא אשכול AlloyDB, לדוגמה us-central1.
  • ‫CLUSTER_ID: המזהה של אשכול AlloyDB.
  • ‫INSTANCE_ID: המזהה של מכונת AlloyDB.
  • ‫DATABASE: השם של מסד הנתונים המטורגט, לדוגמה financial.
  • ‫TABLE_1_ID, TABLE_2_ID: אופציונלי. רשימה של הטבלאות במסד הנתונים שהסוכן לאינטראקציה עם נתונים יכול להשתמש בהן, לדוגמה: "loan",‏ "client",‏ "disp".
  • ‫billing_project: המזהה של הפרויקט לחיוב שבו הפעלתם את ממשקי ה-API הנדרשים.
  • ‫location: המיקום שבו נמצאת קבוצת ההקשרים, לדוגמה global.
  • ‫your_context_set_id: אם יצרתם מיקוד מתקדם לפי הקשר לנציג, המזהה של קבוצת ההקשרים.

חיבור לנתונים של Cloud SQL ל-MySQL ו-Cloud SQL ל-PostgreSQL

כדי להתחבר למכונה של Cloud SQL, ב-Conversational Analytics API משתמשים בשדה database_reference שבשדה sql.

בדוגמה הבאה מוגדר חיבור למסד נתונים של Cloud SQL ל-MySQL או של Cloud SQL ל-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"
          # }
    }
}

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫PROJECT_ID: מזהה הפרויקט ב- Google Cloud שמכיל את המכונה של Cloud SQL.
  • ‫REGION: האזור שבו נמצא המכונה של Cloud SQL, לדוגמה us-central1.
  • ‫CLUSTER_ID: המזהה של אשכול Cloud SQL.
  • ‫INSTANCE_ID: המזהה של המכונה ב-Cloud SQL.
  • ‫DATABASE_ID: השם של מסד הנתונים המטורגט, לדוגמה financial.
  • ‫TABLE_1_ID, TABLE_2_ID: אופציונלי. רשימה של הטבלאות במסד הנתונים שהסוכן לאינטראקציה עם נתונים יכול להשתמש בהן, לדוגמה: "loan",‏ "client",‏ "disp".
  • ‫billing_project: המזהה של הפרויקט לחיוב שבו הפעלתם את ממשקי ה-API הנדרשים.
  • ‫location: המיקום שבו נמצאת קבוצת ההקשרים, לדוגמה global.
  • ‫your_context_set_id: אם יצרתם מיקוד מתקדם לפי הקשר לנציג, המזהה של קבוצת ההקשרים.

חיבור לנתונים ב-Spanner

‫Conversational Analytics API משתמש בשדה database_reference שבשדה spanner כדי להתחבר למכונה של Spanner.

בדוגמה הבאה מוגדר חיבור למסד נתונים של 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"
        # }
    }
}

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫PROJECT_ID: מזהה הפרויקט ב- Google Cloud שמכיל את המכונה של Spanner.
  • ‫INSTANCE_ID: המזהה של מכונת Spanner.
  • ‫DATABASE: השם של מסד הנתונים המטורגט, לדוגמה financial.
  • ‫TABLE_1_ID, ‏TABLE_2_ID: רשימה של הטבלאות במסד הנתונים שהסוכן לאינטראקציה עם נתונים יכול להשתמש בהן, לדוגמה "loan", ‏"client", ‏"disp".
  • ‫billing_project: המזהה של הפרויקט לחיוב שבו הפעלתם את ממשקי ה-API הנדרשים.
  • ‫location: המיקום שבו נמצאת קבוצת ההקשרים, לדוגמה global.
  • ‫your_context_set_id: אם יצרתם מיקוד מתקדם לפי הקשר לסוכן, המזהה של קבוצת ההקשרים.

יצירת סוכן לאינטראקציה עם נתונים

בדוגמת קוד לדוגמה הבאה מוסבר איך ליצור את סוכן לאינטראקציה עם נתונים באופן סינכרוני או אסינכרוני על ידי שליחת בקשת HTTP POST לנקודת הקצה ליצירת סוכן לאינטראקציה עם נתונים. ה-payload של הבקשה כולל את הפרטים הבאים:

  • השם המלא של המשאב של הנציג. הערך הזה כולל את מזהה הפרויקט, המיקום ומזהה ייחודי של הנציג.
  • תיאור הסוכן לאינטראקציה עם נתונים.
  • ההקשר של הסוכן לאינטראקציה עם נתונים, כולל תיאור המערכת (שמוגדר בקטע קביעת הגדרות ראשוניות ואימות) ומקור הנתונים שבו הסוכן משתמש (שמוגדר בקטע קישור למקור נתונים).

אם רוצים להגן על הסוכן לאינטראקציה עם נתונים באמצעות מפתחות הצפנה בניהול הלקוח (CMEK), צריך לכלול את השדה kms_key במטען הייעודי (payload) של הבקשה כשיוצרים את הסוכן. מידע נוסף מופיע במאמר מפתחות הצפנה בניהול הלקוח (CMEK).

אפשר גם להפעיל ניתוח מתקדם באמצעות Python על ידי הכללת הפרמטר options במטען הייעודי (payload) של הבקשה. במאמר משאב REST: ‏projects.locations.dataAgents מוסבר בהרחבה על הפרמטר options ועל האפשרויות שאפשר להגדיר לשיחה.

סינכרוני

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)

אסינכרוני

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫DATA_AGENT_ID: מזהה ייחודי של הסוכן לאינטראקציה עם נתונים. הערך הזה משמש בשם המשאב של הנציג וכפרמטר השאילתה data_agent_id של כתובת ה-URL.
  • ‫KMS_PROJECT_ID: אם משתמשים ב-CMEK, מזהה הפרויקט שבו המפתח מתארח. אם לא תציינו פרויקט, ברירת המחדל תהיה הפרויקט לחיוב.
  • ‫KEY_RING_NAME: אם משתמשים ב-CMEK, השם של אוסף המפתחות ב-Cloud KMS.
  • ‫KEY_NAME: אם משתמשים ב-CMEK, השם של מפתח Cloud KMS.
  • ‫KEY_LOCATION: אם משתמשים ב-CMEK, המיקום של אוסף המפתחות. בשביל eu במספר אזורים, משתמשים ב-europe. בכל המיקומים האחרים, צריך להשתמש באותו מיקום כמו של הסוכן לאינטראקציה עם נתונים. אם לא מציינים מיקום, כברירת מחדל נבחר המיקום של הסוכן לאינטראקציה עם נתונים, שמתאים לכל המיקומים חוץ מהמיקום eu במספר אזורים. מידע נוסף זמין במאמר דרישות לגבי מיקום המפתח.
  • ‫This is the description of the data agent.: תיאור של הסוכן לאינטראקציה עם נתונים.

יצירת שיחה

הקוד לדוגמה הבא ממחיש איך ליצור שיחה עם הסוכן לאינטראקציה עם נתונים.

אם רוצים להגן על השיחה באמצעות CMEK, אפשר לכלול את השדה kms_key במטען הייעודי (payload) של הבקשה כשיוצרים את השיחה. מידע נוסף מופיע במאמר מפתחות הצפנה בניהול הלקוח (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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים, כמו שמוגדר בבלוק הקוד לדוגמה בקטע יצירת סוכן לאינטראקציה עם נתונים.
  • ‫CONVERSATION_ID: מזהה ייחודי של השיחה.
  • ‫KMS_PROJECT_ID: אם משתמשים ב-CMEK, מזהה הפרויקט שבו המפתח מתארח. אם לא תציינו פרויקט, ברירת המחדל תהיה הפרויקט לחיוב.
  • ‫KEY_RING_NAME: אם משתמשים ב-CMEK, השם של אוסף המפתחות ב-Cloud KMS.
  • ‫KEY_NAME: אם משתמשים ב-CMEK, השם של מפתח Cloud KMS.
  • ‫KEY_LOCATION: אם משתמשים ב-CMEK, המיקום של אוסף המפתחות. בשביל us במספר אזורים, משתמשים ב-us-central1. בשביל eu במספר אזורים, משתמשים ב-europe-west1. אם אתם בוחרים אזור אחד, בחרו את האזור שבו מתנהלת השיחה. אם לא מציינים מיקום, ברירת המחדל היא המיקום של השיחה, וזה עובד רק באזורים בודדים. מידע נוסף זמין במאמר דרישות לגבי מיקום המפתח.

ניהול סוכנים לאינטראקציה עם נתונים ושיחות

דוגמאות הקוד הבאות מראות איך לנהל את הסוכנים לאינטראקציה עם נתונים ואת השיחות באמצעות Conversational Analytics API. אתם יכולים לבצע את המשימות הבאות:

אחזור של סוכן לאינטראקציה עם נתונים

הקוד לדוגמה הבא מראה איך לאחזר סוכן קיים לאינטראקציה עם נתונים על ידי שליחת בקשת HTTP GET לכתובת ה-URL של המשאב של הסוכן לאינטראקציה עם נתונים.

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)

בדוגמה הקודמת, מחליפים את DATA_AGENT_ID במזהה של הסוכן לאינטראקציה עם נתונים שרוצים לאחזר.

הצגת רשימה של סוכנים לאינטראקציה עם נתונים

בדוגמת הקוד הבאה אפשר לראות איך לשלוח בקשת HTTP GET לנקודת הקצה (endpoint) dataAgents כדי להציג את כל הסוכנים לאינטראקציה עם נתונים בפרויקט מסוים.

כדי להציג את כל הנציגים, צריכה להיות לכם הרשאת geminidataanalytics.dataAgents.list בפרויקט. למידע נוסף על תפקידי IAM שכוללים את ההרשאה הזו, עיינו ברשימה של תפקידים מוגדרים מראש.

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

מחליפים את BILLING_PROJECT במזהה של הפרויקט לחיוב.

רשימת הסוכנים לאינטראקציה עם נתונים שיש אליהם גישה

כדי להציג את כל הסוכנים לאינטראקציה עם נתונים שאפשר לגשת אליהם בפרויקט מסוים, שולחים בקשת HTTP מסוג GET לנקודת הקצה (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}")

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫CREATOR_FILTER: המסנן שיופעל על סמך היוצר של הסוכן לאינטראקציה עם נתונים. הערכים האפשריים כוללים את NONE (ברירת מחדל), CREATOR_ONLY ו-NOT_CREATOR_ONLY.

עדכון סוכן לאינטראקציה עם נתונים

בדוגמת הקוד הבאה אפשר לראות איך לעדכן סוכן לאינטראקציה עם נתונים באופן סינכרוני או אסינכרוני, על ידי שליחת בקשת HTTP PATCH לכתובת ה-URL של המשאב של הסוכן. מטען הייעודי (payload) של הבקשה כולל את הערכים החדשים של השדות שרוצים לשנות, והפרמטרים של הבקשה כוללים פרמטר updateMask שמציין את השדות שצריך לעדכן.

סינכרוני

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)

אסינכרוני

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים שרוצים לעדכן.
  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫Updated description of the data agent.: תיאור חדש לסוכן לאינטראקציה עם נתונים.

קבלת מדיניות ה-IAM של סוכן לאינטראקציה עם נתונים

הקוד לדוגמה הבא ממחיש איך לאחזר את מדיניות ה-IAM של סוכן לאינטראקציה עם נתונים, על ידי שליחת בקשת HTTP מסוג POST לכתובת ה-URL של הסוכן. המטען הייעודי (payload) של הבקשה כולל את הנתיב של הסוכן לאינטראקציה עם נתונים.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים שרוצים לקבל את מדיניות ה-IAM שלו.

הגדרת מדיניות IAM לסוכן לאינטראקציה עם נתונים

כדי לשתף נציג, אתם יכולים להשתמש בשיטה setIamPolicy כדי להקצות תפקידי IAM למשתמשים בנציג ספציפי. בדוגמת הקוד לדוגמה הבאה אפשר לראות איך מבצעים קריאת POST לכתובת ה-URL של הסוכן לאינטראקציה עם נתונים, עם מטען ייעודי (payload) שכולל קישורים. הקישור מציין אילו תפקידים צריך להקצות לאילו משתמשים.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים שרוצים להגדיר לו מדיניות IAM.
  • ‫222larabrown@gmail.com, cloudysanfrancisco@gmail.com: רשימה מופרדת בפסיקים של כתובות אימייל של משתמשים שרוצים לתת להם את התפקיד שצוין.

מחיקת סוכן לאינטראקציה עם נתונים

בדוגמת הקוד הבאה מוסבר איך למחוק סוכן לאינטראקציה עם נתונים באופן סינכרוני או אסינכרוני, על ידי שליחת בקשת HTTP DELETE לכתובת ה-URL של המשאב של הסוכן. כשמוחקים סוכן לאינטראקציה עם נתונים, הוא נכנס לתקופת מחיקה זמנית של 30 יום שבה אי אפשר לשחזר אותו. מידע נוסף זמין במאמר שמירת נתונים ומחיקה.

סינכרוני

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)

אסינכרוני

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים שרוצים למחוק.

איך מקבלים שיחה

הקוד לדוגמה הבא ממחיש איך לאחזר שיחה קיימת על ידי שליחת בקשת HTTP GET לכתובת ה-URL של משאב השיחה.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫CONVERSATION_ID: המזהה של השיחה שרוצים לאחזר.

הצגת רשימת השיחות

הקוד לדוגמה הבא ממחיש איך להציג רשימה של שיחות בפרויקט נתון על ידי שליחת בקשת HTTP GET לנקודת הקצה (endpoint) conversations.

כברירת מחדל, השיטה הזו מחזירה את השיחות שיצרתם. אדמינים (משתמשים עם תפקיד ה-IAM‏ cloudaicompanion.topicAdmin) יכולים לראות את כל השיחות בפרויקט.

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)

מחליפים את BILLING_PROJECT במזהה של הפרויקט לחיוב שבו הפעלתם את ממשקי ה-API הנדרשים.

הצגת רשימת ההודעות בשיחה

הקוד לדוגמה הבא מראה איך להציג את כל ההודעות בשיחה על ידי שליחת בקשת HTTP GET לנקודת הקצה (endpoint) messages של השיחה.

כדי להציג רשימה של הודעות, צריכה להיות לכם הרשאת cloudaicompanion.topics.get בשיחה.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫CONVERSATION_ID: המזהה של השיחה שאתם רוצים להציג את רשימת ההודעות שלה.

למחוק שיחה

הקוד לדוגמה הבא מדגים איך למחוק שיחה על ידי שליחת בקשת HTTP DELETE לכתובת ה-URL של משאב השיחה. אדמינים (משתמשים עם תפקיד cloudaicompanion.topicAdmin בניהול הזהויות והרשאות הגישה) או משתמשים עם הרשאת cloudaicompanion.topics.delete בניהול הזהויות והרשאות הגישה יכולים למחוק שיחות בפרויקט.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫BILLING_PROJECT: המזהה של הפרויקט לחיוב.
  • ‫CONVERSATION_ID: המזהה של השיחה שרוצים למחוק.

איך לשאול שאלות באמצעות ה-API

אחרי שיוצרים סוכן לאינטראקציה עם נתונים ושיחה (לצ'אט עם שמירת מצב), אפשר לשלוח שאילתות לסוכן.

כששולחים שאילתה, ה-API מחזיר זרם של אובייקטים מסוג Message. הסטרימינג הזה יכול להכיל סוגים שונים של הודעות, כולל טקסט, טבלאות נתונים ותרשימים. הודעות SMS יכולות לספק תובנות לגבי תהליך החשיבה של הסוכן, לדווח על ההתקדמות שלו או לתת את התשובה הסופית. המטרה של כל הודעת טקסט מצוינת בערך TextType שלה:

  • ‫THOUGHT: מציג את תהליך החשיבה הפנימי של הסוכן כשהוא מתכנן איך לענות על השאילתה. הודעות מסוג THOUGHT מספקות תובנות מפורטות לגבי תהליך החשיבה וקבלת ההחלטות של הנציג, והן מכילות שני חלקים: parts[0] הוא סיכום המחשבה, שמסכם בקצרה את טקסט המחשבה המלא, ו-parts[1] הוא טקסט המחשבה המלא.
  • ‫PROGRESS: דיווח על התקדמות הנציג בפעולה, כמו אחזור נתונים או הפעלת כלי. הערך הזה מוחזר רק למקורות נתונים של Looker והוא מכיל שני חלקים: parts[0] הוא הסיכום, ו-parts[1] הוא טקסט ההתקדמות המלא.
  • ‫FINAL_RESPONSE: מספק את התשובה הסופית לשאילתה.

בדוגמאות שבקטע הבא נעשה שימוש בפונקציות העזר שמוגדרות בקטע פונקציות עזר ב-Python להעברת תשובות בסטרימינג בצ'אט כדי לעבד ולהציג כל הודעה בתשובה שמועברת בסטרימינג מה-API. במאמר עיבוד תשובות של נציגים למקורות נתונים של Looker מוסבר איך לעבד את ההודעות האלה בממשק משתמש כשמשתמשים במקורות נתונים של Looker.

שליחת שאלות בשיחות עם שמירת מצב ובשיחות ללא שמירת מצב

אפשר להשתמש ב-API במצבים העיקריים הבאים:

  • צ'אט עם שמירת מצב: Google Cloud שומר ומנהל את היסטוריית השיחות. צ'אט עם שמירת מצב הוא מטבעו צ'אט עם כמה פניות, כי ה-API שומר את ההקשר מההודעות הקודמות. צריך לשלוח רק את ההודעה הנוכחית בכל תור.
  • צ'אט ללא שמירת מצב: האפליקציה שלכם מנהלת את היסטוריית השיחות. אתם צריכים לכלול את ההודעות הקודמות הרלוונטיות בכל הודעה חדשה. במאמר יצירת שיחה מרובת-שלבים בלי הקשר קודם מוסבר איך לנהל שיחות כאלה.

בדוגמאות הבאות מוסבר איך להשתמש ב-API לצ'אט עם שמירת מצב ולצ'אט בלי שמירת מצב, על ידי שליחת בקשת POST לנקודת הקצה :chat.

שיחה עם זיכרון

שליחת בקשת צ'אט עם שמירת מצב והפניה לשיחה

הקוד לדוגמה הבא מראה איך לשאול את ה-API שאלות באמצעות השיחה שהגדרתם בשלבים הקודמים. בדוגמה הזו נעשה שימוש בפונקציית עזר של get_stream כדי להעביר את התשובה בסטרימינג.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים, כמו שמוגדר בבלוק הקוד לדוגמה בקטע יצירת סוכן לאינטראקציה עם נתונים.
  • ‫CONVERSATION_ID: מזהה ייחודי של השיחה.
  • ההנחיה לדוגמה הייתה Make a bar graph for the top 5 states by the total number of airports.

צ'אט ללא שמירת מצב (stateless)

בדוגמאות הבאות מוסבר איך לשלוח בקשות בלי שמירת מצב באמצעות הפניה לסוכן לאינטראקציה עם נתונים או הקשר מוטבע.

שליחת בקשת צ'אט ללא שמירת מצב עם הפניה לסוכן לאינטראקציה עם נתונים

הקוד לדוגמה הבא מראה איך לשאול את ה-API שאלה בלי שמירת מצב באמצעות הסוכן לאינטראקציה עם נתונים שהגדרתם בשלבים הקודמים. בדוגמה הזו נעשה שימוש בפונקציית עזר של get_stream כדי להעביר את התשובה בסטרימינג.

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)

מחליפים את ערכי הדוגמה באופן הבא:

  • ‫DATA_AGENT_ID: המזהה של הסוכן לאינטראקציה עם נתונים, כמו שמוגדר בבלוק הקוד לדוגמה בקטע יצירת סוכן לאינטראקציה עם נתונים.
  • ההנחיה לדוגמה הייתה Make a bar graph for the top 5 states by the total number of airports.

שליחת בקשה לצ'אט ללא שמירת מצב עם הקשר מוטבע

הקוד לדוגמה הבא מראה איך לשאול את ה-API שאלה בלי שמירת מצב באמצעות הקשר מוטבע. בדוגמה הזו נעשה שימוש בפונקציית עזר של get_stream כדי להעביר את התשובה בסטרימינג, ונעשה שימוש במקור נתונים של BigQuery כדוגמה.

אפשר גם להפעיל ניתוח מתקדם באמצעות Python על ידי הכללת הפרמטר options במטען הייעודי (payload) של הבקשה. בדף משאב REST: ‏ projects.locations.dataAgents מופיע מידע נוסף על הפרמטר options ועל האפשרויות שאפשר להגדיר לשיחה.

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)

הקוד לדוגמה הבא ממחיש איך לשאול את ה-API שאלה בלי שמירת מצב באמצעות הקשר מוטבע ומקור נתונים של AlloyDB כדוגמה.

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)

יצירת שיחה רב-שלבית בלי שמירת מצב

כדי לשאול שאילתות המשך בשיחה בלי שמירת מצב, האפליקציה צריכה לנהל את ההקשר של השיחה על ידי שליחת כל היסטוריית ההודעות עם כל בקשה חדשה. שיחות עם כמה שלבים מאפשרות לכם לשלוח שאלות המשך שמבוססות על שלבים קודמים בשיחה.

בדוגמה הבאה מוגדרת פונקציית multi_turn_conversation והיא נקראת כדי לנהל את ההקשר של השיחה על ידי אחסון ההודעות ברשימה. הפונקציה multi_turn_conversation מפעילה את הפונקציה get_stream_multi_turn כדי לנתח את התגובה מה-API לסטרימינג ולעדכן את הרשימה conversation_messages. התהליך הזה שומר על ההקשר של התורות הבאים. כדי לראות את הקוד של get_stream_multi_turn ופונקציות עזר נדרשות אחרות, עיינו בקטע פונקציות עזר של צ'אט בסטרימינג.

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)

בדוגמה הקודמת, מחליפים את DATA_AGENT_ID במזהה של הסוכן לאינטראקציה עם נתונים, כמו שמוגדר בבלוק הקוד לדוגמה בקטע יצירת סוכן לאינטראקציה עם נתונים.

אפשר לקרוא לפונקציית העזר multi_turn_conversation בכל שלב בשיחה. הקוד לדוגמה הבא מראה איך לשלוח בקשה ראשונית ואז בקשת המשך שמבוססת על התשובה הקודמת:

# 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?")

בדוגמה הקודמת, מחליפים את ערכי הדוגמה באופן הבא:

  • ‫Which species of tree is most prevalent?: שאלה בשפה טבעית שתישלח לסוכן לאינטראקציה עם נתונים.
  • ‫Can you show me the results as a bar chart?: שאלת המשך שמתבססת על השאלה הקודמת או מחדדת אותה.

הגדרת פונקציות עזר

הקטע הבא מכיל הגדרות של פונקציות עזר שמשמשות בדוגמאות הקוד הקודמות כדי לנתח תגובות מה-API ולהציג את התוצאות.

פונקציות עזר לסטרימינג של צ'אט

הפונקציות הבאות מנתחות ומציגות את התגובה בסטרימינג מה-API לבקשות צ'אט רגילות (פנייה אחת).

הצגת פונקציות עזר לתשובות בסטרימינג בצ'אט

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