Cymbal Transit: un sistema multi-agente che utilizza LangChain4J e l'SDK Java di MCP Toolbox

1. Panoramica

I viaggiatori moderni si aspettano esperienze conversazionali. Invece di navigare tra filtri complessi dell'interfaccia utente, vogliono chiedere: "Posso portare il mio cane sull'autobus delle 9:00 per Boston?" Ciò richiede un agente in grado di ragionare su dati non strutturati (norme PDF) e dati strutturati (pianificazioni SQL).

In questo lab, creeremo l'agente di transito Cymbal utilizzando:

  • LangChain4j:il principale framework Java per l'orchestrazione dell'AI.
  • AlloyDB:un database compatibile con PostgreSQL ad alte prestazioni.
  • SDK Java di MCP Toolbox:un modo standardizzato per connettere gli agenti Java a strumenti esterni e origini dati.

Cosa creerai

e68388d533c9997e.png

Cymbal Bus Agent, un'applicazione Java Spring Boot composta da:

  1. Database AlloyDB e SDK Java di MCP Toolbox per l'orchestrazione degli strumenti con gli agenti.
  2. Cloud Run per il deployment e l'applicazione di Toolbox (deployment dell'agente).
  3. Libreria LangChain4J per l'agente e il framework LLM in un'applicazione Spring Boot con Java 17.

Obiettivi didattici

  • Come utilizzare LangChain4J per creare agenti e subagenti specializzati orchestrati utilizzando l'SDK Java di MCP Toolbox per i database
  • Come configurare e utilizzare AlloyDB per dati e AI.
  • Come utilizzare MCP Toolbox per connettere gli agenti agli strumenti di dati di AlloyDB.
  • Come eseguire il deployment della soluzione utilizzando Cloud Run o eseguirla localmente.

L'architettura

  1. AlloyDB per PostgreSQL:funge da database operativo ad alte prestazioni che contiene i nostri record di itinerari, norme e prenotazioni. Alimenta la ricerca e il recupero vettoriali.
  2. SDK Java di MCP Toolbox for Databases:funge da "maestro dell'orchestrazione", esponendo i dati di AlloyDB come strumenti eseguibili che gli agenti possono chiamare.

L'SDK Java di MCP Toolbox consente di orchestrare gli agenti con gli strumenti di database senza problemi per le applicazioni di livello aziendale.

  1. LangChain4J:una libreria Java open source che semplifica l'integrazione di modelli linguistici di grandi dimensioni (LLM) nelle applicazioni Java. Fornisce strumenti e astrazioni per la creazione di applicazioni basate sull'AI, tra cui chatbot, agenti e sistemi RAG (Retrieval-Augmented Generation).
  2. Cloud Run:una piattaforma serverless completamente gestita che ti consente di creare ed eseguire il deployment di app o siti web rapidamente in qualsiasi linguaggio, libreria o binario. Puoi scrivere codice utilizzando il linguaggio, il framework e le librerie che preferisci, pacchettizzarlo come container, eseguire "gcloud run deploy" e la tua app sarà attiva, con tutto ciò di cui ha bisogno per essere eseguita in produzione. La creazione di un container è del tutto facoltativa. Se usi Go, Node.js, Python, Java, .NET Core o Ruby, puoi usare l'opzione di deployment basato sull'origine, che crea il container per te, usando le best practice per il linguaggio che stai utilizzando.

Requisiti

  • Un browser, ad esempio Chrome o Firefox.
  • Un progetto Google Cloud con la fatturazione abilitata.
  • Conoscenza di base di SQL e Java.

2. Prima di iniziare

Crea un progetto

  1. Nella console Google Cloud, nella pagina di selezione del progetto, seleziona o crea un progetto Google Cloud.
  2. Verifica che la fatturazione sia attivata per il tuo progetto Cloud. Scopri come verificare se la fatturazione è abilitata per un progetto.
  1. Utilizzerai Cloud Shell, un ambiente a riga di comando in esecuzione in Google Cloud. Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.

Immagine del pulsante Attiva Cloud Shell

  1. Una volta eseguita la connessione a Cloud Shell, verifica di essere già autenticato e che il progetto sia impostato sul tuo ID progetto utilizzando il seguente comando:
gcloud auth list
  1. Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto.
gcloud config list project
  1. Se il progetto non è impostato, utilizza il seguente comando per impostarlo:
gcloud config set project <YOUR_PROJECT_ID>
  1. Abilita le API richieste: segui il link e abilita le API.

In alternativa, puoi utilizzare il comando gcloud. Consulta la documentazione per i comandi e l'utilizzo di gcloud.

Aspetti da considerare e risoluzione dei problemi

La sindrome del "progetto fantasma"

Hai eseguito gcloud config set project, ma in realtà stai esaminando un progetto diverso nell'interfaccia utente della console. Controlla l'ID progetto nel menu a discesa in alto a sinistra.

La barriera di fatturazione

Hai attivato il progetto, ma hai dimenticato l'account di fatturazione. AlloyDB è un motore ad alte prestazioni; non si avvia se il "serbatoio" (fatturazione) è vuoto.

Ritardo di propagazione dell'API

Hai fatto clic su "Abilita API", ma la riga di comando indica ancora Service Not Enabled. Attendi 60 secondi. Il cloud ha bisogno di un attimo per attivare i suoi neuroni.

Quota Quags

Se utilizzi un account di prova nuovo di zecca, potresti raggiungere una quota regionale per le istanze AlloyDB. Se us-central1 non va a buon fine, prova us-east1.

Service Agent"Nascosto"

A volte all'agente di servizio AlloyDB non viene concesso automaticamente il ruolo aiplatform.user. Se in un secondo momento le query SQL non riescono a comunicare con Gemini, di solito questo è il problema.

3. Configurazione del database

Al centro della nostra applicazione si trova AlloyDB per PostgreSQL. Abbiamo sfruttato le sue potenti funzionalità vettoriali e il motore colonnare integrato per generare incorporamenti per oltre 50.000 record SCM. Ciò consente l'analisi vettoriale quasi in tempo reale, consentendo ai nostri agenti di identificare anomalie di inventario o rischi logistici in set di dati di grandi dimensioni in pochi millisecondi.

In questo lab utilizzeremo AlloyDB come database per i dati di test. Utilizza i cluster per contenere tutte le risorse, come database e log. Ogni cluster ha un'istanza primaria che fornisce un punto di accesso ai dati. Le tabelle conterranno i dati effettivi.

Creiamo un cluster, un'istanza e una tabella AlloyDB in cui verrà caricato il set di dati di test.

  1. Fai clic sul pulsante o copia il link riportato di seguito nel browser in cui hai eseguito l'accesso all'utente della console Google Cloud.

In alternativa, puoi andare al terminale Cloud Shell dal progetto in cui hai riscattato l'account di fatturazione, clonare il repository GitHub e passare al progetto utilizzando i comandi riportati di seguito:

git clone https://github.com/AbiramiSukumaran/easy-alloydb-setup

cd easy-alloydb-setup
  1. Una volta completato questo passaggio, il repository verrà clonato nell'editor Cloud Shell locale e potrai eseguire il comando riportato di seguito dalla cartella del progetto (è importante assicurarsi di trovarsi nella directory del progetto):
sh run.sh
  1. Ora utilizza la UI (facendo clic sul link nel terminale o sul link "Anteprima sul web" nel terminale).
  2. Inserisci i tuoi dati per l'ID progetto, il cluster e i nomi delle istanze per iniziare.
  3. Prendi un caffè mentre scorrono i log e leggi qui come funziona dietro le quinte.

Aspetti da considerare e risoluzione dei problemi

Il problema della "pazienza"

I cluster di database sono un'infrastruttura pesante. Se aggiorni la pagina o termini la sessione Cloud Shell perché "sembra bloccata", potresti ritrovarti con un'istanza "fantasma" di cui è stato eseguito il provisioning parziale e impossibile da eliminare senza un intervento manuale.

Regione non corrispondente

Se hai abilitato le API in us-central1, ma provi a eseguire il provisioning del cluster in asia-south1, potresti riscontrare problemi di quota o ritardi nell'autorizzazione del service account. Attieniti a una regione per l'intero lab.

Zombie Clusters

Se in precedenza hai utilizzato lo stesso nome per un cluster e non lo hai eliminato, lo script potrebbe indicare che il nome del cluster esiste già. I nomi dei cluster devono essere univoci all'interno di un progetto.

Timeout di Cloud Shell

Se la pausa caffè dura 30 minuti, Cloud Shell potrebbe entrare in modalità di sospensione e disconnettere il processo sh run.sh. Mantieni la scheda attiva.

4. Provisioning dello schema

Una volta che il cluster e l'istanza AlloyDB sono in esecuzione, vai all'editor SQL di AlloyDB Studio per attivare le estensioni AI e eseguire il provisioning dello schema.

1e3ac974b18a8113.png

Potrebbe essere necessario attendere il completamento della creazione dell'istanza. Una volta creato, accedi ad AlloyDB utilizzando le credenziali che hai creato durante la creazione del cluster. Utilizza i seguenti dati per l'autenticazione a PostgreSQL:

  • Nome utente : "postgres"
  • Database : "postgres"
  • Password : "alloydb" (o quella che hai impostato al momento della creazione)

Una volta eseguita l'autenticazione in AlloyDB Studio, i comandi SQL vengono inseriti nell'editor. Puoi aggiungere più finestre dell'editor utilizzando il segno più a destra dell'ultima finestra.

28cb9a8b6aa0789f.png

Inserirai i comandi per AlloyDB nelle finestre dell'editor, utilizzando le opzioni Esegui, Formatta e Cancella in base alle esigenze.

Attivare le estensioni

Per creare questa app, utilizzeremo le estensioni pgvector e google_ml_integration. L'estensione pgvector consente di archiviare ed eseguire ricerche di vector embedding. L'estensione google_ml_integration fornisce funzioni che utilizzi per accedere agli endpoint di previsione Vertex AI per ottenere previsioni in SQL. Attiva queste estensioni eseguendo i seguenti DDL:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

Concedi autorizzazione

Esegui l'istruzione riportata di seguito per concedere l'esecuzione della funzione "embedding":

GRANT EXECUTE ON FUNCTION embedding TO postgres;

Concedi il ruolo Utente Vertex AI al service account AlloyDB

Dalla console Google Cloud IAM, concedi al service account AlloyDB (simile a service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) l'accesso al ruolo "Utente Vertex AI". PROJECT_NUMBER conterrà il numero del tuo progetto.

In alternativa, puoi eseguire il comando riportato di seguito dal terminale Cloud Shell:

PROJECT_ID=$(gcloud config get-value project)


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

Creare una tabella

Puoi creare una tabella utilizzando l'istruzione DDL riportata di seguito in AlloyDB Studio:

DROP TABLE IF EXISTS transit_policies;
DROP TABLE IF EXISTS bus_schedules;
DROP TABLE IF EXISTS bookings;

-- Table 1: Transit Policies (Unstructured Data for RAG)
CREATE TABLE transit_policies (
    policy_id SERIAL PRIMARY KEY,
    category VARCHAR(50),
    policy_text TEXT,
    policy_embedding vector(768) 
);

-- Table 2: Intercity Bus Schedules (Structured Data)
CREATE TABLE bus_schedules (
    trip_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    origin_city VARCHAR(100),
    destination_city VARCHAR(100),
    departure_time TIMESTAMP,
    arrival_time TIMESTAMP,
    available_seats INT DEFAULT 50,
    ticket_price DECIMAL(6,2)
);

-- Table 3: Booking Ledger (Transactional Action Data)
CREATE TABLE bookings (
    booking_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    trip_id UUID REFERENCES bus_schedules(trip_id),
    passenger_id VARCHAR(100),
    status VARCHAR(20) DEFAULT 'CONFIRMED',
    booking_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

La colonna policy_embedding consentirà di memorizzare i valori del vettore di alcuni campi di testo.

Importazione dati

Esegui il seguente insieme di istruzioni SQL per inserire in blocco i record nelle rispettive tabelle:

  1. Inserire politiche non strutturate e GENERARE EMBEDDING REALI in modo nativo in AlloyDB
-- 1. Insert Unstructured Policies and GENERATE REAL EMBEDDINGS natively in AlloyDB

INSERT INTO transit_policies (category, policy_text, policy_embedding) 
VALUES 
('Pets', 'Service animals are always welcome. Small pets (under 25 lbs) are allowed in secure carriers for a $25 fee. Large dogs are not permitted on standard coaches.', embedding('text-embedding-005', 'Service animals are always welcome. Small pets (under 25 lbs) are allowed in secure carriers for a $25 fee. Large dogs are not permitted on standard coaches.')),
('Luggage', 'Each passenger is allowed one carry-on (up to 15 lbs) and two stowed bags (up to 50 lbs each) free of charge. Additional bags cost $15 each.', embedding('text-embedding-005', 'Each passenger is allowed one carry-on (up to 15 lbs) and two stowed bags (up to 50 lbs each) free of charge. Additional bags cost $15 each.')),
('Refunds', 'Tickets are fully refundable up to 24 hours before departure. Within 24 hours, tickets can be exchanged for travel credit only.', embedding('text-embedding-005', 'Tickets are fully refundable up to 24 hours before departure. Within 24 hours, tickets can be exchanged for travel credit only.'));
  1. Generare oltre 200 programmi realistici per 7 giorni utilizzando generate_series
-- 2. Generate 200+ Realistic Schedules for the Next 7 Days using generate_series

INSERT INTO bus_schedules (origin_city, destination_city, departure_time, arrival_time, ticket_price, available_seats)
SELECT 
    origin,
    destination,
    -- Generate departures every 4 hours starting from tomorrow
    (CURRENT_DATE + 1) + (interval '4 hours' * seq) AS dep_time,
    (CURRENT_DATE + 1) + (interval '4 hours' * seq) + interval '4.5 hours' AS arr_time,
    ROUND((RANDOM() * 30 + 25)::numeric, 2) AS price, -- Random price between $25 and $55
    FLOOR(RANDOM() * 50 + 1) AS seats -- Random seats between 1 and 50
FROM 
    (VALUES 
        ('New York', 'Boston'), ('Boston', 'New York'),
        ('Philadelphia', 'Washington DC'), ('Washington DC', 'Philadelphia'),
        ('Seattle', 'Portland'), ('Portland', 'Seattle')
    ) AS routes(origin, destination)
CROSS JOIN generate_series(1, 40) AS seq; -- 6 routes * 40 time slots = 240 distinct trips ingested!

Genera incorporamenti

Gli embedding vengono coperti automaticamente nell'istruzione di inserimento nella tabella transit_policies utilizzando la funzione "embedding('text-embedding-005', '<<policytext>>')".

Aspetti da considerare e risoluzione dei problemi

Il ciclo "Amnesia della password"

Se hai utilizzato la configurazione "Un clic" e non ricordi la password, vai alla pagina delle informazioni di base dell'istanza nella console e fai clic su "Modifica" per reimpostare la password di postgres.

Errore "Estensione non trovata"

Se CREATE EXTENSION non va a buon fine, spesso è perché l'istanza è ancora nello stato "Manutenzione" o "Aggiornamento" dal provisioning iniziale. Controlla se il passaggio di creazione dell'istanza è completato e attendi qualche secondo, se necessario.

Problemi di propagazione di IAM

Hai eseguito il comando IAM gcloud, ma il comando SQL CALL continua a non riuscire a causa di un errore di autorizzazione. La propagazione delle modifiche IAM può richiedere un po' di tempo tramite l'infrastruttura di Google. Fai un respiro.***CRITICO:

  1. A volte, è possibile che il service account AlloyDB abbia un aspetto diverso dal formato esistente che abbiamo utilizzato nel passaggio delle autorizzazioni. Per assicurarti al 100% che il service account AlloyDB disponga del ruolo Utente Vertex AI: vai alla pagina Cluster AlloyDB nella console Google Cloud. Fai clic sul cluster e nella scheda Panoramica cerca un campo etichettato Service Account.
    Copia il valore e poi vai a IAM e aggiungi il ruolo Utente Vertex AI.
  2. Inoltre, se hai saltato il passaggio "Abilita API" nella sezione "Prima di iniziare", avrai problemi ad accedere agli incorporamenti da AlloyDB.

Mancata corrispondenza delle dimensioni del vettore

La colonna policy_embedding della tabella transit_policies è impostata su VECTOR(768). Se in un secondo momento provi a utilizzare un modello diverso (ad esempio un modello a 1536 dimensioni), gli inserti verranno espansi. Attieniti a text-embedding-005.

Errore di battitura nell'ID progetto

Nella chiamata create_model, se lasci le parentesi « » o digiti in modo errato l'ID progetto, la registrazione del modello sembrerà riuscita, ma non andrà a buon fine durante la prima query effettiva. Controlla la stringa.

5. Configurazione di strumenti e toolbox

MCP Toolbox for Databases è un server MCP open source per i database. Ti consente di sviluppare strumenti in modo più semplice, rapido e sicuro gestendo le complessità come il pooling di connessioni, l'autenticazione e altro. Toolbox ti aiuta a creare strumenti di AI generativa che consentono agli agenti di accedere ai dati del tuo database.

Utilizziamo Model Context Protocol (MCP) Toolbox for Databases come "direttore d'orchestra". Funge da middleware standardizzato tra i nostri agenti e AlloyDB. Definendo una configurazione tools.yaml, la casella degli strumenti espone automaticamente operazioni di database complesse come strumenti puliti ed eseguibili come find-bus-schedules and routes o query-schedules for specific routes ed esegue azioni autonome come book-ticket. In questo modo si elimina la necessità di raggruppamento manuale delle connessioni o di SQL boilerplate nella logica dell'agente.

Installazione del server Toolbox

Dal terminale Cloud Shell, crea una cartella per salvare il nuovo file YAML degli strumenti e il file binario della toolbox:

mkdir cymbal-bus-toolbox

cd cymbal-bus-toolbox

Dall'interno della nuova cartella, esegui il seguente insieme di comandi:

# see releases page for other versions
export VERSION=0.27.0
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox

Poi crea il file tools.yaml all'interno della nuova cartella navigando nell'editor di Cloud Shell e copia i contenuti di questo file repo nel file tools.yaml.

... (Refer to entire file in the repo)

tools:

   find-bus-schedules:
    kind: postgres-sql
    source: alloydb
    description: Find all available bus schedules.
    statement: |
      SELECT CAST(trip_id AS TEXT) trip_id, departure_time, arrival_time, ticket_price, available_seats , origin_city, destination_city 
      FROM bus_schedules;

   query-schedules:
    kind: postgres-sql
    source: alloydb
    description: Find available bus schedules between an origin and destination city.
    parameters:
      - name: origin
        type: string
        description: The departure city name.
      - name: destination
        type: string
        description: The arrival city name.
    statement: |
      SELECT CAST(trip_id AS TEXT) trip_id, departure_time, arrival_time, ticket_price, available_seats 
      FROM bus_schedules 
      WHERE lower(origin_city) = lower($1) 
        AND lower(destination_city) = lower($2) 
        AND available_seats > 0 
      ORDER BY departure_time ASC 
      LIMIT 5;

   book-ticket:
    kind: postgres-sql
    source: alloydb
    description: Books a ticket for a specific trip, decrementing available seats and generating a confirmed booking record.
    parameters:
      - name: trip_id
        type: string
        description: The UUID of the trip schedule to book.
      - name: passenger_name
        type: string
        description: Name or ID of the passenger (Bound securely via backend or AuthToken).
        authServices:
          - name: google_auth
            field: sub
    statement: |
      WITH updated_schedule AS (
          UPDATE bus_schedules 
          SET available_seats = available_seats - 1 
          WHERE trip_id = CAST($1 AS UUID) AND available_seats > 0
          RETURNING trip_id
      )
      INSERT INTO bookings (trip_id, passenger_id)
      SELECT trip_id, $2 
      FROM updated_schedule
      RETURNING CAST(booking_id as TEXT) as booking_id, trip_id, passenger_id, status, booking_time;

   search-policies:
    kind: postgres-sql
    source: alloydb
    description: Semantic search for transit policies regarding luggage, pets, refunds, and general rules.
    parameters:
      - name: search_query
        type: string
        description: The user's question about transit policies to be embedded and searched.
    statement: |
      SELECT category, policy_text 
      FROM transit_policies 
      ORDER BY policy_embedding <=> CAST(embedding('text-embedding-005', $1) AS vector(768))
      LIMIT 2;

Nota:

  1. Nella configurazione di tools.yaml, non dimenticare di includere ipType: "private" nella configurazione dell'origine AlloyDB.
  2. Ricorda anche di includere l'URL del servizio MCP Toolbox nel parametro clientId per la configurazione di authServices. Potresti ricevere il link solo dopo l'implementazione iniziale, quindi dovrai eseguire i passaggi di implementazione due volte per assicurarti che lo scenario di utilizzo degli strumenti autenticati funzioni.
  3. Le opzioni riportate di seguito per testare la toolbox localmente non funzioneranno se la connessione AlloyDB è impostata come privata. Devi impostarla come pubblica per testarla localmente o utilizzare un proxy per la connessione. Ma non preoccuparti. Nel nostro caso, lo eseguiremo il deployment direttamente su Cloud Run e poi lo testeremo.

Per testare il file tools.yaml nel server locale:

./toolbox --tools-file "tools.yaml"

In alternativa, puoi testarlo nell'interfaccia utente:

./toolbox --ui

Eseguiamo il deployment in Cloud Run nel seguente modo.

Deployment di Cloud Run

  1. Imposta la variabile di ambiente PROJECT_ID:
export PROJECT_ID="my-project-id"
  1. Inizializza gcloud CLI:
gcloud init
gcloud config set project $PROJECT_ID
  1. Devi aver abilitato le seguenti API:
gcloud services enable run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       iam.googleapis.com \
                       secretmanager.googleapis.com
  1. Crea un account di servizio backend se non ne hai già uno:
gcloud iam service-accounts create toolbox-identity
  1. Concedi le autorizzazioni per utilizzare Secret Manager:
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/secretmanager.secretAccessor
  1. Concedi al service account autorizzazioni aggiuntive specifiche per la nostra origine AlloyDB (ruoli roles/alloydb.client e roles/serviceusage.serviceUsageConsumer)
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/alloydb.client


gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/serviceusage.serviceUsageConsumer
  1. Carica tools.yaml come secret:
gcloud secrets create tools-cymbal-transit --data-file=tools.yaml
  1. Se hai già un secret e vuoi aggiornare la versione del secret, esegui il comando seguente:
gcloud secrets versions add tools-cymbal-transit --data-file=tools.yaml
  1. Imposta una variabile di ambiente sull'immagine container che vuoi utilizzare per Cloud Run:
export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
  1. Esegui il deployment di Toolbox su Cloud Run utilizzando questo comando:

Se hai abilitato l'accesso pubblico nella tua istanza AlloyDB, segui il comando riportato di seguito per il deployment su Cloud Run:

gcloud run deploy toolbox-cymbal-transit \
    --image $IMAGE \
    --service-account toolbox-identity \
    --region us-central1 \
    --set-secrets "/app/tools.yaml=tools-cymbal-transit:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated

Se utilizzi una rete VPC, utilizza il comando riportato di seguito:

gcloud run deploy toolbox-cymbal-transit \
    --image $IMAGE \
    --service-account toolbox-identity \
    --region us-central1 \
    --set-secrets "/app/tools.yaml=tools-cymbal-transit:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --network <<YOUR_NETWORK_NAME>> \
    --subnet <<YOUR_SUBNET_NAME>> \
    --allow-unauthenticated

Nota: una volta eseguito il deployment, vai all'elenco dei servizi Cloud Run e assicurati che nella scheda di sicurezza di quel servizio sia selezionata l'opzione "Consenti accesso pubblico".

6. Configurazione dell'applicazione agente

Clona questo repository nel tuo progetto e analizziamolo.

Repository GitHub

Per clonare questo progetto, esegui questo comando dal terminale Cloud Shell (nella directory principale o da dove vuoi creare il progetto):

git clone https://github.com/googleapis/mcp-toolbox-sdk-java

Il comando precedente clona l'intero mcp-toolbox-sdk-java. Ci serve solo il progetto di esempio. Vai alla directory root del progetto all'interno del repository:

cd mcp-toolbox-sdk-java/demo-applications/cymbal-transit
  1. In questo modo dovrebbe essere creato il progetto, che puoi verificare nell'editor di Cloud Shell.

a494664032904c77.png

  1. Apri CymbalTransitController.java e imposta le variabili di ambiente:
  2. GCP_PROJECT_ID
  3. GCP_REGION
  4. GEMINI_MODEL_NAME
  5. MCP_TOOLBOX_URL

In alternativa (solo a scopo di sviluppo), puoi anche sostituire i segnaposto dei rispettivi valori di riserva.

7. Procedura dettagliata del codice

CymbalTransitController funge da punto di ingresso per il nostro servizio Cloud Run. Gestisce il flusso della conversazione e garantisce che l'agente abbia accesso alla richiesta corrente dell'utente.

L'implementazione segue un'architettura a livelli che separa l'orchestrazione dell'AI, il bridging degli strumenti e la comunicazione MCP di basso livello.

1. Configurazione dell'agente AI (AgentConfiguration)

Questa classe utilizza @Configuration di Spring per eseguire il bootstrap dei componenti AI. Inizializza VertexAiGeminiChatModel e lo associa alla nostra interfaccia Agent.

@Bean
ChatLanguageModel geminiChatModel() {
    return VertexAiGeminiChatModel.builder()
        .project(projectId)
        .location(region)
        .modelName(modelName)
        .build();
}

@Bean
TransitAgent transitAgent(ChatLanguageModel chatLanguageModel, TransitAgentTools tools) {
    return AiServices.builder(TransitAgent.class)
        .chatLanguageModel(chatLanguageModel)
        .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(20))
        .tools(tools) 
        .build();
}

Significato: AiServices associa l'interfaccia all'LLM. MessageWindowChatMemory garantisce che l'agente ricordi le preferenze dell'utente (come un trasportino per animali domestici menzionato in precedenza) per un massimo di 20 messaggi all'interno di una singola sessione.

2. Interfaccia dell'agente AI (TransitAgent)

L'annotazione @SystemMessage definisce il "Personaggio" e i vincoli operativi, in particolare una strategia di routing.

@SystemMessage({
    "You are the Cymbal Transit Concierge.",
    "CRITICAL INSTRUCTION: On your very first interaction, you MUST use the 'findAllSchedules' tool to fetch and memorize the broad bus routes.",
    "ONLY if the user asks a specifically narrowed-down question... should you route to the specific tools like 'querySchedules', 'bookTicket', 'searchPolicies'.",
    "Don't show any asterisks while listing results. Keep it formatted and numbered or bulleted."
})
String chat(@MemoryId String sessionId, @UserMessage String userMessage);

Significato:questa strategia riduce al minimo la latenza. Recuperando prima i dati generali, l'agente può rispondere a domande generali sul routing utilizzando il contesto interno senza effettuare chiamate di backend ridondanti.

3. Toolbox Bridge (TransitAgentTools)

Questo servizio funge da "mani" dell'agente, traducendo le chiamate agli strumenti LangChain4j in logica di esecuzione.

@Tool("Fetches the initial, broad dataset of all available bus schedules and routes.")
public String findAllSchedules() {
    return mcpService.findAllSchedules().join();
}


@Tool("Book a ticket for a passenger using a specific trip ID.")
public String bookTicket(String tripId, String passengerName) {
    return mcpService.bookTicket(tripId, passengerName).join();
}

Esecuzione sincrona:sebbene le chiamate MCP siano asincrone (restituiscono CompletableFuture), l'LLM richiede un risultato prima di poter continuare il suo processo di "pensiero". Utilizziamo .join() per fornire risultati sincroni all'agente.

4. Il servizio MCP Toolbox (McpToolboxService)

Questo è il livello di comunicazione che utilizza l'SDK Java di MCP Toolbox per interagire con il backend di AlloyDB.

// Identity Management: Fetching OIDC ID Token for Auth
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
this.idToken = ((IdTokenProvider) credentials)
    .idTokenWithAudience(targetUrl, Collections.emptyList())
    .getTokenValue();

// Dynamic Invocation: Executing a tool by name
public CompletableFuture<String> findAllSchedules() {
    return mcpClient.invokeTool("find-bus-schedules", Collections.emptyMap()).thenApply(result -> {
        return result.content().stream()
            .map(content -> content.text())
            .collect(Collectors.joining(", ", "[", "]"));
    });
}

Significato: McpToolboxClient gestisce il lavoro pesante della comunicazione JSON-RPC. Il metodo bookTicket mostra in modo specifico la capacità dell'SDK di associare dinamicamente parametri complessi.

5. Il controller REST (TransitAgentController)

L'endpoint finale è radicalmente semplificato perché LangChain4j gestisce lo stato e la logica.

@PostMapping("/chat")
public ResponseEntity<String> handleUserChat(@RequestBody String userMessage, HttpSession session) {
    String sessionId = session.getId();
    String agentResponse = transitAgent.chat(sessionId, userMessage);
    return ResponseEntity.ok(agentResponse);
}

Significato:mappando l'ID HttpSession a @MemoryId, ci assicuriamo che i piani di viaggio di utenti diversi non vengano confusi, mantenendo al contempo il codice del controller pulito e leggibile.

8. MCP Toolbox: significatività e SDK Java

Che cos'è MCP?

Considera il Model Context Protocol (MCP) come un traduttore universale per l'AI. Creato per standardizzare il modo in cui i modelli AI si connettono a strumenti e set di dati esterni, MCP sostituisce gli script di integrazione personalizzati e frammentati con un protocollo universale sicuro. Che l'agente debba eseguire una query SQL transazionale, cercare tra migliaia di documenti di policy o attivare un'API REST, MCP fornisce un'interfaccia singola e unificata.

Strumenti MCP per i database

I team di ingegneria stanno andando oltre i semplici chatbot per creare sistemi agentici che interagiscono direttamente con i database mission-critical. Tuttavia, la creazione di questi agent aziendali spesso comporta l'incontro con un muro di integrazione di codice di collegamento personalizzato, API fragili e logica di database complessa.

Per sostituire questi colli di bottiglia hardcoded con un control plane sicuro e unificato, siamo felici di annunciare l'SDK Java per il toolbox Model Context Protocol (MCP) per i database. Questa release introduce l'orchestrazione di agenti di prima classe e type-safe nell'ecosistema aziendale più adottato al mondo. L'architettura matura di Java è progettata appositamente per queste esigenze rigorose, fornendo l'elevata concorrenza, la rigorosa integrità transazionale e la solida gestione dello stato necessarie per scalare in sicurezza gli agenti AI mission critical in produzione.

Perché l'SDK Java?

L'SDK Java di MCP Toolbox consente agli sviluppatori Java di:

  1. Consume Tools:connettiti a un server MCP (come MCP Toolbox per AlloyDB) e trasforma automaticamente le sue funzionalità in metodi Java comprensibili a LangChain4j.
  2. Type Safety:sfrutta la tipizzazione forte di Java per i parametri degli strumenti, riducendo gli errori di "allucinazione" di runtime nelle chiamate degli strumenti.
  3. Preparazione per l'utilizzo aziendale:integrazione semplice con Spring Boot, Quarkus, Micronaut e così via.
  4. Connessione senza problemi: evita di scrivere codice JSON-RPC boilerplate.
  5. Standardizza l'autenticazione:il supporto nativo per i token OIDC di Google Cloud garantisce l'esecuzione sicura degli strumenti.

e molto altro.

Dipendenze: configurazione di pom.xml

Aggiungi la seguente dipendenza al tuo progetto Maven per includere l'ultima versione dell'SDK Java di MCP Toolbox:

   <dependency>
        <groupId>com.google.cloud.mcp</groupId>
        <artifactId>mcp-toolbox-sdk-java</artifactId>
        <version>0.2.0</version>
    </dependency>

Aggiungi la seguente dipendenza al tuo progetto Maven per includere l'artefatto LangChain4j:

     <!-- LangChain4j Core & Gemini -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.35.0</version>
    </dependency>

È tutto!!! Abbiamo clonato correttamente il progetto e illustrato i dettagli dell'agente, dell'SDK Java di MCP Toolbox e del contesto.

9. Esecuzione in locale

Per testare l'agente sulla tua macchina, devi indirizzarlo al server MCP Toolbox di cui hai eseguito il deployment.

  1. Imposta le variabili di ambiente:
export GCP_PROJECT_ID="<<YOUR_PROJECT_ID>>"
export GCP_REGION="us-central1"
export GEMINI_MODEL_NAME="gemini-2.5-flash"
export MCP_TOOLBOX_URL="<<YOUR_TOOLBOX_ENDPOINT_URL>>/mcp"
  1. Esegui con Maven:
mvn compile

mvn spring-boot:run

In questo modo l'agente dovrebbe avviarsi localmente e dovresti essere in grado di testarlo.

10. Eseguiamo il deployment in Cloud Run

Esegui il deployment su Cloud Run eseguendo questo comando dal terminale Cloud Shell in cui il progetto è clonato e assicurati di trovarti nella cartella principale del progetto.

SE NON TI TROVI NELLA CARTELLA RADICE DEL NOSTRO PROGETTO ATTUALE, esegui questo comando nel terminale Cloud Shell:

cd cymbal-transit

Se ti trovi già nella radice di cymbal-transit, esegui il comando riportato di seguito per eseguire il deployment diretto dell'app su Cloud Run:

gcloud run deploy cymbal-transit --source . --set-env-vars GCP_PROJECT_ID=<<YOUR_PROJECT_ID>>,GCP_REGION=us-central1,GEMINI_MODEL_NAME=gemini-2.5-flash,MCP_TOOLBOX_URL=<<YOUR_MCP_TOOLBOX_URL>> --allow-unauthenticated

Sostituisci i valori dei segnaposto <<YOUR_PROJECT>> and <<YOUR_MCP_TOOLBOX_URL>>

Al termine del comando, verrà visualizzato un URL del servizio. Copialo.

Concedi il ruolo Client AlloyDB al service account Cloud Run.In questo modo, la tua applicazione serverless può creare un tunnel sicuro nel database.

Esegui questo comando nel terminale Cloud Shell:

# 1. Get your Project ID and Project Number
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")

# 2. Grant the AlloyDB Client role
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role="roles/alloydb.client"

Nota: una volta eseguito il deployment, vai all'elenco dei servizi Cloud Run e assicurati che nella scheda di sicurezza di quel servizio sia selezionata l'opzione "Consenti accesso pubblico".

Ora utilizza l'URL del servizio (l'endpoint Cloud Run che hai copiato in precedenza) e testa l'app.

Nota:se riscontri un problema con il servizio e viene indicata la memoria come motivo, prova ad aumentare il limite di memoria allocata a 1 GiB per eseguire il test.

11. Demo

Chiedi all'agente: "Domani mattina devo andare da New York a Boston. Posso portare il mio Golden Retriever?" Osserva come l'agente:

  1. Cerca le norme per i cani di taglia grande.
  2. Trova orari specifici.
  3. Riepiloga il viaggio più veloce con un ID viaggio.
  4. Prenota anche un biglietto se dai seguito alla richiesta di azione.

aa0408a81074d0fc.png

12. Esegui la pulizia

Una volta completato questo lab, non dimenticare di eliminare il cluster e l'istanza AlloyDB.

Dovrebbe pulire il cluster insieme alle relative istanze.

13. Complimenti

Hai creato un agente di transito sofisticato basato su Java. Sfruttando LangChain4j per l'orchestrazione e l'SDK Java di MCP Toolbox per la connettività dei dati, hai creato un sistema in grado di ragionare su agenti, strumenti e origini dati. Se vuoi iniziare a orchestrare le tue applicazioni agentic con MCP Toolbox for Databases in più database, anche su più piattaforme, inizia subito a utilizzare l'SDK Java. Qui puoi trovare il blog dell'annuncio di lancio che fornisce informazioni più dettagliate sulla libreria. Se vuoi creare altre applicazioni di questo tipo in modo pratico, senza costi, al tuo ritmo e con la guida di un istruttore, registrati a Code Vipassana all'indirizzo https://codevipassana.dev.