Bezpośredni serwer proxy PSC silnika agenta

1. Wprowadzenie

Interfejs Private Service Connect to zasób, który umożliwia sieci VPC producenta inicjowanie połączeń z różnymi miejscami docelowymi w sieci VPC konsumenta. Sieci producenta i odbiorcy mogą znajdować się w różnych projektach i organizacjach.

Jeśli przyłącze sieci zaakceptuje połączenie z interfejsu Private Service Connect, Google Cloud przydzieli interfejsowi adres IP z podsieci konsumenta określonej przez przyłącze sieci. Sieci konsumenta i producenta są połączone i mogą komunikować się za pomocą wewnętrznych adresów IP.

Połączenie między przyłączem sieci a interfejsem Private Service Connect jest podobne do połączenia między punktem końcowym Private Service Connect a przyłączem usługi, ale ma 2 kluczowe różnice:

  • Przyłącze sieci umożliwia sieci producenta inicjowanie połączeń z siecią konsumenta (ruch wychodzący usługi zarządzanej), a punkt końcowy umożliwia sieci konsumenta inicjowanie połączeń z siecią producenta (ruch przychodzący usługi zarządzanej).
  • Połączenie interfejsu Private Service Connect jest przechodnie. Oznacza to, że sieć producenta może komunikować się z innymi sieciami połączonymi z siecią konsumenta.

Wskazówki dotyczące dostępności interfejsu PSC Vertex AI

  • Interfejs PSC może kierować ruch do miejsc docelowych w sieci VPC lub lokalnych w bloku adresów RFC1918.
  • Kierowanie na interfejs PSC na bloki adresów inne niż rfc-1918 wymaga wdrożenia w sieci VPC konsumenta jawnego serwera proxy z adresem rfc-1918. W ramach wdrożenia Vertex AI serwer proxy musi być zdefiniowany wraz z w pełni kwalifikowaną nazwą domeny docelowego punktu końcowego.
  • Jeśli skonfigurujesz wdrożenie tylko za pomocą interfejsu PSC, zachowa ono domyślny dostęp do internetu. Ten ruch wychodzący jest kierowany bezpośrednio z zabezpieczonej sieci najemcy zarządzanej przez Google.

Wskazówki dotyczące interfejsu VPC-SC usługi Vertex AI PSC

  • Gdy Twój projekt jest częścią granicy ustawień usługi VPC, domyślny dostęp do internetu w dzierżawach zarządzanych przez Google jest blokowany przez tę granicę, aby zapobiec wydobywaniu danych.
  • Aby umożliwić wdrożeniu dostęp do publicznego internetu w tym scenariuszu, musisz wyraźnie skonfigurować bezpieczną ścieżkę ruchu wychodzącego, która kieruje ruch przez sieć VPC.
  • Zalecany sposób to skonfigurowanie serwera proxy wewnątrz obwodu sieci VPC z adresem RFC1918 i utworzenie bramy Cloud NAT, aby umożliwić maszynie wirtualnej serwera proxy dostęp do internetu.

Więcej informacji znajdziesz w tych materiałach:

Wdrażanie agenta | Generatywna AI w Vertex AI | Google Cloud

Konfigurowanie interfejsu Private Service Connect dla zasobów Vertex AI | Google Cloud

Co utworzysz

W tym samouczku utworzysz kompleksowy silnik agenta wdrożony z interfejsem Private Service Connect (PSC), który umożliwi połączenie z publiczną witryną (https://api.frankfurter.app/) za pomocą maszyny wirtualnej serwera proxy wdrożonej w sieci VPC konsumenta z adresem RFC1918. Przykładowe wdrożenie ma zastosowanie w projekcie z włączoną usługą VPC-SC lub w przypadku administratorów, którzy wymagają wychodzącego ruchu internetowego przez sieć klienta zamiast przez sieć VPC najemcy.

Rysunek 1.

f42f2db921f6d5af.png

W konsumenckiej sieci VPC utworzysz pojedynczy zasób psc-network-attachment, który będzie korzystać z równorzędnego połączenia DNS, aby rozwiązać adres proxy-vm sieci konsumenckiej w projekcie najemcy hostującym Agent Engine. Umożliwi to następujące przypadki użycia:

wdrożyć Agent Engine i skonfigurować maszynę wirtualną proxy tak, aby działała jako serwer proxy jawny, co umożliwi jej dostęp do publicznego adresu URL https://api.frankfurter.app;

Czego się nauczysz

  • Tworzenie przyłącza sieci
  • Jak producent może użyć przyłącza sieci do utworzenia interfejsu PSC
  • Jak nawiązać komunikację między producentem a konsumentem za pomocą połączenia równorzędnego DNS
  • Jak wdrożyć i używać maszyny wirtualnej proxy do wychodzącego ruchu internetowego

Czego potrzebujesz

Projekt Google Cloud

Uprawnienia

2. Zanim zaczniesz

Aktualizowanie projektu na potrzeby samouczka

W tym samouczku używamy zmiennych $variables, aby ułatwić implementację konfiguracji gcloud w Cloud Shell.

W Cloud Shell wykonaj te czynności:

gcloud config list project
gcloud config set project [YOUR-PROJECT-NAME]
projectid=YOUR-PROJECT-NAME
echo $projectid

Włączanie interfejsu API

W Cloud Shell wykonaj te czynności:

gcloud services enable "compute.googleapis.com"
gcloud services enable "aiplatform.googleapis.com"
gcloud services enable "dns.googleapis.com"
gcloud services enable "notebooks.googleapis.com"
gcloud services enable "storage.googleapis.com"
gcloud services enable "iap.googleapis.com"

Sprawdzanie, czy interfejsy API zostały włączone

gcloud services list --enabled

3. Konfiguracja dla konsumentów

Utwórz VPC klienta

Ta sieć VPC znajduje się w projekcie klienta. W tej sieci VPC zostaną utworzone te zasoby:

  • Podsieć konsumencka
  • Podsieć przyłącza sieci
  • Cloud Router (wymagany w przypadku Cloud NAT)
  • Cloud NAT

W Cloud Shell wykonaj te czynności:

gcloud compute networks create consumer-vpc --project=$projectid --subnet-mode=custom

Tworzenie podsieci konsumenckich

W Cloud Shell utwórz podsieć dla maszyny wirtualnej serwera proxy:

gcloud compute networks subnets create rfc1918-subnet1 --project=$projectid --range=10.10.10.0/28 --network=consumer-vpc --region=us-central1

Utwórz podsieć przyłącza sieci Private Service Connect

W Cloud Shell utwórz podsieć dla przyłącza sieci PSC:

gcloud compute networks subnets create intf-subnet --project=$projectid --range=192.168.10.0/28 --network=consumer-vpc --region=us-central1

Konfiguracja routera Cloud Router i NAT

W tym samouczku Cloud NAT służy do zapewnienia dostępu do internetu maszynie wirtualnej proxy, która nie ma publicznego adresu IP. Cloud NAT umożliwia maszynom wirtualnym, które mają tylko prywatne adresy IP, łączenie się z internetem, co pozwala im wykonywać zadania takie jak instalowanie pakietów oprogramowania.

W Cloud Shell utwórz router Cloud Router.

gcloud compute routers create cloud-router-for-nat --network consumer-vpc --region us-central1

W Cloud Shell utwórz bramę NAT z włączonym logowaniem. Będziemy używać logowania do weryfikowania dostępu do publicznego adresu IP w przypadku interfejsu Frankfurter API (https://api.frankfurter.app/).

gcloud compute routers nats create cloud-nat-us-central1 --router=cloud-router-for-nat --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --region us-central1 --enable-logging --log-filter=ALL

4. Włączanie IAP

Aby umożliwić IAP połączenie z instancjami maszyn wirtualnych, utwórz regułę zapory sieciowej, która:

  • Dotyczy wszystkich instancji maszyn wirtualnych, które mają być dostępne przez IAP.
  • Zezwala na ruch przychodzący z zakresu adresów IP 35.235.240.0/20. Ten zakres zawiera wszystkie adresy IP, których IAP używa do przekierowywania TCP.

W Cloud Shell utwórz regułę zapory sieciowej IAP.

gcloud compute firewall-rules create ssh-iap-consumer \
    --network consumer-vpc \
    --allow tcp:22 \
    --source-ranges=35.235.240.0/20

5. Tworzenie instancji maszyn wirtualnych konsumentów

W Cloud Shell utwórz instancję maszyny wirtualnej klienta, proxy-vm, która będzie służyć jako jawny serwer proxy dla Agent Engine. Do przekierowywania ruchu HTTP użyjemy aplikacji tinyproxy.

gcloud compute instances create proxy-vm \
    --project=$projectid \
    --machine-type=e2-micro \
    --image-family debian-11 \
    --no-address \
    --can-ip-forward \
    --image-project debian-cloud \
    --zone us-central1-a \
    --subnet=rfc1918-subnet1 \
    --shielded-secure-boot \
    --metadata startup-script="#! /bin/bash
      sudo apt-get update
      sudo apt-get install tcpdump
      sudo apt-get install tinyproxy -y
      sudo apt-get install apache2 -y
      sudo service apache2 restart
      echo 'proxy server !!' | tee /var/www/html/index.html
      EOF"

6. Przyłącze sieci Private Service Connect

Przyłącza sieci to zasoby regionalne, które reprezentują stronę konsumenta interfejsu Private Service Connect. Z przyłączem sieci możesz powiązać jedną podsieć, a producent przypisuje adresy IP do interfejsu Private Service Connect z tej podsieci. Podsieć musi znajdować się w tym samym regionie co przyłącze sieci. Przyłącze sieci musi znajdować się w tym samym regionie co usługa producenta.

Tworzenie przyłącza sieci

W Cloud Shell utwórz przyłącze sieci.

gcloud compute network-attachments create psc-network-attachment \
    --region=us-central1 \
    --connection-preference=ACCEPT_AUTOMATIC \
    --subnets=intf-subnet

Wyświetlanie listy przyłączy sieci

W Cloud Shell wyświetl listę przyłączy sieci.

gcloud compute network-attachments list

Opisz przyłącza sieci

W Cloud Shell opisz przyłącze sieci.

gcloud compute network-attachments describe psc-network-attachment --region=us-central1

Zanotuj nazwę przyłącza sieci PSC, psc-network-attachment, która będzie używana przez producenta podczas tworzenia interfejsu Private Service Connect.

Aby wyświetlić adres URL przyłączenia sieci PSC w konsoli Google Cloud, otwórz:

Usługi sieciowe → Private Service Connect → Przyłącze sieci → psc-network-attachment

8eec51cb197da218.png

7. Prywatna strefa DNS

Utwórz strefę Cloud DNS dla demo.com i wypełnij ją rekordem A, który wskazuje adresy IP maszyny wirtualnej proxy. Później w Agent Engine zostanie wdrożona komunikacja równorzędna DNS, która umożliwi dostęp do rekordów DNS konsumenta.

W Cloud Shell wykonaj te czynności, aby utworzyć nazwę DNS demo.com.

gcloud dns --project=$projectid managed-zones create private-dns-codelab --description="" --dns-name="demo.com." --visibility="private" --networks="https://compute.googleapis.com/compute/v1/projects/$projectid/global/networks/consumer-vpc"

Pobierz i zapisz adresy IP instancji używanych w rekordach DNS A.

W Cloud Shell wykonaj opis instancji maszyn wirtualnych.

gcloud compute instances describe proxy-vm --zone=us-central1-a | grep  networkIP:

W Cloud Shell utwórz zestaw rekordów dla maszyny wirtualnej proxy-vm.demo.com. Pamiętaj, aby zaktualizować adres IP na podstawie danych wyjściowych środowiska.

gcloud dns --project=$projectid record-sets create proxy-vm.demo.com. --zone="private-dns-codelab" --type="A" --ttl="300" --rrdatas="10.10.10.2"

Tworzenie reguły zapory sieciowej Cloud Firewall, która zezwala na dostęp z interfejsu PSC

W następnej sekcji utwórz regułę zapory sieciowej, która zezwala na ruch pochodzący z sieci PSC do maszyny wirtualnej proxy w sieci VPC klienta.

W Cloud Shell utwórz regułę zapory sieciowej dotyczącą ruchu przychodzącego.

gcloud compute firewall-rules create allow-access-to-compute \
    --network=consumer-vpc \
    --action=ALLOW \
    --rules=ALL \
    --direction=INGRESS \
    --priority=1000 \
    --source-ranges="192.168.10.0/28" \
    --destination-ranges="10.10.10.0/28" \
    --enable-logging

8. Tworzenie notatnika Jupyter

W sekcji poniżej znajdziesz instrukcje tworzenia notatnika Jupyter. Ten notatnik będzie używany do wdrażania Agent Engine kierowanego na jawny serwer proxy na potrzeby wychodzącego ruchu internetowego.

Tworzenie konta usługi zarządzanego przez użytkownika

W następnej sekcji utworzysz konto usługi, które będzie powiązane z instancją Vertex AI Workbench używaną w tym samouczku.

W tym samouczku do konta usługi zostaną przypisane te role:

W Cloud Shell utwórz konto usługi.

gcloud iam service-accounts create notebook-sa \
    --display-name="notebook-sa"

W Cloud Shell zaktualizuj konto usługi, przypisując mu rolę Administrator miejsca na dane.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/storage.admin"

W Cloud Shell zaktualizuj konto usługi, przypisując mu rolę Użytkownik Vertex AI.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/aiplatform.user"

W Cloud Shell zaktualizuj konto usługi, przypisując mu rolę Administrator Artifact Registry.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/artifactregistry.admin"

W Cloud Shell zezwól kontu usługi notatnika na używanie domyślnego konta usługi Compute Engine.

gcloud iam service-accounts add-iam-policy-binding \
    $(gcloud projects describe $(gcloud config get-value project) --format='value(projectNumber)')-compute@developer.gserviceaccount.com \
    --member="serviceAccount:notebook-sa@$projectid.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountUser"

9. Aktualizowanie serwera proxy

W następnej sekcji musisz połączyć się z serwerem proxy za pomocą protokołu SSH i zaktualizować plik konfiguracyjny tinyproxy.conf, a następnie zresetować serwer.

Z Cloud Shell

gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid

Otwórz plik konfiguracyjny tinyproxy i zaktualizuj go w wybranym edytorze. Poniżej znajdziesz przykład użycia VIM.

sudo vim /etc/tinyproxy/tinyproxy.conf

# Locate the "Listen" configuration line to restrict listening to only its private IP address of the Proxy-VM, rather than all interfaces. 

Listen 10.10.10.2

# Locate the "Allow" configuration line to allow requests ONLY from the PSC Network Attachment Subnet

Allow 192.168.10.0/24

Save the configs by the following steps:
1. Press the `ESC` key to enter Command Mode.
2. Type `:wq` to save (w) and quit (q).
3. Press `Enter`

Restart the tinyproxy service to apply the changes:
sudo systemctl restart tinyproxy

Validate the tinyproxy service is running:
sudo systemctl status tinyproxy

Perform an exit returning to cloud shell
exit

10. Tworzenie instancji Vertex AI Workbench

W sekcji poniżej utwórz instancję Vertex AI Workbench, która zawiera utworzone wcześniej konto usługi notebook-sa.

W Cloud Shell utwórz instancję private-client.

gcloud workbench instances create workbench-tutorial --vm-image-project=cloud-notebooks-managed --vm-image-family=workbench-instances --machine-type=n1-standard-4 --location=us-central1-a --subnet-region=us-central1 --subnet=rfc1918-subnet1 --disable-public-ip --shielded-secure-boot=true --shielded-integrity-monitoring=true --shielded-vtpm=true --service-account-email=notebook-sa@$projectid.iam.gserviceaccount.com

11. Aktualizacja agenta usługi Vertex AI

Vertex AI działa w Twoim imieniu, wykonując operacje takie jak uzyskiwanie adresu IP z podsieci przyłącza sieci PSC używanej do tworzenia interfejsu PSC. W tym celu Vertex AI używa agenta usługi (wymienionego poniżej), który wymaga uprawnień administratora sieci:

service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com

W Cloud Shell uzyskaj numer projektu.

gcloud projects describe $projectid | grep projectNumber

W Cloud Shell ustaw numer projektu.

projectnumber=YOUR-PROJECT-Number

W Cloud Shell utwórz konto usługi dla AI Platform. Pomiń ten krok, jeśli w projekcie masz już konto usługi.

gcloud beta services identity create --service=aiplatform.googleapis.com --project=$projectnumber

W Cloud Shell zaktualizuj konto agenta usługi, przypisując mu rolę compute.networkAdmin.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/compute.networkAdmin"

W Cloud Shell zaktualizuj konto agenta usługi, nadając mu rolę dns.peer.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:service-$projectnumber@gcp-sa-aiplatform.iam.gserviceaccount.com" --role="roles/dns.peer"

Aktualizacja domyślnego konta usługi

Przyznaj domyślnemu kontu usługi dostęp do Vertex AI. Pamiętaj, że zanim zmiana dostępu zostanie zastosowana, może minąć trochę czasu.

W Cloud Shell zaktualizuj domyślne konto usługi, przypisując mu rolę aiplatform.user.

gcloud projects add-iam-policy-binding $projectid \
  --member="serviceAccount:$projectnumber-compute@developer.gserviceaccount.com" \
    --role="roles/aiplatform.user"

12. Proxy VM Tcpdump

Aby sprawdzić łączność IP z Agent Engine, możemy użyć narzędzia TCPDUMP. Dzięki temu będziemy mogli obserwować komunikację pochodzącą z podsieci PSC Network Attachment, 192.168.10.0/28, podczas wywoływania żądania GET z Agent Engine do publicznego adresu URL.

Połącz się z maszyną wirtualną serwera proxy przez SSH w Cloud Shell.

gcloud compute ssh --zone us-central1-a "proxy-vm" --tunnel-through-iap --project $projectid

Uruchom tcpdump w systemie operacyjnym maszyny wirtualnej proxy.

sudo tcpdump -i any net 192.168.10.0/28 -nn

13. Wdrażanie silnika agenta

Uwaga: do wykonania zadań w tej sekcji użyjemy konsoli GCP i notatnika JupyterLab.

W kolejnej sekcji utworzysz notatnik, który będzie wykonywać te zadania:

  • Korzysta z interfejsu Frankfurter API (https://api.frankfurter.app/) do pobierania danych o kursach wymiany.
  • Odwołuje się do serwera proxy (proxy_server) kierowanego na maszynę wirtualną proxy w sieci VPC konsumentów za pomocą w pełni kwalifikowanej nazwy domeny proxy-vm.demo.com.
  • Zdefiniuj dnsPeeringConfigs "domain": "demo.com."

Uruchom zadanie trenowania w instancji Vertex AI Workbench.

  • W konsoli Google Cloud otwórz Vertex AI → Workbench.
  • Obok nazwy instancji Vertex AI Workbench (workbench-tutorial) kliknij Otwórz JupyterLab. Instancja Vertex AI Workbench otworzy się w JupyterLab.
  • Wybierz Plik > Nowy > Notatnik.
  • Wybierz Jądro > Python 3.

Zainstaluj niezbędne biblioteki Pythona: zainstaluj biblioteki wymagane przez Agent Engine, w tym pyyaml, google-cloud-aiplatform, cloudpickle, google-cloud-api-keys i langchain-google-vertexai.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

!pip install pyyaml
!pip install google-cloud-aiplatform[agent_engines,langchain]==1.96.0
!pip install cloudpickle==3.1.1
!pip install google-cloud-api-keys
!pip install langchain-google-vertexai==2.0.24

Ponownie uruchom jądro Jupyter Notebook: upewnij się, że nowo zainstalowane biblioteki są prawidłowo załadowane.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

# Restart the notebook kernel after install, so you can run langchain successfully.

import IPython

app = IPython.Application.instance()
app.kernel.do_shutdown(True)

Ustaw zmienne projektu i zasobnika: zdefiniuj identyfikator projektu Google Cloud, numer projektu, nazwę usługi, katalog GCS, punkt końcowy, nazwę zasobnika i lokalizację.

Zanim uruchomisz komórkę, zaktualizuj te pola

  • PROJECT_ID = "enter-your-projectid"
  • PROJECT_NUMBER = "enter-your-projectnumber"
  • BUCKET= "enter-a-unique-bucket-name"

Uwaga: w następnym kroku użyjemy zmiennej BUCKET do utworzenia zasobnika Cloud Storage.

W notatniku JupyterLab utwórz nową komórkę, zaktualizuj i uruchom poniższy kod.

PROJECT_ID = "enter-your-projectid"  #@param {type:"string"}
PROJECT_NUMBER = "enter-your-projectnumber"  #@param {type:"string"}
SERVICE_NAME = "aiplatform"  #@param ["autopush-aiplatform", "staging-aiplatform", "aiplatform"]
# @markdown  Specify where your agent code should be written in GCS:
GCS_DIR = "reasoning-engine-test"  #@param {type:"string"}
ENDPOINT = "https://us-central1-aiplatform.googleapis.com" # @param ["https://us-central1-aiplatform.googleapis.com", "https://us-central1-autopush-aiplatform.sandbox.googleapis.com", "https://us-central1-staging-aiplatform.sandbox.googleapis.com"]
BUCKET= "enter-a-unique-bucket-name" #@param {type:"string"}
LOCATION="us-central1" #@param {type:"string"}

Utwórz zasobnik GCS: utwórz zasobnik Cloud Storage do przechowywania kodu agenta.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

!gcloud storage buckets create gs://{BUCKET}

Określ nazwę przyłącza sieci: podaj nazwę przyłącza sieci Private Service Connect.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

NETWORK_ATTACHMENT_NAME = 'psc-network-attachment' #@param {type:"string"}

Zainicjuj biblioteki klienta w Pythonie: skonfiguruj niezbędne biblioteki klienta dla usług Google Cloud.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

import json
import pprint

import cloudpickle
from google import auth as google_auth
from google.auth.transport import requests as google_requests
from google.cloud import storage
import yaml


def get_identity_token():
    """Gets ID token for calling Cloud Run."""
    credentials, _ = google_auth.default()
    auth_request = google_requests.Request()
    credentials.refresh(auth_request)
    return credentials.id_token

if not GCS_DIR or "your_ldap" in GCS_DIR:
    raise ValueError("GCS_DIR must be set or you must set your ldap.")

if not PROJECT_ID:
    raise ValueError("PROJECT_ID must be set.")


client = storage.Client(project=PROJECT_ID)
bucket = client.get_bucket(BUCKET)

Skonfiguruj agenta i narzędzia: zdefiniuj klasę StreamingAgent i funkcję get_exchange_rate, aby pobierać kursy wymiany walut za pomocą interfejsu Frankfurter API przez jawny serwer proxy.

W notatniku JupyterLab utwórz nową komórkę i uruchom poniższą konfigurację. Zwróć uwagę na te elementy:

  • Funkcja def get_exchange_rate będzie używać interfejsu Frankfurter API (https://api.frankfurter.app/) do pobierania danych o kursach wymiany.
  • proxy_server = "http://proxy-vm.demo.com:8888" FQDN jest powiązana z maszyną wirtualną serwera proxy wdrożoną w sieci VPC konsumenta. W kolejnym kroku użyjemy komunikacji równorzędnej DNS, aby rozpoznać w pełni kwalifikowaną nazwę domeny.
from langchain_google_vertexai import ChatVertexAI
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad.tools import format_to_tool_messages
from langchain.agents.output_parsers.tools import ToolsAgentOutputParser
from langchain.tools.base import StructuredTool
from langchain_core import prompts
from re import S
from typing import Callable, Sequence
import google.auth
import vertexai


class StreamingAgent:

    def __init__(
            self,
            model: str,
            tools: Sequence[Callable],
            project_id: str,
        ):
        self.model_name = model
        self.tools = tools
        self.project_id = project_id

    def set_up(self):
        """All unpickle-able logic should go here.

        The .set_up() method should not be called for an object that is being
        prepared for deployment.
        """
        creds, _ = google.auth.default(quota_project_id=self.project_id)
        vertexai.init(project=self.project_id, location="us-central1", credentials=creds)

        prompt = {
            "input": lambda x: x["input"],
            "agent_scratchpad": (
                lambda x: format_to_tool_messages(x["intermediate_steps"])
            ),
        } | prompts.ChatPromptTemplate.from_messages([
            ("user", "{input}"),
            prompts.MessagesPlaceholder(variable_name="agent_scratchpad"),
        ])

        llm = ChatVertexAI(model_name=self.model_name)
        if self.tools:
            llm = llm.bind_tools(tools=self.tools)

        self.agent_executor = AgentExecutor(
            agent=prompt | llm | ToolsAgentOutputParser(),
            tools=[StructuredTool.from_function(tool) for tool in self.tools],
        )

    def query(self, input: str):
        """Query the application.

        Args:
            input: The user prompt.

        Returns:
            The output of querying the application with the given input.
        """
        return self.agent_executor.invoke(input={"input": input})

    def stream_query(self, input: str):
        """Query the application and stream the output.

        Args:
            input: The user prompt.

        Yields:
            Chunks of the response as they become available.
        """
        for chunk in self.agent_executor.stream(input={"input": input}):
            yield chunk

def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Retrieves the exchange rate between two currencies on a specified date.

    Uses the Frankfurter API (https://api.frankfurter.app/) to obtain
    exchange rate data.

    Args:
        currency_from: The base currency (3-letter currency code).
            Defaults to "USD" (US Dollar).
        currency_to: The target currency (3-letter currency code).
            Defaults to "EUR" (Euro).
        currency_date: The date for which to retrieve the exchange rate.
            Defaults to "latest" for the most recent exchange rate data.
            Can be specified in YYYY-MM-DD format for historical rates.

    Returns:
        dict: A dictionary containing the exchange rate information.
            Example: {"amount": 1.0, "base": "USD", "date": "2023-11-24",
                "rates": {"EUR": 0.95534}}
    """
    import requests

    proxy_server = "http://proxy-vm.demo.com:8888" # This is the VM's FQDN to reach the proxy vm in the consumers network

    proxies = {
       "http": proxy_server,
       "https": proxy_server,
    }
    response = requests.get(
        f"https://api.frankfurter.app/{currency_date}",
        params={"from": currency_from, "to": currency_to},
        proxies=proxies,
    )
    return response.json()

Prześlij pliki agenta do Cloud Storage: prześlij serializowanego agenta i jego wymagania do wyznaczonego zasobnika GCS.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

# Upload files to Cloud Storage.
if not GCS_DIR:
    raise ValueError("GCS_DIR must be set.")

FILE = "streaming_agent.pkl"
blob = bucket.blob(f"{GCS_DIR}/{FILE}")
with blob.open("wb") as f:
    cloudpickle.dump(
        StreamingAgent(
            model="gemini-2.0-flash-001",  # Required.
            tools=[get_exchange_rate],  # Optional.
            project_id=PROJECT_ID
        ), f)


requirements = """
google-cloud-aiplatform[agent_engines,langchain]==1.96.0
cloudpickle==3.1.1
"""

blob = bucket.blob(f"{GCS_DIR}/requirements-streaming.txt")
blob.upload_from_string(requirements)

!gsutil ls gs://{BUCKET}/{GCS_DIR}

Wdróż Agent Engine: wdróż Agent Engine, konfigurując go za pomocą interfejsu PSC i komunikacji równorzędnej DNS, aby rozwiązać w sieci VPC konsumenta w pełni kwalifikowaną nazwę domeny maszyny wirtualnej proxy.

W notatniku JupyterLab utwórz i uruchom komórkę poniżej. Zwróć uwagę na te elementy:

  • DNS Peering do sieci VPC konsumenta jest konfigurowany za pomocą dnsPeeringConfigs (dnsPeeringConfigs) dla nazwy domeny demo.com.
import requests


token = !gcloud auth application-default print-access-token

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/reasoningEngines",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({
        "displayName": "PSC-I Explicit Proxy",
        "description": "test psc-i agent + proxy vm",
        "spec": {
            "packageSpec": {
                "pickleObjectGcsUri": f"gs://{BUCKET}/{GCS_DIR}/streaming_agent.pkl",
                "requirementsGcsUri": f"gs://{BUCKET}/{GCS_DIR}/requirements-streaming.txt",
                "pythonVersion": "3.10"
            },
            "deploymentSpec": {
                "pscInterfaceConfig": {
                    "networkAttachment": NETWORK_ATTACHMENT_NAME,
                    "dnsPeeringConfigs": [
                    {
                      "domain": "demo.com.",
                      "targetProject": PROJECT_ID,
                      "targetNetwork": "consumer-vpc", #Consumer VPC
                    },
                  ],
                }
            }
        },
    })
)

pprint.pprint(json.loads(response.content))
reasoning_engine_id = json.loads(response.content)["name"].split("/")[5]
pprint.pprint(reasoning_engine_id)

Monitoruj stan wdrożenia: sprawdź stan operacji wdrożenia Agent Engine.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

operation_id = json.loads(response.content)["name"].split("/")[7]
pprint.pprint(operation_id)

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

Uwaga: wykonanie tej operacji może potrwać około 5 minut. Uruchom ponownie komórkę, aby sprawdzić postęp. Nie przechodź do następnej sekcji, dopóki nie zobaczysz danych wyjściowych podobnych do tych na zrzucie ekranu poniżej.

# You can run this multiple times to check the status of the deployment operation, operation takes approx 5 min.
token = !gcloud auth application-default print-access-token
response = requests.get(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/operations/{operation_id}        ",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    }
)
pprint.pprint(json.loads(response.content))

Przykład udanego uruchomienia:

3f6dcd1074af7651.png

Wysyłanie zapytań do wdrożonego agenta: wyślij zapytanie do wdrożonego silnika agenta, aby przetestować jego działanie.

W notatniku JupyterLab utwórz nową komórkę i uruchom to polecenie:

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/{LOCATION}/reasoningEngines/{reasoning_engine_id}:query",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({ "input": {"input": "What is the exchange rate from US dollars to Euro?"} })
)
print(response.text)

Przesyłanie strumieniowe wyników zapytania: przesyłaj strumieniowo dane wyjściowe z zapytania do silnika agenta.

W notatniku JupyterLab utwórz nową komórkę i uruchom poniższy kod, który wywoła wywołanie interfejsu API do publicznego adresu URL przy użyciu jawnego serwera proxy w sieci VPC konsumentów.

token = !gcloud auth application-default print-access-token
print(f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}:streamQuery")

response = requests.post(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}:streamQuery",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
    data=json.dumps({ "input": {"input": "What is the exchange rate from US dollars to Euro?"} })
)
for chunk in response.iter_lines():
    print(chunk.decode('utf-8'))
# pprint.pprint(json.loads(response.content))

Przykład udanego uruchomienia:

1bd81d12426a348f.png

14. Weryfikacja za pomocą narzędzia tcpdump

Wyświetl dane wyjściowe tcpdump, które szczegółowo opisują komunikację między adresem IP przyłączenia sieci PSC używanym przez Agent Engine a maszyną wirtualną Prox-VM po wysłaniu żądania.

user@proxy-vm:~$ sudo tcpdump -i any net 192.168.10.0/28 -nn
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:17:53.983212 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [S], seq 3841740961, win 28800, options [mss 1440,sackOK,TS val 4245243253 ecr 0,nop,wscale 7], length 0
22:17:53.983252 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [S.], seq 2232973833, ack 3841740962, win 64768, options [mss 1420,sackOK,TS val 2251247643 ecr 4245243253,nop,wscale 7], length 0
22:17:53.985167 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [.], ack 1, win 225, options [nop,nop,TS val 4245243256 ecr 2251247643], length 0
22:17:53.986476 ens4  In  IP 192.168.10.2.22261 > 10.10.10.2.8888: Flags [P.], seq 1:45, ack 1, win 16384, options [nop,nop,TS val 4245243256 ecr 2251247643], length 44
22:17:53.986485 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [.], ack 45, win 506, options [nop,nop,TS val 2251247646 ecr 4245243256], length 0
22:17:54.043347 ens4  Out IP 10.10.10.2.8888 > 192.168.10.2.22261: Flags [P.], seq 1:71, ack 45, win 506, options [nop,nop,TS val 2251247703 ecr 4245243256], length 70

15. Weryfikacja interfejsu PSC

Adresy IP połączenia sieciowego używane przez Agent Engine możesz też sprawdzić, wykonując te czynności:

Usługi sieciowe → Private Service Connect → Przyłącze sieci → psc-network-attachment

Wybierz projekt najemcy (nazwa projektu kończy się na -tp).

8a4b5a6e5dfd63d7.png

Wyróżnione pole oznacza adres IP używany przez Agent Engine z załącznika sieci PSC.

c618359f6eafc0c6.png

16. Weryfikacja Cloud Logging

Zakończ sesję TCPDump na maszynie wirtualnej proxy i wykonaj polecenie PING na adres api.frankfurter.app, aby uzyskać powiązany publiczny adres IP.

ping -c4 api.frankfurter.app 

Przykład identyfikuje adres 104.26.1.198 jako publiczny adres IP domeny api.frankfurter.app.

user@proxy-vm:~$ ping -c4 api.frankfurter.app

PING api.frankfurter.app (104.26.1.198) 56(84) bytes of data.

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=1 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=2 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=3 ttl=61 time=10.9 ms

64 bytes from 104.26.1.198 (104.26.1.198): icmp_seq=4 ttl=61 time=10.9 ms

Przyjrzyjmy się logowaniu NAT, aby sprawdzić, czy zaobserwowano ruch dla adresu 104.26.1.198.

Przejdź do:

Monitorowanie → Eksplorator logów

Użyj tego filtra:

resource.type="nat_gateway"

31024dc29c39084.png

Wybierz przedział czasu, a następnie kliknij Uruchom zapytanie.

5976857e92d149d3.png

Rozwiń wpis dziennika, który identyfikuje (docelowy) publiczny adres IP (104.26.1.198) api.frankfurter.app oraz źródłowy adres IP i nazwę maszyny wirtualnej proxy, która weryfikuje użycie jawnego serwera proxy do wychodzącego ruchu internetowego.

14e293a7fea68db4.png

17. Czyszczenie danych

W notatniku JupyterLab utwórz nową komórkę i uruchom poniższy kod, który spowoduje usunięcie wdrożenia silnika agenta.

token = !gcloud auth application-default print-access-token

response = requests.delete(
    f"{ENDPOINT}/v1beta1/projects/{PROJECT_ID}/locations/us-central1/reasoningEngines/{reasoning_engine_id}",
    headers={
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {token[0]}"
    },
)
print(response.text)

W Cloud Shell usuń komponenty samouczka.

gcloud dns record-sets delete proxy-vm.demo.com --zone=private-dns-codelab  --type=A

gcloud dns managed-zones delete private-dns-codelab

gcloud compute instances delete proxy-vm --zone=us-central1-a --quiet

gcloud compute instances delete workbench-tutorial --zone=us-central1-a --quiet

gcloud compute routers delete cloud-router-for-nat --region=us-central1 --quiet

gcloud compute network-attachments delete psc-network-attachment --region=us-central1 --quiet

gcloud compute networks subnets delete intf-subnet rfc1918-subnet1 --region=us-central1 --quiet

gcloud compute networks delete consumer-vpc --quiet

18. Gratulacje

Gratulacje. Udało Ci się skonfigurować i zweryfikować silnik agenta wdrożony za pomocą interfejsu Private Service Connect z ruchem wychodzącym z internetu realizowanym przez jawny serwer proxy.

Infrastruktura konsumenta została utworzona, a do niej dodano przyłącze sieci, które umożliwiło producentowi utworzenie maszyny wirtualnej z wieloma interfejsami sieciowymi, aby połączyć komunikację konsumenta i producenta. Wiesz już, jak utworzyć jawny serwer proxy i połączenie równorzędne DNS, które umożliwiają łączność z internetem.

Cosmopup uważa, że samouczki są świetne!!

c911c127bffdee57.jpeg

Co dalej?

Więcej informacji i filmy

Dokumentacja