Создавайте мощные, отслеживающие состояние, E2E приложения-агенты ИИ на Java с помощью ADK, AlloyDB и Gemini!!

1. Обзор

В различных отраслях контекстный поиск является критически важной функцией, составляющей основу их приложений. Технология дополненной генерации поиска (Retrieval Augmented Generation, RAG) уже довольно давно является ключевым двигателем этой важной технологической эволюции благодаря своим механизмам поиска на основе генеративного ИИ. Генеративные модели с их большими контекстными окнами и впечатляющим качеством выходных данных трансформируют ИИ. RAG предоставляет систематический способ внедрения контекста в приложения и агентов ИИ, основываясь на структурированных базах данных или информации из различных источников. Эти контекстные данные имеют решающее значение для ясности истины и точности выходных данных, но насколько точны эти результаты? Зависит ли ваш бизнес в значительной степени от точности этих контекстных совпадений и релевантности? Тогда этот проект вас заинтересует!

Теперь представьте, что мы можем использовать возможности генеративных моделей для создания интерактивных агентов, способных принимать автономные решения, опираясь на такую ​​контекстно-критичную информацию и основываясь на истине; именно это мы и собираемся создать сегодня. Мы собираемся разработать комплексное приложение для ИИ-агента, используя Agent Development Kit на базе передового RAG в AlloyDB, для приложения анализа патентов.

Программа Patent Analysis Agent помогает пользователю находить патенты, имеющие отношение к его поисковому запросу, и по запросу предоставляет четкое и краткое объяснение, а также, при необходимости, дополнительные сведения по выбранному патенту. Готовы узнать, как это работает? Давайте начнем!

Цель

Цель проста. Предоставить пользователю возможность искать патенты на основе текстового описания, а затем получать подробное объяснение конкретного патента из результатов поиска, и все это с помощью агента искусственного интеллекта, созданного на основе Java ADK, AlloyDB, Vector Search (с расширенными индексами), Gemini, и всего приложения, развернутого в бессерверной среде Cloud Run.

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

В рамках этой лабораторной работы вы:

  1. Создайте экземпляр AlloyDB и загрузите данные из общедоступного набора данных о патентах.
  2. Внедрите расширенный векторный поиск в AlloyDB, используя функции оценки ScaNN и Recall.
  3. Создайте агента с помощью Java ADK.
  4. Реализуйте серверную логику работы с базой данных на Java в бессерверных облачных функциях.
  5. Разверните и протестируйте агента в Cloud Run.

Следующая диаграмма иллюстрирует поток данных и этапы реализации.

c22563ace65a6930.png

High level diagram representing the flow of the Patent Search Agent with AlloyDB & ADK

Требования

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

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

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

  1. В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
  2. Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта .
  3. Вы будете использовать 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. Вы можете использовать команду gcloud в терминале Cloud Shell:
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com

Альтернативой команде gcloud является поиск каждого продукта в консоли или использование этой ссылки .

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

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

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

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

Создайте кластер и экземпляр.

  1. Перейдите на страницу AlloyDB в Cloud Console. Большинство страниц в Cloud Console легко найти, используя строку поиска консоли.
  2. На этой странице выберите пункт «СОЗДАТЬ КЛАСТЕР» :

f76ff480c8c889aa.png

  1. Вы увидите экран, похожий на тот, что показан ниже. Создайте кластер и экземпляр со следующими значениями (убедитесь, что значения совпадают, если вы клонируете код приложения из репозитория):
  • идентификатор кластера : " vector-cluster "
  • пароль : " alloydb "
  • Рекомендуемая последняя версия PostgreSQL: 15.
  • Регион : " us-central1 "
  • Сетевые настройки : " default "

538dba58908162fb.png

  1. При выборе сети по умолчанию вы увидите экран, похожий на тот, что показан ниже.

Выберите «НАСТРОЙКА СОЕДИНЕНИЯ» .
7939bbb6802a91bf.png

  1. Затем выберите « Использовать автоматически выделенный диапазон IP-адресов » и продолжите. После проверки информации выберите «СОЗДАТЬ СОЕДИНЕНИЕ». 768ff5210e79676f.png
  2. После настройки сети вы можете продолжить создание кластера. Нажмите кнопку «СОЗДАТЬ КЛАСТЕР» , чтобы завершить настройку кластера, как показано ниже:

e06623e55195e16e.png

Обязательно измените идентификатор экземпляра (который можно найти во время настройки кластера/экземпляра) на

vector-instance . Если вы не можете его изменить, не забудьте использовать свой идентификатор экземпляра во всех последующих ссылках.

Обратите внимание, что создание кластера займет около 10 минут. После успешного завершения процесса вы увидите экран с обзором только что созданного кластера.

4. Ввод данных

Теперь пришло время добавить таблицу с данными о магазине. Перейдите в AlloyDB, выберите основной кластер, а затем AlloyDB Studio:

847e35f1bf8a8bd8.png

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

  • Имя пользователя: " postgres "
  • База данных: " postgres "
  • Пароль: " alloydb "

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

91a86d9469d499c4.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;

Чтобы проверить, какие расширения включены в вашей базе данных, выполните следующую SQL-команду:

select extname, extversion from pg_extension;

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

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

CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;

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

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

Выполните указанное ниже выражение, чтобы предоставить права на выполнение функции "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"

Загрузите данные о патентах в базу данных.

В качестве набора данных мы будем использовать общедоступные наборы данных патентов Google в BigQuery. Для выполнения запросов мы будем использовать AlloyDB Studio. Данные загружаются в insert scripts sql находится в этом репозитории , и мы запустим его для загрузки данных о патентах.

  1. В консоли Google Cloud откройте страницу AlloyDB .
  2. Выберите созданный кластер и щелкните по его экземпляру.
  3. В меню навигации AlloyDB нажмите AlloyDB Studio . Войдите в систему, используя свои учетные данные.
  4. Откройте новую вкладку, нажав на значок «Новая вкладка» справа.
  5. Скопируйте и выполните запросы insert из файлов insert_scripts1.sql , insert_script2.sql , insert_scripts3.sql , insert_scripts4.sql по одному. Для быстрой демонстрации этого варианта использования можно скопировать от 10 до 50 запросов на вставку.

Для выполнения запроса нажмите кнопку «Выполнить» . Результаты запроса отобразятся в таблице «Результаты» .

5. Создайте векторные представления данных о патентах.

Для начала протестируем функцию встраивания, выполнив следующий пример запроса:

SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');

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

25a1d7ef0e49e91e.png

Обновите поле Abstract_Embeddings Vector.

Приведенный ниже DML-код следует использовать для обновления аннотаций патентов в таблице соответствующими векторными представлениями, если для аннотаций необходимо сгенерировать эти представления. Однако в нашем случае операторы вставки уже содержат эти векторные представления для каждой аннотации, поэтому вам не нужно вызывать метод embeddings().

UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);

6. Выполните векторный поиск.

Теперь, когда таблица, данные и векторные представления готовы, давайте выполним векторный поиск в реальном времени для поискового запроса пользователя. Вы можете проверить это, выполнив запрос ниже:

SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

В этом запросе,

  1. Поисковый запрос пользователя: "Анализ настроений".
  2. Мы преобразуем его в векторные представления в методе embedding(), используя модель: text-embedding-005.
  3. Символ "<=>" обозначает использование метода расстояния косинусного сходства.
  4. Мы преобразуем результат метода встраивания в векторный тип, чтобы обеспечить его совместимость с векторами, хранящимися в базе данных.
  5. LIMIT 10 означает, что мы выбираем 10 наиболее близких совпадений с поисковым текстом.

AlloyDB выводит векторный поиск RAG на новый уровень:

Представлено немало нововведений. Два из них, ориентированные на разработчиков, следующие:

  1. Встроенная фильтрация
  2. Оценщик отзыва

Встроенная фильтрация

Раньше разработчикам приходилось выполнять векторный поиск и заниматься фильтрацией и полнотой запросов. Оптимизатор запросов AlloyDB сам выбирает способ выполнения запроса с фильтрами. Встроенная фильтрация — это новая техника оптимизации запросов, которая позволяет оптимизатору запросов AlloyDB оценивать как условия фильтрации метаданных, так и векторный поиск, используя как векторные индексы, так и индексы на столбцах метаданных. Это повысило производительность полноты запросов, позволяя разработчикам использовать все преимущества AlloyDB «из коробки».

Встроенная фильтрация лучше всего подходит для случаев со средней избирательностью. При поиске по векторному индексу AlloyDB вычисляет расстояния только для тех векторов, которые соответствуют условиям фильтрации метаданных (ваши функциональные фильтры в запросе, обычно обрабатываемые в предложении WHERE). Это значительно повышает производительность таких запросов, дополняя преимущества пост-фильтрации или пре-фильтрации .

  1. Установите или обновите расширение pgvector.
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';

Если расширение pgvector уже установлено, обновите его до версии 0.8.0.google-3 или более поздней, чтобы получить возможности оценки результатов поиска.

ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';

Этот шаг необходимо выполнить только в том случае, если расширение вашего вектора <0.8.0.google-3.

Важное замечание: если количество строк меньше 100, вам вообще не нужно создавать индекс ScaNN, так как он не будет применяться к меньшему количеству строк. В этом случае пропустите следующие шаги.

  1. Для создания индексов ScaNN установите расширение alloydb_scann.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. Сначала выполните запрос векторного поиска без индекса и без включенного встроенного фильтра:
SELECT id || ' - ' || title as title FROM patents_data 
WHERE num_claims >= 15 
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

Результат должен быть примерно таким:

6989de0fc3f0f753.png

  1. Запустите на нем Explain Analyze (без индекса и встроенной фильтрации).

908dcf87c7f00ed4.png

Время выполнения составляет 2,4 мс.

  1. Давайте создадим обычный индекс по полю num_claims, чтобы можно было фильтровать данные по нему:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
  1. Давайте создадим индекс ScaNN для нашего приложения поиска патентов. Выполните следующие действия в AlloyDB Studio:
CREATE INDEX patent_index ON patents_data 
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);

Важное замечание: (num_leaves=32) применяется ко всему нашему набору данных, содержащему более 1000 строк. Если количество строк меньше 100, вам не нужно создавать индекс, так как он не будет применяться для меньшего количества строк.

  1. Включите встроенную фильтрацию для индекса ScaNN:
SET scann.enable_inline_filtering = on
  1. Теперь выполним тот же запрос, добавив фильтр и векторный поиск:
SELECT id || ' - ' || title as title FROM patents_data 
WHERE num_claims >= 15 
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

aa54cba2b2ada2cb.png

Как видите, время выполнения значительно сократилось для того же алгоритма векторного поиска. Это стало возможным благодаря встроенной фильтрации с использованием индекса ScaNN в алгоритме векторного поиска!

Далее оценим полноту (recall) для этого векторного поиска с использованием ScaNN.

Оценщик отзыва

Показатель полноты (recall) в поиске по сходству — это процент релевантных результатов, полученных в ходе поиска, то есть количество истинных положительных результатов. Это наиболее распространенная метрика, используемая для измерения качества поиска. Одна из причин потери полноты связана с разницей между приблизительным поиском ближайшего соседа (aNN) и поиском k (точных) ближайших соседей (kNN). Векторные индексы, такие как ScaNN в AlloyDB, реализуют алгоритмы aNN, позволяя ускорить векторный поиск на больших наборах данных за счет небольшого снижения полноты. Теперь AlloyDB предоставляет возможность измерять этот компромисс непосредственно в базе данных для отдельных запросов и гарантировать его стабильность во времени. Вы можете обновлять параметры запроса и индекса в ответ на эту информацию для достижения лучших результатов и производительности.

Для определения полноты векторного запроса по векторному индексу для заданной конфигурации можно использовать функцию evaluate_query_recall . Эта функция позволяет настраивать параметры для достижения желаемых результатов полноты векторного запроса. Полнота — это метрика, используемая для оценки качества поиска, и определяется как процент возвращаемых результатов, которые объективно наиболее близки к векторам запроса. Функция evaluate_query_recall включена по умолчанию.

Важное примечание:

Если на следующих шагах вы сталкиваетесь с ошибкой "Доступ запрещен" при работе с индексом HNSW, пропустите пока весь раздел оценки восстановления. Возможно, это связано с ограничениями доступа, поскольку на момент написания этого руководства это было только что выпущено.

  1. Установите флаг Enable Index Scan для индексов ScaNN и HNSW:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
  1. Выполните следующий запрос в AlloyDB Studio:
SELECT
  *
FROM
  evaluate_query_recall($$
  SELECT
    id || ' - ' || title AS title,
    abstract
  FROM
    patents_data
    where num_claims >= 15
  ORDER BY
    abstract_embeddings <=> embedding('text-embedding-005',
      'sentiment analysis')::vector
  LIMIT 25 $$,
    '{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
    ARRAY['scann']);

Функция evaluate_query_recall принимает запрос в качестве параметра и возвращает его значение recall. В качестве входного запроса для функции я использую тот же запрос, что и для проверки производительности. В качестве метода индексации я добавил SCaNN. Дополнительные параметры см. в документации .

Для данного запроса векторного поиска мы использовали показатель полноты:

c98f38fbe6a0b6c5.png

Я вижу, что показатель полноты (RECALL) составляет 70%. Теперь я могу использовать эту информацию для изменения параметров индекса, методов и параметров запроса, чтобы улучшить показатель полноты для этого векторного поиска!

Я изменил количество строк в результирующем наборе до 7 (с 10 ранее) и вижу незначительное улучшение показателя RECALL, а именно 86%.

c12f7b92b8481ceb.png

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

Итак, пора развертывать логику базы данных и переходить к агенту!!!

7. Перенесите логику работы с базой данных в веб-среду без использования серверов.

Готовы перенести это приложение в веб-браузер? Следуйте инструкциям ниже:

  1. Чтобы создать новую функцию Cloud Run Function, перейдите в раздел Cloud Run Functions в консоли Google Cloud, нажав кнопку «Написать функцию», или воспользуйтесь ссылкой: https://console.cloud.google.com/run/create?deploymentType=function .
  2. Выберите опцию «Использовать встроенный редактор для создания функции» и начните настройку. Укажите имя службы « patent-search », регион « us-central1 » и среду выполнения «Java 17» . Установите аутентификацию в значение « Разрешить неаутентифицированные вызовы ».
  3. В разделе «Контейнеры, тома, сети, безопасность» выполните следующие действия, не упуская ни одной детали:

Перейдите на вкладку «Сеть»:

828cd861864d99ea.png

Выберите « Подключиться к VPC для исходящего трафика », а затем выберите « Использовать коннекторы Serverless VPC Access ».

В раскрывающемся списке «Сеть», в настройках, щелкните раскрывающийся список «Сеть» и выберите параметр « Добавить новый коннектор VPC » (если вы еще не настроили коннектор по умолчанию ), затем следуйте инструкциям в появившемся диалоговом окне:

6559ccfd10e597f2.png

Укажите имя для VPC-коннектора и убедитесь, что регион совпадает с регионом вашего экземпляра. Оставьте значение «Сеть» по умолчанию и установите подсеть как «Пользовательский диапазон IP-адресов» с диапазоном IP-адресов 10.8.0.0 или аналогичным доступным значением.

Разверните раздел «ПОКАЗАТЬ НАСТРОЙКИ МАСШТАБИРОВАНИЯ» и убедитесь, что параметры конфигурации установлены точно следующим образом:

199b0ccd80215004.png

Нажмите кнопку СОЗДАТЬ , и этот соединитель должен появиться в списке настроек исходящего трафика.

Выберите только что созданный соединитель.

Выберите вариант, при котором весь трафик будет направляться через этот VPC-коннектор.

Нажмите ДАЛЕЕ , а затем РАЗВЕРНУТЬ .

  1. По умолчанию точка входа будет установлена ​​на " gcfv2.HelloHttpFunction ". Замените код-заполнитель в файлах HelloHttpFunction.java и pom.xml вашей функции Cloud Run кодом из файлов " PatentSearch.java " и " pom.xml " соответственно. Измените имя файла класса на PatentSearch.java.
  2. Не забудьте заменить заполнитель ************* и учетные данные для подключения к AlloyDB на свои значения в Java-файле. Учетные данные AlloyDB — это те, которые мы использовали в начале этого практического занятия. Если вы использовали другие значения, пожалуйста, измените их в Java-файле.
  3. Нажмите «Развернуть» .
  4. После развертывания обновленной облачной функции вы должны увидеть сгенерированную конечную точку. Скопируйте ее и замените в следующей команде:
PROJECT_ID=$(gcloud config get-value project)

curl -X POST <<YOUR_ENDPOINT>> \
  -H 'Content-Type: application/json' \
  -d '{"search":"Sentiment Analysis"}'

Вот и всё! Выполнить расширенный контекстный векторный поиск сходства с использованием модели Embeddings на данных AlloyDB очень просто.

8. Давайте создадим агента с помощью Java ADK.

Для начала давайте создадим Java-проект в редакторе.

  1. Перейдите в терминал Cloud Shell.

https://shell.cloud.google.com/?fromcloudshell=true&show=ide%2Cterminal

  1. Подтвердите авторизацию при появлении запроса.
  2. Чтобы переключиться в редактор Cloud Shell, щелкните значок редактора в верхней части консоли Cloud Shell.

f913b886324e5196.png

  1. В консоли Cloud Shell Editor на главной странице создайте новую папку и назовите её "adk-agents".

В корневом каталоге вашей облачной оболочки нажмите кнопку «Создать новую папку», как показано ниже:

94c9804697614a94.png

Назовите его "adk-agents":

37445dc1fe08f74c.png

  1. Создайте следующую структуру папок и пустые файлы с соответствующими именами файлов в указанной ниже структуре:
adk-agents/
 └—— pom.xml
 └—— src/ 
     └—— main/
         └—— java/
             └—— agents/
                 └—— App.java
  1. Откройте репозиторий GitHub в отдельной вкладке и скопируйте исходный код файлов App.java и pom.xml.
  2. Если вы открыли редактор в новой вкладке, используя значок «Открыть в новой вкладке» в правом верхнем углу, то терминал будет открыт внизу страницы. Вы можете одновременно открыть редактор и терминал, что позволит вам работать свободно.
  3. После клонирования вернитесь в консоль редактора Cloud Shell.
  4. Поскольку мы уже создали функцию Cloud Run, вам не нужно копировать файлы функции Cloud Run из папки репозитория .

Начало работы с ADK Java SDK

Это довольно просто. В первую очередь вам нужно убедиться, что на этапе клонирования учтены следующие моменты:

  1. Добавить зависимости:

Включите артефакты google-adk и google-adk-dev (для веб-интерфейса) в ваш pom.xml. Если вы скопировали исходный код из репозитория, они уже включены в файлы, вам не нужно их добавлять. Вам просто нужно внести изменения в конечную точку Cloud Run Function, чтобы она соответствовала развернутой вами конечной точке. Это описано в следующих шагах этого раздела.

<!-- The ADK core dependency -->
        <dependency>
            <groupId>com.google.adk</groupId>
            <artifactId>google-adk</artifactId>
            <version>0.1.0</version>
        </dependency>
        <!-- The ADK dev web UI to debug your agent -->
        <dependency>
            <groupId>com.google.adk</groupId>
            <artifactId>google-adk-dev</artifactId>
            <version>0.1.0</version>
        </dependency>

Обязательно укажите ссылку на файл pom.xml из исходного репозитория, поскольку для корректной работы приложения необходимы и другие зависимости и конфигурации.

  1. Настройте свой проект:

Убедитесь, что версия Java (рекомендуется 17+) и настройки компилятора Maven правильно указаны в вашем файле pom.xml. Вы можете настроить свой проект в соответствии со следующей структурой:

adk-agents/
 └—— pom.xml
 └—— src/ 
     └—— main/
         └—— java/
             └—— agents/
                 └—— App.java
  1. Определение агента и его инструментов (App.java):

Именно здесь проявляется волшебство ADK Java SDK. Мы определяем нашего агента, его возможности (инструкции) и инструменты, которые он может использовать.

Упрощенную версию нескольких фрагментов кода основного класса агента можно найти здесь. Полный проект доступен в репозитории проекта здесь .

// App.java (Simplified Snippets)
package agents;

import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.InvocationContext;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
// ... other imports

public class App {

    static FunctionTool searchTool = FunctionTool.create(App.class, "getPatents");
    static FunctionTool explainTool = FunctionTool.create(App.class, "explainPatent");

    public static BaseAgent ROOT_AGENT = initAgent();

    public static BaseAgent initAgent() {
        return LlmAgent.builder()
            .name("patent-search-agent")
            .description("Patent Search agent")
            .model("gemini-2.0-flash-001") // Specify your desired Gemini model
            .instruction(
                """
                You are a helpful patent search assistant capable of 2 things:
                // ... complete instructions ...
                """)
            .tools(searchTool, explainTool)
            .outputKey("patents") // Key to store tool output in session state
            .build();
    }

    // --- Tool: Get Patents ---
    public static Map<String, String> getPatents(
        @Schema(name="searchText",description = "The search text for which the user wants to find matching patents")
        String searchText) {
        try {
            String patentsJson = vectorSearch(searchText); // Calls our Cloud Run Function
            return Map.of("status", "success", "report", patentsJson);
        } catch (Exception e) {
            // Log error
            return Map.of("status", "error", "report", "Error fetching patents.");
        }
    }

    // --- Tool: Explain Patent (Leveraging InvocationContext) ---
    public static Map<String, String> explainPatent(
        @Schema(name="patentId",description = "The patent id for which the user wants to get more explanation for, from the database") 
    String patentId, 
    @Schema(name="ctx",description = "The list of patent abstracts from the database from which the user can pick the one to get more explanation for") 
    InvocationContext ctx) { // Note the InvocationContext
        try {
            // Retrieve previous patent search results from session state
            String previousResults = (String) ctx.session().state().get("patents");
            if (previousResults != null && !previousResults.isEmpty()) {
// Logic to find the specific patent abstract from 'previousResults' by 'patentId'
                String[] patentEntries = previousResults.split("\n\n\n\n"); 
                for (String entry : patentEntries) {
                    if (entry.contains(patentId)) { // Simplified check
       // The agent will then use its instructions to summarize this 'report'
                        return Map.of("status", "success", "report", entry);
                    }
                }
            }
            return Map.of("status", "error", "report", "Patent ID not found in previous search.");
        } catch (Exception e) {
            // Log error
            return Map.of("status", "error", "report", "Error explaining patent.");
        }
    }

    public static void main(String[] args) throws Exception {
        InMemoryRunner runner = new InMemoryRunner(ROOT_AGENT);
        // ... (Session creation and main input loop - shown in your source)
    }
}

Основные компоненты Java-кода ADK выделены:

  1. LlmAgent.builder(): Fluent API для настройки вашего агента.
  2. .instruction(...): Предоставляет основные подсказки и рекомендации для LLM, включая информацию о том, когда следует использовать тот или иной инструмент.
  3. FunctionTool.create(App.class, "methodName"): Легко регистрирует ваши Java-методы в качестве инструментов, которые может вызывать агент. Строка с именем метода должна соответствовать фактическому открытому статическому методу.
  4. @Schema(description = ...): Аннотирует параметры инструмента, помогая LLM понять, какие входные данные ожидает каждый инструмент. Это описание имеет решающее значение для точного выбора инструмента и заполнения параметров.
  5. InvocationContext ctx: Автоматически передается методам инструмента, предоставляя доступ к состоянию сессии (ctx.session().state()), информации о пользователе и многому другому.
  6. .outputKey("patents"): Когда инструмент возвращает данные, ADK может автоматически сохранять их в состоянии сессии под этим ключом. Именно так explainPatent может получить доступ к результатам getPatents.
  7. VECTOR_SEARCH_ENDPOINT: Это переменная, содержащая основную функциональную логику контекстных вопросов и ответов для пользователя в сценарии поиска патентов.
  8. Пункт действий: После выполнения шага «Запуск функции Java Cloud» из предыдущего раздела необходимо установить обновленное значение развернутой конечной точки.
  9. searchTool : Этот инструмент взаимодействует с пользователем, помогая найти в базе данных патентов контекстно релевантные совпадения по поисковому запросу пользователя.
  10. explainTool : Этот инструмент запрашивает у пользователя информацию о конкретном патенте для углубленного анализа. Затем он суммирует аннотацию патента и отвечает на дополнительные вопросы пользователя, основываясь на имеющихся данных о патенте.

Важное примечание: обязательно замените переменную VECTOR_SEARCH_ENDPOINT на значение вашей развернутой конечной точки CRF.

Использование InvocationContext для взаимодействия с сохранением состояния.

Одна из важнейших особенностей для создания полезных агентов — управление состоянием на протяжении нескольких ходов диалога. Компонент InvocationContext из ADK значительно упрощает эту задачу.

В нашем файле App.java:

  1. Когда определен метод initAgent(), мы используем .outputKey("patents"). Это сообщает ADK, что когда инструмент (например, getPatents) возвращает данные в поле отчета, эти данные должны храниться в состоянии сессии под ключом "patents".
  2. В методе инструмента explainPatent мы внедряем InvocationContext ctx:
public static Map<String, String> explainPatent(
    @Schema(description = "...") String patentId, InvocationContext ctx) {
    String previousResults = (String) ctx.session().state().get("patents");
    // ... use previousResults ...
}

Это позволяет инструменту explainPatent получить доступ к списку патентов, полученному инструментом getPatents в предыдущем раунде, что делает диалог состоятельным и согласованным.

9. Локальное тестирование через командную строку

Определите переменные среды

Вам потребуется экспортировать две переменные среды:

  1. Ключ Gemini, который можно получить в AI Studio:

Для этого перейдите по ссылке https://aistudio.google.com/apikey и получите ключ API для вашего активного проекта Google Cloud, в котором вы внедряете это приложение, и сохраните ключ где-нибудь:

ae2db169e6a94e4a.png

  1. Получив ключ, откройте терминал Cloud Shell и перейдите в созданную нами директорию adk-agents, выполнив следующую команду:
cd adk-agents
  1. Переменная, указывающая на то, что в этот раз мы не будем использовать Vertex AI.
export GOOGLE_GENAI_USE_VERTEXAI=FALSE
export GOOGLE_API_KEY=AIzaSyDF...
  1. Запустите свой первый агент через командную строку.

Для запуска первого агента используйте следующую команду Maven в терминале:

mvn compile exec:java -DmainClass="agents.App"

В вашем терминале вы увидите интерактивный ответ от агента.

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

Развертывание вашего Java-агента ADK в Cloud Run аналогично развертыванию любого другого Java-приложения:

  1. Dockerfile: Создайте Dockerfile для упаковки вашего Java-приложения.
  2. Сборка и загрузка образа Docker: используйте Google Cloud Build и Artifact Registry.
  3. Вы можете выполнить описанный выше шаг и развернуть приложение в Cloud Run всего одной командой:
gcloud run deploy --source . --set-env-vars GOOGLE_API_KEY=<<Your_Gemini_Key>>

Аналогичным образом вы можете развернуть свою Java Cloud Run Function (gcfv2.PatentSearch). В качестве альтернативы, вы можете создать и развернуть Java Cloud Run Function для логики работы с базой данных непосредственно из консоли Cloud Run Function.

11. Тестирование с использованием веб-интерфейса.

ADK поставляется с удобным веб-интерфейсом для локального тестирования и отладки вашего агента. Когда вы запускаете свой файл App.java локально (например, mvn exec:java -Dexec.mainClass="agents.App", если это настроено, или просто запускаете метод main), ADK обычно запускает локальный веб-сервер.

Веб-интерфейс ADK позволяет вам:

  1. Отправляйте сообщения своему агенту.
  2. Просмотрите события (сообщение пользователя, вызов инструмента, ответ инструмента, ответ LLM).
  3. Проверьте состояние сессии.
  4. Просмотрите журналы и трассировки.

Это бесценно на этапе разработки для понимания того, как ваш агент обрабатывает запросы и использует свои инструменты. Предполагается, что ваш mainClass в pom.xml установлен на com.google.adk.web.AdkWebServer , и ваш агент зарегистрирован в нем, или вы используете локальный тестовый раннер, который предоставляет к нему доступ.

При запуске файла App.java с использованием InMemoryRunner и Scanner для ввода в консоль вы тестируете основную логику агента. Веб-интерфейс — это отдельный компонент для более наглядной отладки, часто используемый, когда ADK предоставляет доступ к вашему агенту по протоколу HTTP.

Для запуска локального сервера SpringBoot из корневого каталога вы можете использовать следующую команду Maven:

mvn compile exec:java -Dexec.args="--adk.agents.source-dir=src/main/java/ --logging.level.com.google.adk.dev=TRACE --logging.level.com.google.adk.demo.agents=TRACE"

Интерфейс часто доступен по URL-адресу, указанному в выводе приведенной выше команды. Если он развернут в Cloud Run , вы сможете получить к нему доступ по ссылке, соответствующей развертыванию в Cloud Run.

Результат должен отображаться в интерактивном интерфейсе.

Посмотрите видео ниже, посвященное работе нашего патентного агента:

Демонстрация системы контроля качества патентных заявок с встроенной оценкой поиска и полноты в AlloyDB!

ca7b0fc4fe571dd6.png

12. Уборка

Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этой статье, выполните следующие действия:

  1. В консоли Google Cloud перейдите по ссылке https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog
  2. https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog page.
  3. В списке проектов выберите проект, который хотите удалить, и нажмите кнопку «Удалить» .
  4. В диалоговом окне введите идентификатор проекта, а затем нажмите «Завершить» , чтобы удалить проект.

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

Поздравляем! Вы успешно создали своего агента для анализа патентов на Java, объединив возможности ADK, https://cloud.google.com/alloydb/docs?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog , Vertex AI и Vector Search. Кроме того, мы сделали огромный шаг вперед в создании контекстного поиска сходства, сделав его настолько преобразующим, эффективным и действительно значимым.

Начните прямо сегодня!

Документация ADK: [Ссылка на официальную документацию ADK для Java]

Исходный код программы анализа патентов: [Ссылка на ваш (теперь общедоступный) репозиторий GitHub]

Примеры Java-агентов: [ссылка на репозиторий adk-samples]

Присоединяйтесь к сообществу ADK: https://www.reddit.com/r/agentdevelopmentkit/

Успешного создания агентов!