Cymbal Transit: Многоагентная система с использованием LangChain4J и Java SDK MCP Toolbox.

1. Обзор

Современные путешественники ожидают диалогового взаимодействия. Вместо того чтобы разбираться в сложных фильтрах пользовательского интерфейса, они хотят спросить: «Можно ли взять с собой собаку в автобус до Бостона в 9 утра?» Для этого требуется агент, способный анализировать неструктурированные данные (политики в формате PDF) и структурированные данные (расписания SQL).

В этой лабораторной работе мы создадим агента Cymbal Transit Agent , используя следующие инструменты:

  • LangChain4j: Ведущий Java-фреймворк для оркестровки ИИ.
  • AlloyDB: высокопроизводительная база данных, совместимая с PostgreSQL.
  • MCP Toolbox Java SDK: стандартизированный способ подключения Java-агентов к внешним инструментам и источникам данных.

Что вы построите

e68388d533c9997e.png

Cymbal Bus Agent — это Java Spring Boot приложение, состоящее из:

  1. База данных AlloyDB и Java SDK MCP Toolbox для оркестрации инструментов с помощью агентов.
  2. Cloud Run для развертывания инструментов и приложений (развертывание агентов).
  3. Библиотека LangChain4J для агента и фреймворка LLM в приложении Spring Boot на Java 17.

Что вы узнаете

  • Как использовать LangChain4J для создания специализированных агентов и субагентов, управляемых с помощью Java SDK MCP Toolbox for Databases.
  • Как настроить и использовать AlloyDB для работы с данными и искусственным интеллектом.
  • Как использовать MCP Toolbox для подключения агентов к инструментам обработки данных AlloyDB.
  • Как развернуть решение с помощью Cloud Run или запустить его локально.

Архитектура

  1. AlloyDB для PostgreSQL: служит высокопроизводительной операционной базой данных, хранящей записи о маршрутах, политиках и бронированиях. Она обеспечивает векторный поиск и извлечение данных.
  2. MCP Toolbox for Databases Java SDK: выступает в роли «маэстро оркестровки», предоставляя доступ к данным AlloyDB в виде исполняемых инструментов, которые могут вызывать агенты.

MCP Toolbox Java SDK позволяет без труда организовывать взаимодействие агентов с вашими инструментами работы с базами данных для приложений корпоративного уровня.

  1. LangChain4J: Библиотека Java с открытым исходным кодом, упрощающая интеграцию больших языковых моделей (LLM) в Java-приложения. Она предоставляет инструменты и абстракции для создания приложений на основе искусственного интеллекта, включая чат-боты, агентов и системы генерации с дополненной информацией (RAG).
  2. Cloud Run: полностью управляемая БЕССЕРВЕРНАЯ платформа, позволяющая легко и быстро создавать и развертывать приложения или веб-сайты на любом языке, с любой библиотекой и любым исполняемым файлом. Вы можете писать код, используя свой любимый язык, фреймворк и библиотеки, упаковывать его в контейнер, запускать команду «gcloud run deploy», и ваше приложение будет запущено — со всем необходимым для работы в продакшене. Создание контейнера является полностью необязательным. Если вы используете Go, Node.js, Python, Java, .NET Core или Ruby, вы можете использовать вариант развертывания на основе исходного кода , который создаст контейнер для вас, используя лучшие практики для используемого вами языка.

Требования

  • Браузер, например Chrome или Firefox .
  • Проект Google Cloud с включенной функцией выставления счетов.
  • Базовые знания SQL и Java.

2. Прежде чем начать

Создать проект

  1. В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
  2. Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта .
  1. Вы будете использовать Cloud Shell — среду командной строки, работающую в Google Cloud. Нажмите «Активировать Cloud Shell» в верхней части консоли Google Cloud.

Изображение кнопки «Активировать Cloud Shell»

  1. После подключения к Cloud Shell необходимо проверить, прошли ли вы аутентификацию и установлен ли идентификатор вашего проекта, используя следующую команду:
gcloud auth list
  1. Выполните следующую команду в Cloud Shell, чтобы убедиться, что команда gcloud знает о вашем проекте.
gcloud config list project
  1. Если ваш проект не задан, используйте следующую команду для его установки:
gcloud config set project <YOUR_PROJECT_ID>
  1. Включите необходимые API: перейдите по ссылке и включите API.

В качестве альтернативы можно использовать команду gcloud. Для получения информации о командах gcloud и их использовании обратитесь к документации .

Подводные камни и устранение неполадок

Синдром «Проекта-призрака»

Вы выполнили команду gcloud config set project , но в консоли отображается другой проект. Проверьте идентификатор проекта в выпадающем списке в левом верхнем углу!

Баррикада Биллинга

Вы активировали проект, но забыли указать платежный аккаунт. AlloyDB — высокопроизводительный движок; он не запустится, если «топливо» (платежный бак) пуст.

Задержка распространения API

Вы нажали «Включить API», но в командной строке по-прежнему отображается сообщение Service Not Enabled . Подождите 60 секунд. Облаку нужно время, чтобы активировать свои нейроны.

Квота Квагс

Если вы используете совершенно новую пробную учетную запись, вы можете столкнуться с региональной квотой на экземпляры AlloyDB. Если us-central1 не работает, попробуйте us-east1 .

«Скрытый» сервисный агент

Иногда агенту службы AlloyDB автоматически не предоставляется роль aiplatform.user . Если ваши SQL-запросы не могут взаимодействовать с Gemini в дальнейшем, обычно в этом причина.

3. Настройка базы данных

В основе нашего приложения лежит AlloyDB для PostgreSQL . Мы использовали его мощные векторные возможности и встроенный столбцовый механизм для генерации векторных представлений для более чем 50 000 записей SCM . Это позволяет проводить векторный анализ практически в реальном времени, что дает нашим агентам возможность выявлять аномалии в инвентаризации или логистические риски в огромных массивах данных за миллисекунды.

В этой лабораторной работе мы будем использовать AlloyDB в качестве базы данных для тестовых данных. Она использует кластеры для хранения всех ресурсов, таких как базы данных и журналы. Каждый кластер имеет основной экземпляр , который обеспечивает точку доступа к данным. Таблицы будут содержать сами данные.

Давайте создадим кластер AlloyDB, экземпляр и таблицу, куда будет загружен тестовый набор данных.

  1. Нажмите на кнопку или скопируйте ссылку ниже в браузер, где вы авторизованы в Google Cloud Console.

В качестве альтернативы вы можете перейти в терминал Cloud Shell из проекта, где вы активировали платежный аккаунт, клонировать репозиторий GitHub и перейти к проекту, используя приведенные ниже команды:

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

cd easy-alloydb-setup
  1. После завершения этого шага репозиторий будет клонирован в ваш локальный редактор CloudShell, и вы сможете запустить приведенную ниже команду, указав папку проекта (важно убедиться, что вы находитесь в каталоге проекта):
sh run.sh
  1. Теперь воспользуйтесь пользовательским интерфейсом (щелкните ссылку в терминале или щелкните ссылку «предварительный просмотр в веб-браузере» в терминале).
  2. Введите данные для идентификатора проекта, названия кластера и экземпляра, чтобы начать работу.
  3. Пока прокручиваются логи, выпейте кофе, а подробнее о том, как это всё происходит за кулисами, вы можете прочитать здесь.

Подводные камни и устранение неполадок

Проблема «терпения»

Кластеры баз данных — это ресурсоемкая инфраструктура. Если вы обновите страницу или завершите сессию Cloud Shell, потому что она «зависла», вы можете получить «фантомный» экземпляр, который будет частично выделен и его невозможно будет удалить без ручного вмешательства.

Региональное несоответствие

Если вы включили API в регионе us-central1 , но пытаетесь развернуть кластер в регионе asia-south1 , вы можете столкнуться с проблемами квот или задержками в предоставлении прав доступа к учетной записи службы. Используйте один регион для всей тестовой среды!

Скопления зомби

Если вы ранее использовали это же имя для кластера и не удалили его, скрипт может сообщить, что имя кластера уже существует. Имена кластеров должны быть уникальными в рамках одного проекта.

Таймаут облачной оболочки

Если ваш перерыв на кофе длится 30 минут, Cloud Shell может перейти в спящий режим и отключить процесс sh run.sh Поэтому оставьте вкладку активной!

4. Предоставление схемы

После запуска кластера и экземпляра AlloyDB перейдите в редактор SQL AlloyDB Studio, чтобы включить расширения AI и настроить схему.

1e3ac974b18a8113.png

Возможно, вам потребуется дождаться завершения создания экземпляра. После этого войдите в AlloyDB, используя учетные данные, которые вы создали при создании кластера. Для аутентификации в PostgreSQL используйте следующие данные:

  • Имя пользователя: " postgres "
  • База данных: " postgres "
  • Пароль: " alloydb " (или тот, который вы указали при создании учетной записи)

После успешной аутентификации в AlloyDB Studio команды SQL вводятся в редакторе. Вы можете добавить несколько окон редактора, используя значок плюса справа от последнего окна.

28cb9a8b6aa0789f.png

Команды для AlloyDB будут вводиться в окнах редактора, используя при необходимости параметры «Выполнить», «Форматировать» и «Очистить».

Включить расширения

Для создания этого приложения мы будем использовать расширения pgvector и google_ml_integration . Расширение pgvector позволяет хранить и искать векторные представления. Расширение google_ml_integration предоставляет функции, которые вы используете для доступа к конечным точкам прогнозирования Vertex AI и получения прогнозов в формате SQL. Включите эти расширения, выполнив следующие DDL-скрипты:

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

Предоставить разрешение

Выполните указанное ниже выражение, чтобы предоставить права на выполнение функции "embedding":

GRANT EXECUTE ON FUNCTION embedding TO postgres;

Предоставьте учетной записи службы AlloyDB роль пользователя Vertex AI.

В консоли Google Cloud IAM предоставьте учетной записи службы AlloyDB (которая выглядит следующим образом: service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) доступ к роли "Пользователь Vertex AI". В поле PROJECT_NUMBER будет указан номер вашего проекта.

В качестве альтернативы вы можете выполнить следующую команду в терминале 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"

Создайте таблицу

В AlloyDB Studio можно создать таблицу, используя приведенный ниже оператор DDL:

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
);

Столбец policy_embedding позволит хранить векторные значения некоторых текстовых полей.

Ввод данных

Выполните приведенный ниже набор SQL-запросов для массовой вставки записей в соответствующие таблицы:

  1. Встраивайте неструктурированные политики и генерируйте реальные эмбеддинги непосредственно в 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. Создайте более 200 реалистичных расписаний на 7 дней с помощью функции 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!

Сгенерировать векторные представления

Функция " embedding('text-embedding-005', '<<policytext>>') " автоматически обрабатывает данные в операторе INSERT в таблицу transit_policies.

Подводные камни и устранение неполадок

Цикл «Забвения паролей»

Если вы использовали настройку "в один клик" и не помните свой пароль, перейдите на страницу основной информации об экземпляре в консоли и нажмите "Изменить", чтобы сбросить пароль postgres .

Ошибка "Расширение не найдено"

Если CREATE EXTENSION завершается с ошибкой, это часто происходит потому, что экземпляр все еще находится в состоянии «Обслуживание» или «Обновление» после первоначального создания. Проверьте, завершен ли этап создания экземпляра, и при необходимости подождите несколько секунд.

Проблемы распространения IAM

Вы выполнили команду gcloud IAM, но CALL SQL по-прежнему завершается ошибкой доступа. Изменения в IAM могут потребовать некоторого времени для распространения по сети Google. Сделайте глубокий вдох.*** КРИТИЧЕСКАЯ СИТУАЦИЯ:

  1. Иногда ваша учетная запись службы AlloyDB может отличаться от существующего формата, который мы использовали на этапе настройки разрешений. Поэтому, чтобы на 100% убедиться, что учетная запись службы AlloyDB имеет роль пользователя Vertex AI : перейдите на страницу кластеров AlloyDB в консоли Google Cloud. Щелкните свой кластер, и на вкладке «Обзор» найдите поле с названием « Учетная запись службы» .
    Скопируйте значение, затем перейдите в IAM и добавьте роль пользователя Vertex AI.
  2. Кроме того, если вы пропустили шаг «Включить API» в разделе «Перед началом работы», у вас возникнут проблемы с доступом к эмбеддингам из AlloyDB.

Несоответствие размерности вектора

В таблице transit_policies столбец policy_embedding имеет значение VECTOR(768) . Если вы позже попытаетесь использовать другую модель (например, модель с 1536 размерами), ваши вставки приведут к сбою. Используйте text-embedding-005 .

Опечатка в идентификаторе проекта

Если в вызове функции create_model вы оставите скобки « » или неправильно введете идентификатор проекта, регистрация модели будет выглядеть успешной, но завершится ошибкой при первом же фактическом запросе. Дважды проверьте свою строку!

5. Подготовка инструментов и ящика для инструментов

MCP Toolbox for Databases — это сервер MCP с открытым исходным кодом для баз данных. Он позволяет разрабатывать инструменты проще, быстрее и безопаснее, обрабатывая такие сложные процессы, как пулы соединений, аутентификация и многое другое . Toolbox помогает создавать инструменты Gen AI, которые позволяют вашим агентам получать доступ к данным в вашей базе данных.

В качестве "дирижера" мы используем Model Context Protocol (MCP) Toolbox for Databases . Он выступает в роли стандартизированного промежуточного программного обеспечения между нашими агентами и AlloyDB. Определив конфигурацию tools.yaml , Toolbox автоматически предоставляет доступ к сложным операциям с базой данных в виде простых, исполняемых инструментов, таких как find-bus-schedules and routes или query-schedules for specific routes , и выполняет автономные действия, например, book-ticket . Это устраняет необходимость в ручном пуле соединений или шаблонном SQL-коде в логике агента.

Установка сервера Toolbox

В терминале Cloud Shell создайте папку для сохранения нового YAML-файла инструментов и исполняемого файла панели инструментов:

mkdir cymbal-bus-toolbox

cd cymbal-bus-toolbox

В новой папке выполните следующий набор команд:

# 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

Далее создайте файл tools.yaml внутри этой новой папки, перейдя в редактор Cloud Shell и скопировав содержимое этого файла репозитория в файл 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;

Примечание:

  1. В файле tools.yaml не забудьте добавить ipType: "private" в конфигурацию источника alloydb.
  2. Также не забудьте указать URL-адрес службы MCP Toolbox в параметре clientId для конфигурации authServices. Возможно, вы получите ссылку только после первоначального развертывания, поэтому да, вам придется выполнить шаги развертывания дважды, чтобы убедиться, что сценарий использования аутентифицированных инструментов работает.
  3. Приведенные ниже варианты локального тестирования Toolbox не будут работать, если ваше соединение с AlloyDB установлено как частное; для локального тестирования вам необходимо сделать его публичным или использовать прокси-сервер. Но не беспокойтесь об этом. В нашем случае мы развернем его непосредственно в Cloud Run, а затем протестируем.

Для тестирования файла tools.yaml на локальном сервере:

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

Также вы можете протестировать это в пользовательском интерфейсе:

./toolbox --ui

Давайте развернем его в Cloud Run следующим образом.

Развертывание в облаке

  1. Установите переменную среды PROJECT_ID:
export PROJECT_ID="my-project-id"
  1. Инициализация интерфейса командной строки gcloud:
gcloud init
gcloud config set project $PROJECT_ID
  1. Для корректной работы необходимо включить следующие API:
gcloud services enable run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       iam.googleapis.com \
                       secretmanager.googleapis.com
  1. Если у вас его еще нет, создайте учетную запись для бэкэнд-сервиса:
gcloud iam service-accounts create toolbox-identity
  1. Предоставьте разрешение на использование менеджера секретов:
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/secretmanager.secretAccessor
  1. Предоставьте учетной записи службы дополнительные разрешения, специфичные для нашего источника AlloyDB (roles/alloydb.client и 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. Загрузите файл tools.yaml в качестве секретного ключа:
gcloud secrets create tools-cymbal-transit --data-file=tools.yaml
  1. Если у вас уже есть секретный ключ и вы хотите обновить его версию, выполните следующие действия:
gcloud secrets versions add tools-cymbal-transit --data-file=tools.yaml
  1. Установите переменную среды, указывающую на образ контейнера, который вы хотите использовать для Cloud Run:
export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
  1. Разверните Toolbox в Cloud Run, используя следующую команду:

Если вы включили публичный доступ к своему экземпляру AlloyDB , выполните следующую команду для развертывания в 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

Если вы используете сеть VPC , воспользуйтесь приведенной ниже командой:

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

Примечание: После развертывания перейдите к списку служб Cloud Run и убедитесь, что на вкладке «Безопасность» этой службы выбран параметр «Разрешить публичный доступ».

6. Настройка приложения агента

Клонируйте этот репозиторий в свой проект, и давайте разберемся.

Репозиторий на GitHub

Чтобы клонировать этот проект, в терминале Cloud Shell (в корневом каталоге или в любом другом месте, где вы хотите его создать) выполните следующую команду:

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

Приведённая выше команда фактически клонирует весь репозиторий mcp-toolbox-sdk-java. Нам нужен только пример проекта из него. Поэтому перейдите в корневой каталог проекта внутри репозитория:

cd mcp-toolbox-sdk-java/demo-applications/cymbal-transit
  1. Это должно создать проект, и вы можете проверить это в редакторе Cloud Shell.

a494664032904c77.png

  1. Откройте файл CymbalTransitController.java и установите переменные среды:
  2. GCP_PROJECT_ID
  3. GCP_REGION
  4. GEMINI_MODEL_NAME
  5. MCP_TOOLBOX_URL

В качестве альтернативы (только в целях разработки) вы также можете заменить соответствующие заполнители резервных значений.

7. Разбор кода

CymbalTransitController служит точкой входа для нашего сервиса Cloud Run. Он управляет потоком диалога и гарантирует, что агент имеет доступ к текущему запросу пользователя.

Реализация основана на многоуровневой архитектуре, которая разделяет оркестрацию ИИ, взаимодействие инструментов и низкоуровневую коммуникацию MCP.

1. Настройка агента ИИ ( AgentConfiguration )

Этот класс использует @Configuration Spring для инициализации компонентов ИИ. Он инициализирует объект `VertexAiGeminiChatModel` и привязывает его к нашему интерфейсу агента.

@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();
}

Значение: AiServices связывает интерфейс с LLM. MessageWindowChatMemory гарантирует, что агент запоминает пользовательские предпочтения (например, упомянутую ранее переноску для животных) для до 20 сообщений в рамках одной сессии.

2. Интерфейс ИИ-агента ( TransitAgent )

Аннотация @SystemMessage определяет «Персону» и операционные ограничения, в частности, стратегию маршрутизации .

@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);

Значение: Эта стратегия минимизирует задержку. Получая сначала общие данные, агент может отвечать на общие вопросы маршрутизации, используя свой внутренний контекст, без лишних обращений к бэкэнду.

3. Мост Toolbox ( TransitAgentTools )

Этот сервис выступает в роли «рук» агента, преобразуя вызовы инструмента LangChain4j в логику выполнения.

@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();
}

Синхронное выполнение: Хотя вызовы MCP являются асинхронными (возвращая CompletableFuture ), LLM требует результата, прежде чем сможет продолжить свой «мыслительный» процесс. Мы используем .join() для предоставления синхронных результатов обратно агенту.

4. Сервис MCP Toolbox ( McpToolboxService )

Это коммуникационный слой, использующий Java SDK из пакета MCP Toolbox для взаимодействия с бэкэндом 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(", ", "[", "]"));
    });
}

Значение: McpToolboxClient берет на себя основную работу по обмену данными в формате JSON-RPC. Метод bookTicket наглядно демонстрирует возможности SDK по динамической привязке сложных параметров.

5. REST-контроллер ( TransitAgentController )

Конечная точка доступа значительно упрощена, поскольку LangChain4j управляет состоянием и логикой.

@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);
}

Значение: Сопоставляя идентификатор HttpSession с аннотацией @MemoryId , мы гарантируем, что планы поездок разных пользователей не будут перепутаны, при этом сохраняя код контроллера чистым и читаемым.

8. MCP Toolbox: Significance и Java SDK

Что такое MCP?

Рассматривайте протокол контекста модели (MCP) как универсальный транслятор для ИИ. Созданный для стандартизации способов подключения моделей ИИ к внешним инструментам и наборам данных, MCP заменяет пользовательские, разрозненные скрипты интеграции безопасным универсальным протоколом. Независимо от того, нужно ли вашему агенту выполнить транзакционный SQL-запрос, выполнить поиск по тысячам документов с политиками или запустить REST API, MCP предоставляет единый, унифицированный интерфейс.

MCP Toolbox для баз данных

Инженерные команды все чаще выходят за рамки простых чат-ботов и создают агентные системы, которые напрямую взаимодействуют с критически важными базами данных. Однако разработка таких корпоративных агентов часто сопряжена с трудностями интеграции, такими как написание пользовательского связующего кода, ненадежные API и сложная логика работы с базами данных.

Чтобы заменить эти жестко запрограммированные узкие места на безопасную, унифицированную плоскость управления, мы рады объявить о выпуске Java SDK для инструментария Model Context Protocol (MCP) для баз данных. Этот релиз предоставляет первоклассную, типобезопасную оркестрацию агентов для самой распространенной в мире корпоративной экосистемы. Зрелая архитектура Java специально разработана для этих жестких требований, обеспечивая высокую параллельность, строгую транзакционную целостность и надежное управление состоянием, необходимые для безопасного масштабирования критически важных агентов ИИ в производственной среде.

Почему именно Java SDK?

Пакет MCP Toolbox Java SDK позволяет Java-разработчикам:

  1. Использование инструментов: Подключитесь к серверу MCP (например, к MCP Toolbox для AlloyDB) и автоматически преобразуйте его возможности в методы Java, которые понимает LangChain4j.
  2. Типобезопасность: Используйте строгую типизацию Java для параметров инструментов, что позволит уменьшить количество ошибок типа «галлюцинации» во время выполнения при вызове инструментов.
  3. Готовность к использованию в корпоративной среде: Легкая интеграция со Spring Boot, Quarkus, Micronaut и др.
  4. Подключайтесь без усилий: избегайте написания шаблонного кода для JSON-RPC.
  5. Стандартизация аутентификации: встроенная поддержка токенов Google Cloud OIDC обеспечивает безопасное выполнение инструментов.

и многое другое .

Зависимости: pom.xml Конфигурация

Добавьте следующую зависимость в свой проект Maven, чтобы включить последнюю версию Java SDK MCP Toolbox:

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

Добавьте следующую зависимость в свой проект Maven, чтобы включить артефакт LangChain4j:

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

Вот и всё!!! Мы успешно клонировали проект и подробно рассмотрели работу агента, MCP Toolbox Java SDK и контекст.

9. Запуск локально

Для тестирования агента на вашем компьютере необходимо указать путь к развернутому серверу MCP Toolbox.

  1. Установите переменные среды:
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. Запуск с помощью Maven:
mvn compile

mvn spring-boot:run

Это должно запустить ваш агент локально, и вы сможете его протестировать.

10. Давайте развернем его в Cloud Run.

Разверните проект в Cloud Run, выполнив следующую команду в терминале Cloud Shell, куда клонирован проект, и убедитесь, что вы находитесь в корневой папке проекта .

Если вы не находитесь в корневой папке нашего текущего проекта, выполните следующую команду в терминале Cloud Shell:

cd cymbal-transit

Если вы уже находитесь в корневой директории cymbal-transit, выполните следующую команду, чтобы развернуть приложение непосредственно в 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

Замените значения для заполнителей <<YOUR_PROJECT>> and <<YOUR_MCP_TOOLBOX_URL>>

После завершения выполнения команды она выведет URL-адрес сервиса. Скопируйте его.

Предоставьте учетной записи службы Cloud Run роль клиента AlloyDB. Это позволит вашему бессерверному приложению безопасно подключаться к базе данных через туннель.

Выполните следующую команду в терминале 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"

Примечание: После развертывания перейдите к списку служб Cloud Run и убедитесь, что на вкладке «Безопасность» этой службы выбран параметр «Разрешить публичный доступ».

Теперь воспользуйтесь URL-адресом сервиса (конечной точкой Cloud Run, которую вы скопировали ранее) и протестируйте приложение.

Примечание: Если вы столкнулись с проблемой в работе сервиса, и в качестве причины указана нехватка памяти, попробуйте увеличить лимит выделенной памяти до 1 ГБ для проверки.

11. Демонстрация

Спросите агента: «Мне нужно завтра утром добраться из Нью-Йорка в Бостон. Могу ли я взять с собой своего золотистого ретривера?» Обратите внимание на то, как агент:

  1. Проверяет правила выгула крупных собак.
  2. Находит конкретные расписания.
  3. Выводит сводную информацию о самом быстром маршруте с указанием идентификатора поездки.
  4. Также, если вы выполните этот запрос, будет создан тикет.

aa0408a81074d0fc.png

12. Уборка

После завершения этой лабораторной работы не забудьте удалить кластер и экземпляр AlloyDB.

Это должно привести к очистке кластера вместе с его экземплярами.

13. Поздравляем!

Вы успешно создали сложный транзитный агент на основе Java. Используя LangChain4j для оркестрации и Java SDK MCP Toolbox для подключения к данным, вы создали систему, способную взаимодействовать с агентами, инструментами и источниками данных. Если вы хотите начать оркестрацию ваших агентных приложений с помощью MCP Toolbox for Databases, работая с несколькими базами данных и даже на разных платформах, начните работу с Java SDK уже сегодня! Вот блог с анонсом запуска, где представлена ​​более подробная информация о библиотеке . Если вы хотите создавать больше подобных приложений на практике, бесплатно, в удобном для вас темпе и под руководством инструктора, зарегистрируйтесь на Code Vipassana по адресу https://codevipassana.dev !!!