Codelab: Technischer Duet AI-Workshop für Entwickler

1. Ziele

Ziel dieses Workshops ist es, Nutzern und Praktikern praktische Informationen zu Duet AI zu vermitteln.

In diesem Codelab lernen Sie Folgendes:

  1. Aktivieren Sie Duet AI in Ihrem GCP-Projekt und konfigurieren Sie es für die Verwendung in einer IDE und der Cloud Console.
  2. Duet AI für die Codegenerierung, ‑vervollständigung und ‑erklärung verwenden
  3. Mit Duet AI ein Anwendungsproblem erklären und beheben
  4. Duet AI-Funktionen wie IDE-Chat und Chat über mehrere Themen, Chat im Vergleich zur Inline-Codegenerierung, intelligente Aktionen wie Codeerklärung und Bestätigung der Rezitation und mehr.

Hintergrundinformationen

Um zu zeigen, wie Duet AI for Developers im Entwickleralltag authentisch eingesetzt wird, finden die Aktivitäten in diesem Workshop in einem narrativen Kontext statt.

Ein neuer Entwickler fängt bei einem E-Commerce-Unternehmen an. Sie sollen der bestehenden E-Commerce-Anwendung, die aus mehreren Diensten besteht, einen neuen Dienst hinzufügen. Der neue Dienst bietet zusätzliche Informationen (Abmessungen, Gewicht usw.) zu Produkten im Produktkatalog. Dieser Dienst ermöglicht bessere/günstigere Versandkosten basierend auf den Abmessungen und dem Gewicht des Produkts.

Da der Entwickler neu im Unternehmen ist, verwendet er Duet AI zum Generieren, Erklären und Dokumentieren von Code.

Nachdem der Dienst programmiert wurde, verwendet ein Plattformadministrator Duet AI (Chat), um das Artefakt (Docker-Container) und die Ressourcen zu erstellen, die zum Bereitstellen des Artefakts in GCP erforderlich sind (z. B. Artifact Registry, IAM-Berechtigungen, ein Code-Repository, Recheninfrastruktur wie GKE oder Cloud Run usw.).

Sobald die Anwendung in GCP bereitgestellt wurde, verwendet ein Anwendungsoperator/SRE Duet AI (und Cloud Ops), um einen Fehler im neuen Dienst zu beheben.

Persona

Im Workshop wird die folgende Persona behandelt:

  1. App-Entwickler: Hier sind einige Kenntnisse in Programmierung und Softwareentwicklung erforderlich.

Diese Variante des Duet AI-Workshops ist nur für Entwickler vorgesehen. Kenntnisse zu GCP-Cloudressourcen sind nicht erforderlich. Die Skripts zum Erstellen der erforderlichen GCP-Ressourcen zum Ausführen dieser Anwendung finden Sie hier. Folgen Sie der Anleitung in diesem Leitfaden, um die erforderlichen GCP-Ressourcen bereitzustellen.

2. Umgebung vorbereiten

Duet AI aktivieren

Sie können Duet AI in einem GCP-Projekt aktivieren entweder über die API (gcloud oder IaC-Tools wie Terraform) oder über die Cloud Console-Benutzeroberfläche.

Wenn Sie Duet AI in einem Google Cloud-Projekt aktivieren möchten, aktivieren Sie die Cloud AI Companion API und gewähren Sie Nutzern die IAM-Rollen (Identity and Access Management) „Cloud AI Companion User“ und „Service Usage Viewer“.

Über gcloud

Aktivieren Sie Cloud Shell:

Konfigurieren Sie Ihr PROJECT_ID und USER und aktivieren Sie die Cloud AI Companion API.

export PROJECT_ID=<YOUR PROJECT ID>
export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com
gcloud config set project ${PROJECT_ID}
gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}

Die Ausgabe sieht etwa so aus:

Updated property [core/project].
Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.

Weisen Sie dem USER-Konto die IAM-Rollen (Identity and Access Management) „Cloud AI Companion User“ und „Service Usage Viewer“ zu. Die Cloud Companion API ist die Grundlage für die Funktionen, die wir in der IDE und der Console verwenden werden. Die Berechtigung „Service Usage Viewer“ wird als Schnellprüfung verwendet, bevor die Benutzeroberfläche in der Konsole aktiviert wird. So wird die Duet-Benutzeroberfläche nur in Projekten angezeigt, in denen die API aktiviert ist.

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/cloudaicompanion.user

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/serviceusage.serviceUsageViewer

Die Ausgabe sieht etwa so aus:

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/cloudaicompanion.user

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/serviceusage.serviceUsageViewer

Über die Cloud Console

Wenn Sie die API aktivieren möchten, rufen Sie in der Google Cloud Console die Seite „Cloud AI Companion API“ auf.

Wählen Sie in der Projektauswahl ein Projekt aus.

Klicken Sie auf Aktivieren.

Die Seite wird aktualisiert und zeigt den Status Aktiviert an. Duet AI ist jetzt im ausgewählten Google Cloud-Projekt für alle Nutzer mit den erforderlichen IAM-Rollen verfügbar.

Wenn Sie die IAM-Rollen zuweisen möchten, die für die Verwendung von Duet AI erforderlich sind, rufen Sie die Seite IAM auf.

Suchen Sie in der Spalte Hauptkonto nach dem NUTZER, für den Sie den Zugriff auf Duet AI aktivieren möchten, und klicken Sie dann in dieser Zeile auf das Stiftsymbol ✏️ Hauptkonto bearbeiten.

Klicken Sie im Bereich Zugriff bearbeiten auf Weitere Rolle hinzufügen.

Wählen Sie unter „Rolle auswählen“ die Option Cloud AI Companion-Nutzer aus.

Klicken Sie auf Weitere Rolle hinzufügen und wählen Sie Service Usage Viewer aus.

Klicken Sie auf Speichern.

IDE einrichten

Entwickler können aus einer Vielzahl von IDEs auswählen, die ihren Anforderungen am besten entsprechen. Die Duet AI-Codeunterstützung ist in verschiedenen IDEs verfügbar, z. B. in Visual Studio Code, JetBrains-IDEs (IntelliJ, PyCharm, GoLand, WebStorm usw.), Cloud Workstations und Cloud Shell-Editor.

In diesem Lab können Sie entweder Cloud Workstations oder Cloud Shell Editor verwenden.

In diesem Workshop wird der Cloud Shell-Editor verwendet.

Die Einrichtung von Cloud Workstations kann 20 bis 30 Minuten dauern.

Wenn Sie den Editor sofort verwenden möchten, nutzen Sie den Cloud Shell-Editor.

Öffnen Sie den Cloud Shell-Editor, indem Sie in der oberen Menüleiste von Cloud Shell auf das Stiftsymbol ✏️ klicken.

Der Cloud Shell-Editor hat eine sehr ähnliche Benutzeroberfläche wie VSCode.

d6a6565f83576063.png

Klicken Sie auf Strg (Windows)/Cmd (Mac) + , (Komma), um den Bereich „Einstellungen“ aufzurufen.

Geben Sie in der Suchleiste „Duet AI“ ein.

Achten Sie darauf, dass Cloudcode › Duet AI: Aktivieren und Cloudcode › Duet AI › Inline-Vorschläge: Auto aktivieren aktiviert sind.

111b8d587330ec74.png

Klicken Sie unten in der Statusleiste auf Cloud Code – Anmelden und folgen Sie dem Anmeldeworkflow.

Wenn Sie bereits angemeldet sind, wird in der Statusleiste Cloud Code – kein Projekt angezeigt.

Klicken Sie auf „Cloud Code – kein Projekt“. Oben wird ein Drop-down-Bereich mit Aktionen angezeigt. Klicken Sie auf Google Cloud-Projekt auswählen.

3241a59811e3c84a.png

Geben Sie die PROJEKT-ID ein. Ihr Projekt sollte in der Liste angezeigt werden.

c5358fc837588fe.png

Wählen Sie Ihre PROJECT_ID aus der Liste der Projekte aus.

Die Projekt-ID wird in der unteren Statusleiste angezeigt. Wenn nicht, müssen Sie den Cloud Shell Editor-Tab möglicherweise aktualisieren.

Klicken Sie in der Menüleiste auf der linken Seite auf das Duet AI-Symbol d97fc4e7b594c3af.png. Das Duet AI-Chatfenster wird angezeigt. Wenn Sie die Meldung „GCP-Projekt auswählen“ erhalten, Klicken Sie auf das Projekt und wählen Sie es noch einmal aus.

Das Duet AI-Chatfenster wird jetzt angezeigt.

781f888360229ca6.png

3. Infrastruktur einrichten

d3234d237f00fdbb.png

Damit Sie den neuen Versandservice in GCP ausführen können, benötigen Sie die folgenden GCP-Ressourcen:

  1. Eine Cloud SQL-Instanz mit einer Datenbank.
  2. Ein GKE-Cluster zum Ausführen des containerisierten Dienstes.
  3. Eine Artifact Registry zum Speichern des Docker-Images.
  4. Ein Cloud Source Repository für den Code.

Klonen Sie im Cloud Shell-Terminal das folgende Repository und führen Sie die folgenden Befehle aus, um die Infrastruktur in Ihrem GCP-Projekt einzurichten.

# Set your project
export PROJECT_ID=<INSERT_YOUR_PROJECT_ID>
gcloud config set core/project ${PROJECT_ID}

# Enable Cloudbuild and grant Cloudbuild SA owner role 
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
gcloud services enable cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner

# Clone the repo
git clone https://github.com/duetailabs/dev.git ~/duetaidev
cd ~/duetaidev

# Run Cloudbuild to create the necessary resources
gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID}

# To destroy all GCP resources, run the following
# gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml

4. Python Flask-Dienst entwickeln

9745ba5c70782e76.png

Der Dienst, den wir erstellen, besteht letztendlich aus den folgenden Dateien. Sie müssen diese Dateien nicht jetzt erstellen, sondern nacheinander gemäß der Anleitung unten:

  1. package-service.yaml: Eine Open API-Spezifikation für den Paketdienst mit Daten wie Höhe, Breite, Gewicht und besonderen Handhabungsanweisungen.
  2. data_model.py: Datenmodell für die API-Spezifikation des Paketdienstes. Erstellt auch die Tabelle packages in der Datenbank „product_details“.
  3. connect_connector.py – CloudSQL-Verbindung (definiert Engine, Session und Base ORM)
  4. db_init.py: Generiert Beispieldaten in der Tabelle packages.
  5. main.py: Ein Python Flask-Dienst mit einem GET-Endpunkt zum Abrufen von Paketdetails aus den packages-Daten basierend auf der product_id.
  6. test.py – Unittest
  7. requirement.txt – Python-Anforderungen
  8. Dockerfile – Zum Containerisieren dieser Anwendung

Wenn Sie bei den Übungen auf Probleme stoßen, finden Sie die endgültigen Dateien im ANHANG dieses Codelabs.

Im vorherigen Schritt haben Sie ein Cloud Source Repository erstellt. Klonen Sie das Repository. Sie erstellen die Anwendungsdateien im geklonten Repository-Ordner.

Führen Sie im Cloud Shell-Terminal den folgenden Befehl aus, um das Repository zu klonen.

cd ~
gcloud source repos clone shipping shipping
cd ~/shipping 

Öffnen Sie die Duet AI-Chat-Seitenleiste über das Menü links im Cloud Shell-Editor. Das Symbol sieht so aus: 8b135a000b259175.png. Sie können jetzt Duet AI für die Codeunterstützung verwenden.

package-service.yaml

Bitten Sie Duet, eine OpenAPI-Spezifikation für den Versanddienst zu generieren, ohne dass Dateien geöffnet sind.

Aufforderung 1: Generiere eine OpenAPI-YAML-Spezifikation für einen Dienst, der Versand- und Paketinformationen anhand einer numerischen Produkt-ID bereitstellt. Der Dienst sollte Informationen zu Höhe, Breite, Tiefe, Gewicht und besonderen Handhabungsanweisungen des Pakets enthalten.

ba12626f491a1204.png

Rechts oben im Fenster mit dem generierten Code werden drei Optionen angezeigt.

Sie können den Code entweder COPY 71194556d8061dae.png und in eine Datei EINFÜGEN.

Sie können ADD df645de8c65607a.png den Code in die aktuell geöffnete Datei im Editor einfügen.

Alternativ können Sie den Code in einer neuen Datei OPEN a4c7ed6d845df343.png.

Klicken Sie auf OPEN a4c7ed6d845df343.png, um den Code in einer neuen Datei zu speichern.

Klicken Sie auf CTRL/CMD + s, um die Datei zu speichern, und speichern Sie die Datei im Anwendungsordner unter dem Dateinamen package-service.yaml. Klicken Sie auf "OK".

f6ebd5b836949366.png

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Sie können auch verschiedene Prompts ausprobieren, um die Antworten von Duet AI zu sehen.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

data_model.py

Als Nächstes erstellen Sie die Python-Datei für das Datenmodell für den Dienst basierend auf der OpenAPI-Spezifikation.

Geben Sie bei geöffneter Datei package-service.yaml den folgenden Prompt ein.

Aufforderung 1: Generiere mit dem Python-ORM „sqlalchemy“ ein Datenmodell für diesen API-Dienst. Fügen Sie außerdem eine separate Funktion und einen Haupteinstiegspunkt ein, mit denen die Datenbanktabellen erstellt werden.

b873a6a28bd28ca1.png

Sehen wir uns die einzelnen generierten Teile an. Duet AI ist weiterhin ein Assistent. Auch wenn Sie damit schnell Code erstellen können, sollten Sie die generierten Inhalte immer überprüfen und nachvollziehen.

Zuerst gibt es eine Klasse namens Package vom TypBase, die das Datenmodell für die packages-Datenbank wie folgt definiert:

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(String(255))
    height = Column(Float)
    width = Column(Float)
    depth = Column(Float)
    weight = Column(Float)
    special_handling_instructions = Column(String(255))

Als Nächstes benötigen Sie eine Funktion, mit der die Tabelle in der Datenbank erstellt wird, z. B. so:

def create_tables(engine):
    Base.metadata.create_all(engine)

Schließlich benötigen Sie eine Hauptfunktion, die die Funktion create_tables ausführt, um die Tabelle in der Cloud SQL-Datenbank zu erstellen, wie im folgenden Beispiel:

if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine('sqlite:///shipping.db')
    create_tables(engine)

    print('Tables created successfully.')

Die Funktion main erstellt eine Engine mit einer lokalen sqlite-Datenbank. Wenn Sie CloudSQL verwenden möchten, müssen Sie die Einstellung ändern. Das machen Sie etwas später.

Verwenden Sie die OPEN a4c7ed6d845df343.png, um den Code wie bisher in eine neue Datei einzufügen. Speichern Sie den Code in einer Datei mit dem Namen data_model.py (beachten Sie den Unterstrich im Namen, nicht den Bindestrich).

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

connect-connector.py

Erstellen Sie den Cloud SQL-Connector.

Geben Sie bei geöffneter Datei data_model.py die folgenden Prompts ein.

Aufforderung 1: Generiere mit der Bibliothek „cloud-sql-python-connector“ eine Funktion, die einen Verbindungspool für eine Cloud SQL-Instanz von Postgres initialisiert.

ed05cb6ff85d34c5.png

Beachten Sie, dass in der Antwort nicht die cloud-sql-python-connector-Bibliothek verwendet wird. Sie können Prompts verfeinern, um Duet einen kleinen Hinweis zu geben, indem Sie dem Chat-Thread Details hinzufügen.

Verwenden wir einen anderen Prompt.

Aufforderung 2: Die Bibliothek „cloud-sql-python-connector“ muss verwendet werden.

d09095b44dde35bf.png

Achten Sie darauf, dass die cloud-sql-python-connector-Bibliothek verwendet wird.

Verwenden Sie die OPEN a4c7ed6d845df343.png, um den Code wie bisher in eine neue Datei einzufügen. Speichern Sie den Code in einer Datei mit dem Namen connect_conector.py. Möglicherweise müssen Sie die pg8000-Bibliothek manuell importieren. Weitere Informationen finden Sie in der Datei unten.

Löschen Sie den Duet AI-Chatverlauf und generieren Sie mit der geöffneten connect_connector.py-Datei das DB engine-, sessionmaker- und base-ORM, das in der Anwendung verwendet werden soll.

Aufforderung 1: Engine, Sessionmaker-Klasse und Base-ORM mit der Methode „connect_with_connector“ erstellen

6e4214b72ab13a63.png

In der Antwort können die engine-, Session- und Base-Daten an die connect_connector.py-Datei angehängt werden.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Sie können auch verschiedene Prompts ausprobieren, um die potenziellen Variationen der Antworten von Duet AI zu sehen.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

data_model.py aktualisieren

Sie müssen die Engine verwenden, die Sie im vorherigen Schritt (in der Datei connect_connector.py) erstellt haben, um eine Tabelle in der CloudSQL-Datenbank zu erstellen.

Duet AI-Chatprotokoll löschen Öffnen Sie die Datei data_model.py. Probieren Sie den folgenden Prompt aus.

Aufforderung 1: Importieren und verwenden Sie in der Hauptfunktion die Engine aus connect_connector.py.

2e768c9b6c523b9a.png

Sie sollten die Antwort sehen, die engine aus connect_connector (für Cloud SQL) importiert. Die create_table verwendet diese Engine anstelle der lokalen Standarddatenbank sqlite.

Aktualisieren Sie die Datei data_model.py.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Sie können auch verschiedene Prompts ausprobieren, um die unterschiedlichen Antworten von Duet AI zu sehen.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

requirements.txt

Erstellen Sie eine requirements.txt-Datei für die Anwendung.

Öffnen Sie sowohl connect_connector.py als auch die Datei data_model.py und geben Sie den folgenden Prompt ein.

Aufforderung 1: Generiere eine „pip“-Anforderungsdatei für dieses Datenmodell und diesen Dienst.

Prompt 2: Generiere eine „pip“-Anforderungsdatei für dieses Datenmodell und diesen Dienst mit den neuesten Versionen.

69fae373bc5c6a18.png

Prüfen Sie, ob die Namen und Versionen korrekt sind. In der obigen Antwort sind beispielsweise sowohl der Name als auch die Version von google-cloud-sql-connecter falsch. Korrigieren Sie die Versionen manuell und erstellen Sie eine requirements.txt-Datei, die so aussieht:

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0

Führen Sie im Befehlsterminal Folgendes aus:

pip3 install -r requirements.txt

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

Tabelle „packages“ in CloudSQL erstellen

Legen Sie die Umgebungsvariablen für den CloudSQL-Datenbankconnector fest.

export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export DB_USER=evolution
export DB_PASS=evolution
export DB_NAME=product_details

Führen Sie nun „data_model.py“ aus.

python data_model.py

Die Ausgabe sieht in etwa so aus (sehen Sie im Code nach, was tatsächlich erwartet wird):

Tables created successfully.

Stellen Sie eine Verbindung zur Cloud SQL-Instanz her und prüfen Sie, ob die Datenbank erstellt wurde.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Nachdem Sie das Passwort (ebenfalls evolution) eingegeben haben, rufen Sie die Tabellen ab.

product_details=> \dt

Die Ausgabe sieht etwa so aus:

           List of relations
 Schema |   Name   | Type  |   Owner   
--------+----------+-------+-----------
 public | packages | table | evolution
(1 row)

Sie können sich auch das Datenmodell und die Tabellendetails ansehen.

product_details=> \d+ packages

Die Ausgabe sieht etwa so aus:

                                                                        Table "public.packages"
            Column             |       Type        | Collation | Nullable |               Default                | Storage  | Compression | Stats target | Description 
-------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+-------------
 id                            | integer           |           | not null | nextval('packages_id_seq'::regclass) | plain    |             |              | 
 product_id                    | integer           |           | not null |                                      | plain    |             |              | 
 height                        | double precision  |           | not null |                                      | plain    |             |              | 
 width                         | double precision  |           | not null |                                      | plain    |             |              | 
 depth                         | double precision  |           | not null |                                      | plain    |             |              | 
 weight                        | double precision  |           | not null |                                      | plain    |             |              | 
 special_handling_instructions | character varying |           |          |                                      | extended |             |              | 
Indexes:
    "packages_pkey" PRIMARY KEY, btree (id)
Access method: heap

Geben Sie \q ein, um Cloud SQL zu beenden.

db_init.py

Als Nächstes fügen wir der Tabelle packages einige Beispieldaten hinzu.

Duet AI-Chatprotokoll löschen Probieren Sie die folgenden Prompts aus, während die data_model.py-Datei geöffnet ist.

Prompt 1: Generiere eine Funktion, die 10 Beispielpaketzeilen erstellt und in die Tabelle „packages“ (Pakete) überträgt.

Prompt 2: Generiere mit der Sitzung aus „connect_connector“ eine Funktion, die 10 Beispielzeilen für Pakete erstellt und in der Tabelle „packages“ committet.

34a9afc5f04ba5.png

Verwenden Sie die OPEN a4c7ed6d845df343.png, um den Code wie bisher in eine neue Datei einzufügen. Speichern Sie den Code in einer Datei mit dem Namen db_init.py.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Sie können auch verschiedene Prompts ausprobieren, um die unterschiedlichen Antworten von Duet AI zu sehen.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

Beispieldaten für Pakete erstellen

Führen Sie db_init.py über die Befehlszeile aus.

python db_init.py

Die Ausgabe sieht etwa so aus:

Packages created successfully.

Stellen Sie noch einmal eine Verbindung zur Cloud SQL-Instanz her und prüfen Sie, ob die Beispieldaten der Tabelle „packages“ hinzugefügt wurden.

Stellen Sie eine Verbindung zur Cloud SQL-Instanz her und prüfen Sie, ob die Datenbank erstellt wurde.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Nachdem Sie das Passwort (auch evolution) eingegeben haben, rufen Sie alle Daten aus der Tabelle „packages“ ab.

product_details=> SELECT * FROM packages;

Die Ausgabe sieht etwa so aus:

 id | product_id | height | width | depth | weight |   special_handling_instructions   
----+------------+--------+-------+-------+--------+-----------------------------------
  1 |          0 |     10 |    10 |    10 |     10 | No special handling instructions.
  2 |          1 |     10 |    10 |    10 |     10 | No special handling instructions.
  3 |          2 |     10 |    10 |    10 |     10 | No special handling instructions.
  4 |          3 |     10 |    10 |    10 |     10 | No special handling instructions.
  5 |          4 |     10 |    10 |    10 |     10 | No special handling instructions.
  6 |          5 |     10 |    10 |    10 |     10 | No special handling instructions.
  7 |          6 |     10 |    10 |    10 |     10 | No special handling instructions.
  8 |          7 |     10 |    10 |    10 |     10 | No special handling instructions.
  9 |          8 |     10 |    10 |    10 |     10 | No special handling instructions.
 10 |          9 |     10 |    10 |    10 |     10 | No special handling instructions.
(10 rows)

Geben Sie \q ein, um Cloud SQL zu beenden.

main.py

Erstellen Sie mit den geöffneten Dateien data_model.py, package-service.yaml und connect_connector.py ein main.py für die Anwendung.

Aufforderung 1: Erstelle mit der Python-Flask-Bibliothek eine Implementierung, die HTTP-REST-Endpunkte für diesen Dienst verwendet.

Aufforderung 2: Erstelle mit der Python-Flask-Bibliothek eine Implementierung, die HTTP-REST-Endpunkte für diesen Dienst verwendet. Importiere und verwende SessionMaker aus connect_conector.py für Paketdaten.

Aufforderung 3: Erstelle mit der Python-Flask-Bibliothek eine Implementierung, die HTTP-REST-Endpunkte für diesen Dienst verwendet. Importiere und verwende das Paket aus „data_model.py“ und „SessionMaker“ aus „connect_conector.py“ für Paketdaten.

Aufforderung 4: Erstelle mit der Python-Flask-Bibliothek eine Implementierung, die HTTP-REST-Endpunkte für diesen Dienst verwendet. Importiere und verwende das Paket aus „data_model.py“ und „SessionMaker“ aus „connect_conector.py“ für Paketdaten. Host-IP-Adresse 0.0.0.0 für app.run verwenden

6d794fc52a90e6ae.png

Aktualisieren Sie die Anforderungen für main.py.

Prompt: Create requirements file for main.py (Prompt: Erstelle eine Datei mit Anforderungen für main.py)

1cc0b318d2d4ca2f.png

Hängen Sie dies an die Datei requirements.txt an. Verwenden Sie Flask-Version 3.0.0.

Verwenden Sie OPEN a4c7ed6d845df343.png, um den Code wie zuvor in eine neue Datei zu schreiben. Speichern Sie den Code in einer Datei mit dem Namen main.py.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

5. Anwendung testen und ausführen

Installieren Sie die erforderlichen Komponenten.

pip3 install -r requirements.txt

Führen Sie main.py aus.

python main.py

Die Ausgabe sieht etwa so aus:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://10.88.0.3:5000
Press CTRL+C to quit

Testen Sie den /packages/<product_id>-Endpunkt in einem zweiten Terminal.

curl localhost:5000/packages/1

Die Ausgabe sieht etwa so aus:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Sie können auch eine beliebige andere Produkt-ID in Ihren Beispieldaten testen.

Geben Sie CTRL_C ein, um den ausgeführten Docker-Container im Terminal zu beenden.

Unittests erstellen

Generieren Sie Unittests, während die Datei main.py geöffnet ist.

Aufforderung 1: Unittests generieren

e861e5b63e1b2657.png

Verwenden Sie die OPEN a4c7ed6d845df343.png, um den Code wie bisher in eine neue Datei einzufügen. Speichern Sie den Code in einer Datei mit dem Namen test.py.

In der Funktion test_get_package muss ein product_id definiert werden. Sie können sie manuell hinzufügen.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Wenn Sie den Duet AI-Chatverlauf zurücksetzen möchten, klicken Sie oben in der Duet AI-Seitenleiste auf das Papierkorbsymbol f574ca2c1e114856.png.

Einheitentests ausführen

Führen Sie den Einheitentest durch.

python test.py

Die Ausgabe sieht etwa so aus:

.
----------------------------------------------------------------------
Ran 1 test in 1.061s

OK

Schließen Sie alle Dateien im Cloud Shell-Editor und löschen Sie den Chatverlauf, indem Sie in der oberen Statusleiste auf das Papierkorbsymbol 1ecccfe10d6c540.png klicken.

Dockerfile

Erstellen Sie eine Dockerfile für diese Anwendung.

Öffnen Sie main.py und probieren Sie die folgenden Prompts aus.

Aufforderung 1: Generiere ein Dockerfile für diese Anwendung.

Aufforderung 2: Generiere ein Dockerfile für diese Anwendung. Kopieren Sie alle Dateien in den Container.

9c473caea437a5c3.png

Außerdem müssen Sie die ENVARS für INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS und DB_NAME festlegen. Das können Sie manuell tun. Ihr Dockerfile sollte so aussehen:

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]

Verwenden Sie die OPEN a4c7ed6d845df343.png, um den Code wie bisher in eine neue Datei einzufügen. Speichern Sie den Code in einer Datei mit dem Namen „Dockerfile“.

Die endgültige Datei finden Sie im ANHANG dieses Codelabs. Falls nicht, nehmen Sie die entsprechenden Änderungen manuell vor.

Anwendung lokal ausführen

Versuchen Sie es mit dem folgenden Prompt, wenn die Dockerfile geöffnet ist.

Aufforderung 1: Wie führe ich einen Container mit diesem Dockerfile lokal aus?

570fd5c296ca8c83.png

Folgen Sie der Anleitung.

# Build
docker build -t shipping .
# And run
docker run -p 5000:5000 -it shipping

Die Ausgabe sieht etwa so aus:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

Greifen Sie über ein zweites Terminalfenster auf den Container zu.

curl localhost:5000/packages/1

Die Ausgabe sieht etwa so aus:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Die containerisierte Anwendung funktioniert.

Geben Sie CTRL_C ein, um den ausgeführten Docker-Container im Terminal zu beenden.

Container-Image in Artifact Registry erstellen

Erstellen Sie das Container-Image und übertragen Sie es per Push an die Artifact Registry.

cd ~/shipping
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping .
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping

Der Anwendungscontainer befindet sich jetzt unter us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping und kann in GKE bereitgestellt werden.

6. Anwendung im GKE-Cluster bereitstellen

Beim Erstellen der GCP-Ressourcen für diesen Workshop wurde ein GKE Autopilot-Cluster erstellt. Stellen Sie eine Verbindung zum GKE-Cluster her.

gcloud container clusters get-credentials gke1 \
    --region=us-central1

Annotieren Sie das Kubernetes-Standarddienstkonto mit dem Google-Dienstkonto.

kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com

Die Ausgabe sieht etwa so aus:

serviceaccount/default annotated

Bereiten Sie die Datei „k8s.yaml“ vor und wenden Sie sie an.

cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml
kubectl apply -f k8s.yaml

Die Ausgabe sieht etwa so aus:

deployment.apps/shipping created
service/shipping created

Warten Sie, bis die Pods ausgeführt werden und dem Dienst eine externe Load-Balancer-IP-Adresse zugewiesen wurde.

kubectl get pods
kubectl get service shipping

Die Ausgabe sieht etwa so aus:

# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
shipping-f5d6f8d5-56cvk   1/1     Running   0          4m47s
shipping-f5d6f8d5-cj4vv   1/1     Running   0          4m48s
shipping-f5d6f8d5-rrdj2   1/1     Running   0          4m47s

# kubectl get service shipping
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
shipping   LoadBalancer   34.118.225.125   34.16.39.182   80:30076/TCP   5m41s

Warten Sie bei GKE Autopilot-Clustern einige Momente, bis die Ressourcen bereit sind.

Greifen Sie über die EXTERNAL-IP-Adresse auf den Dienst zu.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Die Ausgabe sieht etwa so aus:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

7. Zusätzlicher Schritt: Fehlerbehebung bei der Anwendung

Entfernen Sie die Cloud SQL-Client-IAM-Rolle aus dem Dienstkonto cloudsqlsa. Dadurch tritt ein Fehler beim Herstellen einer Verbindung zur Cloud SQL-Datenbank auf.

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Starten Sie den Versand-Pod neu.

kubectl rollout restart deployment shipping

Versuchen Sie nach dem Neustart des Pods noch einmal, auf den Dienst shipping zuzugreifen.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1 

Die Ausgabe sieht etwa so aus:

...
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

Sehen Sie sich die Logs an, indem Sie zu Kubernetes Engine > Arbeitslasten wechseln.

d225b1916c829167.png

Klicken Sie auf die shipping-Bereitstellung und dann auf den Tab Logs.

1d0459141483d6a7.png

Klicken Sie rechts in der Statusleiste auf das Symbol Im Log-Explorer ansehen df8b9d19a9fe4c73.png. Dadurch wird ein neues Log-Explorer-Fenster geöffnet.

e86d1c265e176bc4.png

Klicken Sie auf einen der Traceback-Fehlereinträge und dann auf Diesen Logeintrag erklären.

d6af045cf03008bc.png

Sie können die Erklärung des Fehlers lesen.

Als Nächstes lassen wir Duet AI uns bei der Fehlerbehebung helfen.

Probieren Sie den folgenden Prompt aus.

Prompt 1: Hilf mir bei der Fehlerbehebung.

9288dd6045369167.png

Geben Sie die Fehlermeldung in den Prompt ein.

Aufforderung 2: Verboten: Das authentifizierte IAM-Hauptkonto scheint nicht autorisiert zu sein, API-Anfragen zu stellen. Prüfen Sie, ob die Cloud SQL Admin API in Ihrem GCP-Projekt aktiviert ist und ob dem IAM-Principal die Rolle „Cloud SQL-Client“ zugewiesen wurde.

f1e64fbdc435d31c.png

Und dann.

Aufforderung 3: Wie weise ich einem Google-Dienstkonto mit gcloud die Rolle „Cloud SQL-Client“ zu?

bb8926b995a8875c.png

Weisen Sie dem cloudsqlsa die Rolle „Cloud SQL-Client“ zu.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Warten Sie einige Minuten und versuchen Sie dann noch einmal, auf die Anwendung zuzugreifen.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Die Ausgabe sieht etwa so aus:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Sie haben Duet AI in Cloud Logging, Log-Explorer und der Funktion Log-Erklärer verwendet, um das Problem zu beheben.

8. Fazit

Glückwunsch! Sie haben dieses Codelab erfolgreich abgeschlossen.

In diesem Codelab haben Sie Folgendes gelernt:

  1. Aktivieren Sie Duet AI in Ihrem GCP-Projekt und konfigurieren Sie es für die Verwendung in einer IDE und der Cloud Console.
  2. Duet AI für die Codegenerierung, ‑vervollständigung und ‑erklärung verwenden
  3. Mit Duet AI ein Anwendungsproblem erklären und beheben
  4. Duet AI-Funktionen wie IDE-Chat und Chat über mehrere Themen, Chat im Vergleich zur Inline-Codegenerierung, intelligente Aktionen wie Codeerklärung und Bestätigung der Rezitation und mehr.

9. Anhang

package-service.yaml

swagger: "2.0"
info:
 title: Shipping and Package Information API
 description: This API provides information about shipping and packages.
 version: 1.0.0
host: shipping.googleapis.com
schemes:
 - https
produces:
 - application/json
paths:
 /packages/{product_id}:
   get:
     summary: Get information about a package
     description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
     parameters:
       - name: product_id
         in: path
         required: true
         type: integer
         format: int64
     responses:
       "200":
         description: A successful response
         schema:
           type: object
           properties:
             height:
               type: integer
               format: int64
             width:
               type: integer
               format: int64
             depth:
               type: integer
               format: int64
             weight:
               type: integer
               format: int64
             special_handling_instructions:
               type: string
       "404":
         description: The product_id was not found

data_model.py

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base

from connect_connector import engine

Base = declarative_base()

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, nullable=False)
    height = Column(Float, nullable=False)
    width = Column(Float, nullable=False)
    depth = Column(Float, nullable=False)
    weight = Column(Float, nullable=False)
    special_handling_instructions = Column(String, nullable=True)

def create_tables():
    Base.metadata.create_all(engine)

if __name__ == '__main__':
    create_tables()

    print('Tables created successfully.')

connect_connector.py

import os

from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy

# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
   """Initializes a connection pool for a Cloud SQL instance of Postgres."""
   # Note: Saving credentials in environment variables is convenient, but not
   # secure - consider a more secure solution such as
   # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
   # keep secrets safe.
   instance_connection_name = os.environ[
       "INSTANCE_CONNECTION_NAME"
   ]  # e.g. 'project:region:instance'
   db_user = os.environ["DB_USER"]  # e.g. 'my-database-user'
   db_pass = os.environ["DB_PASS"]  # e.g. 'my-database-password'
   db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

   ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

   connector = Connector()

   def getconn() -> sqlalchemy.engine.base.Engine:
       conn: sqlalchemy.engine.base.Engine = connector.connect(
           instance_connection_name,
           "pg8000",
           user=db_user,
           password=db_pass,
           db=db_name,
           ip_type=ip_type,
       )
       return conn

   pool = sqlalchemy.create_engine(
       "postgresql+pg8000://",
       creator=getconn,
       # ...
   )
   return pool

# Create a connection pool
engine = connect_with_connector()

# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)

# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()

db_init.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine

from data_model import Package

def create_packages():
    # Create a session
    session = sessionmaker(bind=engine)()

    # Create 10 sample packages
    for i in range(10):
        package = Package(
            product_id=i,
            height=10.0,
            width=10.0,
            depth=10.0,
            weight=10.0,
            special_handling_instructions="No special handling instructions."
        )

        # Add the package to the session
        session.add(package)

    # Commit the changes
    session.commit()

if __name__ == '__main__':
    create_packages()

    print('Packages created successfully.')

main.py

from flask import Flask, request, jsonify

from data_model import Package
from connect_connector import SessionMaker

app = Flask(__name__)

session_maker = SessionMaker()

@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
  """Get information about a package."""

  session = session_maker

  package = session.query(Package).filter(Package.product_id == product_id).first()

  if package is None:
    return jsonify({"message": "Package not found."}), 404

  return jsonify(
      {
          "height": package.height,
          "width": package.width,
          "depth": package.depth,
          "weight": package.weight,
          "special_handling_instructions": package.special_handling_instructions,
      }
  ), 200

if __name__ == "__main__":
  app.run(host="0.0.0.0")

test.py

import unittest

from data_model import Package
from connect_connector import SessionMaker

from main import app

class TestPackage(unittest.TestCase):

    def setUp(self):
        self.session_maker = SessionMaker()

    def tearDown(self):
        self.session_maker.close()

    def test_get_package(self):
        """Test the `get_package()` function."""

        package = Package(
        product_id=11, # Ensure that the product_id different from the sample data
        height=10,
        width=10,
        depth=10,
        weight=10,
        special_handling_instructions="Fragile",
        )

        session = self.session_maker

        session.add(package)
        session.commit()

        response = app.test_client().get("/packages/11")

        self.assertEqual(response.status_code, 200)

        self.assertEqual(
            response.json,
            {
                "height": 10,
                "width": 10,
                "depth": 10,
                "weight": 10,
                "special_handling_instructions": "Fragile",
            },
        )

if __name__ == "__main__":
    unittest.main()

requirements.txt

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3

Dockerfile

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]