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

1. Обзор

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

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

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

Что ты построишь

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

  1. Создайте экземпляр AlloyDB и загрузите набор данных Toys.
  2. Включите расширения pgvector и генеративной модели искусственного интеллекта в AlloyDB.
  3. Генерируйте вложения из описания продукта и выполняйте поиск по косинусному сходству в режиме реального времени для поискового текста пользователя.
  4. Вызов Gemini 2.0 Flash для описания изображения, загруженного пользователем для контекстного поиска игрушек.
  5. Вызовите Imagen 3, чтобы создать игрушку в соответствии с интересами пользователя.
  6. Вызовите инструмент прогнозирования цен, созданный с помощью Gen AI Toolbox for Databases, для получения подробной информации о цене игрушки, созданной по индивидуальному заказу.
  7. Разверните решение в бессерверных функциях Cloud Run.

Требования

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

2. Архитектура

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

  1. Контекстный поиск с помощью RAG на базе искусственного интеллекта (генерация расширенного поиска)

Подумайте об этом так: вместо того, чтобы просто искать «красную машину», система понимает следующее:

«маленькое транспортное средство, подходящее для 3-летнего мальчика».

AlloyDB в качестве основы: мы используем AlloyDB, полностью управляемую базу данных Google Cloud, совместимую с PostgreSQL, для хранения данных наших игрушек, включая описания, URL-адреса изображений и другие соответствующие атрибуты.

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

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

Индекс скорости и точности ScaNN. Чтобы обеспечить быстрые и точные результаты, особенно по мере роста наших запасов игрушек, мы интегрируем индекс ScaNN (масштабируемые ближайшие соседи). Это значительно повышает эффективность и запоминаемость нашего векторного поиска.

  1. Поиск и анализ изображений с помощью Gemini 2.0 Flash

Предположим, что вместо того, чтобы вводить контекст в виде текста, пользователь хочет загрузить изображение знакомой игрушки, по которой он хочет выполнить поиск. Пользователи могут загрузить изображение понравившейся им игрушки и получить при этом соответствующие функции. Мы используем Flash-модель Gemini 2.0 от Google, вызываемую с помощью LangChain4j, для анализа изображения и извлечения соответствующего контекста, такого как цвет игрушки, материал, тип и предполагаемая возрастная группа.

  1. Создайте игрушку своей мечты с помощью генеративного искусственного интеллекта: изображение 3

Настоящее волшебство случается, когда пользователи решают создать собственную игрушку. Используя Imagen 3, мы позволяем им описывать игрушку своей мечты, используя простые текстовые подсказки. Представьте, что вы можете сказать: «Я хочу плюшевого дракона с фиолетовыми крыльями и дружелюбным лицом» и увидеть, как этот дракон оживает на вашем экране! Затем Imagen 3 генерирует изображение специально разработанной игрушки, предоставляя пользователю четкую визуализацию ее создания.

  1. Прогноз цен на основе Agents & Gen AI Toolbox для баз данных

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

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

  1. Java Spring Boot, Gemini Code Assist и Cloud Run для упрощенной разработки и бессерверного развертывания

Все приложение создано с использованием Java Spring Boot, надежной и масштабируемой среды. Мы использовали Gemini Code Assist на протяжении всего процесса разработки, особенно для фронтенд-разработки, что значительно ускоряло цикл разработки и улучшало качество кода. Мы использовали Cloud Run для развертывания всего приложения и функции Cloud Run для развертывания базы данных и агентских функций в качестве независимых конечных точек.

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

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

  1. В Google Cloud Console на странице выбора проекта выберите или создайте проект Google Cloud.
  2. Убедитесь, что для вашего облачного проекта включена оплата. Узнайте, как проверить, включена ли оплата в проекте .
  3. Вы будете использовать Cloud Shell , среду командной строки, работающую в Google Cloud, в которую предварительно загружен bq. Нажмите «Активировать 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, выполнив одну за другой следующие команды в терминале Cloud Shell:

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

gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com 
gcloud services enable cloudresourcemanager.googleapis.com 
gcloud services enable servicenetworking.googleapis.com 
gcloud services enable run.googleapis.com 
gcloud services enable cloudbuild.googleapis.com 
gcloud services enable cloudfunctions.googleapis.com 
gcloud services enable aiplatform.googleapis.com

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

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

Обратитесь к документации по командам и использованию gcloud.

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

В этой лабораторной работе мы будем использовать 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. После настройки сети вы можете продолжить создание кластера. Нажмите CREATE CLUSTER , чтобы завершить настройку кластера, как показано ниже:

e06623e55195e16e.png

Обязательно измените идентификатор экземпляра на «

vector-instance"

.

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

5. Прием данных

Теперь пришло время добавить таблицу с данными о магазине. Перейдите в 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;

Создать таблицу

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

CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;

При успешном выполнении вышеуказанной команды вы сможете просмотреть таблицу в базе данных.

Прием данных

Для этой лабораторной работы у нас есть тестовые данные примерно из 72 записей в этом файле SQL . Он содержит поля id, name, description, quantity, price, image_url . Остальные поля будут заполнены позже в лабораторной работе.

Скопируйте оттуда операторы строк/вставки, а затем вставьте эти строки в пустую вкладку редактора и выберите «Выполнить».

Чтобы просмотреть содержимое таблицы, разверните раздел «Проводник», пока не увидите таблицу с именем «Одежда». Нажмите трехточие (⋮), чтобы увидеть возможность запроса таблицы. Оператор SELECT откроется на новой вкладке редактора.

cfaa52b717f9aaed.png

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

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

GRANT EXECUTE ON FUNCTION embedding TO postgres;

Предоставьте РОЛЬ пользователя Vertex AI сервисной учетной записи AlloyDB.

Перейдите в терминал 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"

6. Создайте вложения для контекста

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

Рассмотрим описание прибрежного места. Его можно назвать «на воде», «на берегу океана», «прогулка из комнаты к океану», «сюр-ла-мер», «на берегу океана» и т. д. Все эти термины выглядят по-разному, но их семантическое значение или, в терминологии машинного обучения, их вложения должны быть очень близки друг к другу.

Теперь, когда данные и контекст готовы, мы запустим SQL, чтобы добавить встраивания описания продукта в таблицу в поле embedding . Вы можете использовать различные модели внедрения. Мы используем text-embedding-005 от Vertex AI. Обязательно используйте одну и ту же модель внедрения на протяжении всего проекта!

Примечание. Если вы используете существующий проект Google Cloud, созданный некоторое время назад, вам, возможно, придется продолжать использовать более старые версии модели встраивания текста, например textembedding-gecko.

Вернитесь на вкладку AlloyDB Studio и введите следующий DML:

UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);

Посмотрите на стол toys еще раз, чтобы увидеть некоторые вложения. Обязательно повторите оператор SELECT, чтобы увидеть изменения.

SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;

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

7d32f7cd7204e1f3.png

Примечание. Недавно созданные проекты Google Cloud на уровне бесплатного пользования могут столкнуться с проблемами квот, когда речь идет о количестве запросов на внедрение, разрешенных в секунду для моделей внедрения. Мы предлагаем вам использовать фильтрационный запрос для идентификатора, а затем выборочно выбирать 1–5 записей и т. д. при создании внедрения.

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

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

Предположим, пользователь спрашивает:

« I want a white plush teddy bear toy with a floral pattern ».

Вы можете найти совпадения для этого, выполнив запрос ниже:

select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

Давайте рассмотрим этот запрос подробно:

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

  1. Текст поиска пользователя: « I want a white plush teddy bear toy with a floral pattern.
  2. Мы конвертируем его во встраивания в методе embedding() используя модель: text-embedding-005 . Этот шаг должен выглядеть знакомо после предыдущего шага, где мы применили функцию внедрения ко всем элементам таблицы.
  3. " <=> " представляет собой использование метода расстояния COSINE SIMILARITY . Вы можете найти все доступные меры сходства в документации pgvector .
  4. Мы преобразуем результат метода внедрения в векторный тип, чтобы сделать его совместимым с векторами, хранящимися в базе данных.
  5. LIMIT 5 означает, что мы хотим извлечь 5 ближайших соседей для искомого текста.

Результат выглядит следующим образом:

fa7f0fc3a4c68804.png

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

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

Теперь предположим, что мы хотим повысить производительность (время запроса), эффективность и запоминаемость результатов векторного поиска с использованием индекса ScaNN . Пожалуйста, прочитайте шаги в этом блоге , чтобы сравнить разницу в результатах с индексом и без него.

Необязательный шаг: повышение эффективности и отзыва с помощью индекса ScanNN

Для удобства просто перечислим этапы создания индекса:

  1. Поскольку у нас уже созданы кластер, экземпляр, контекст и внедрения, нам просто нужно установить расширение ScaNN, используя следующий оператор:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. Далее мы создадим индекс (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);

В приведенном выше DDL apparel_index — это имя индекса.

"игрушки" - мой стол

«сканирование» — индексный метод

«встраивание» — это столбец таблицы, который я хочу индексировать.

«косинус» — это метод расстояния, который я хочу использовать с индексом

«8» — это количество секций, применяемых к этому индексу. Установите любое значение от 1 до 1048576. Дополнительные сведения о том, как определить это значение, см . в разделе Настройка индекса ScanNN .

Я использовал КВАДРАТНЫЙ КОРЕНЬ из количества точек данных, как рекомендовано в репозитории ScaNN (при секционировании num_leaves должно быть примерно квадратным корнем из количества точек данных).

  1. Проверьте, создан ли индекс с помощью запроса:
SELECT * FROM pg_stat_ann_indexes;
  1. Выполните векторный поиск, используя тот же запрос, который мы использовали без индекса:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

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

  1. Протестируйте с помощью простого поискового запроса с индексом и без него (удалив индекс):

В этом варианте использования всего 72 записи, поэтому индекс на самом деле не вступает в силу. Для теста, проведенного в другом варианте использования , результаты следующие:

Тот же запрос векторного поиска к данным встраивания INDEXED приводит к повышению качества и эффективности поиска. Эффективность значительно повышается (с точки зрения времени выполнения: 10,37 мс без ScaNN и 0,87 мс с ScaNN) с помощью индекса. Для получения дополнительной информации по этой теме, пожалуйста, обратитесь к этому блогу .

8. Проверка соответствия с LLM

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

Обеспечение настройки экземпляра для Gemini

Сначала проверьте, включена ли интеграция Google ML для вашего кластера и экземпляра. В AlloyDB Studio введите следующую команду:

show google_ml_integration.enable_model_support;

Если значение отображается как «включено» , вы можете пропустить следующие 2 шага и перейти непосредственно к настройке интеграции AlloyDB и модели Vertex AI.

  1. Перейдите к основному экземпляру кластера AlloyDB и нажмите «РЕДАКТИРОВАТЬ ОСНОВНОЙ ЭКЗЕМПЛЯР».

cb76b934ba3735bd.png

  1. Перейдите в раздел «Флаги» в дополнительных параметрах конфигурации. и убедитесь, что google_ml_integration.enable_model_support flag установлено значение « on », как показано ниже:

6a59351fcd2a9d35.png

Если для него не установлено значение «включено», установите для него значение «включено», а затем нажмите кнопку « ОБНОВИТЬ ЭКЗЕМПЛЯР» . Этот шаг займет несколько минут.

Интеграция моделей AlloyDB и Vertex AI

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

Сначала мы создаем соединение модели Gemini 1.5, как показано ниже. Не забудьте заменить $PROJECT_ID в приведенной ниже команде на идентификатор вашего проекта Google Cloud.

CALL
 google_ml.create_model( model_id => 'gemini-1.5',
   model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
   model_provider => 'google',
   model_auth_type => 'alloydb_service_agent_iam');

Вы можете проверить модели, настроенные для доступа, с помощью следующей команды в AlloyDB Studio:

select model_id,model_type from google_ml.model_info_view;        

Наконец, нам нужно предоставить пользователям базы данных разрешение на выполнение функции ml_predict_row для выполнения прогнозов с помощью моделей Google Vertex AI. Выполните следующую команду:

GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;

Примечание. Если вы используете существующий проект Google Cloud и существующий кластер/экземпляр AlloyDB, созданный некоторое время назад, вам может потребоваться удалить старые ссылки на модель Gemini-1.5 и создать заново с помощью приведенного выше оператора CALL и снова запустить выполнение гранта для функции ml_predict_row на случай, если у вас возникнут проблемы при предстоящих вызовах Gemini-1.5.

Оценка ответов

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

  1. Сначала мы отправим запрос в базу данных, чтобы получить 10 наиболее близких совпадений с пользовательским запросом.
  2. Чтобы определить, насколько действительны ответы, мы воспользуемся внешним запросом, в котором объясним, как оценивать ответы. В качестве части запроса он использует поле recommended_text , которое представляет собой текст поиска и content (поле описания игрушки) внутренней таблицы.
  3. Используя это, мы затем проверим «качественность» полученных ответов.
  4. predict_row возвращает результат в формате JSON. Код « -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'" используется для извлечения фактического текста из этого JSON. Чтобы увидеть фактический возвращаемый JSON, вы можете удалить этот код.
  5. Наконец, чтобы получить ответ LLM, мы извлекаем его с помощью REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g')
SELECT id,
       name,
       content,
       quantity,
       price,
       image_url,
       recommended_text,
       REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
  FROM (SELECT id,
               name,
               content,
               quantity,
               price,
               image_url,
               recommended_text,
               CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
          FROM (SELECT id,
                       name,
                       content,
                       quantity,
                       price,
                       image_url,
                       recommended_text,
                       json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
                                                                   request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ',                                                                                              recommended_text,                                                                                              '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ',                                                                                         content,                                                                                         '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
                  FROM (SELECT id,
                               name,
                               description AS content,
                               quantity,
                               price,
                               image_url,
                               'Pink panther standing' AS recommended_text
                          FROM toys
                         ORDER BY text_embeddings <=> embedding('text-embedding-005',
                                                                'Pink panther standing')::VECTOR
                         LIMIT 10) AS xyz) AS X
         GROUP BY id,
                  name,
                  content,
                  quantity,
                  price,
                  image_url,
                  recommended_text) AS final_matches
 WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';

Хотя это все еще может показаться устрашающим, надеюсь, вы сможете найти в этом немного больше смысла. Результаты показывают, есть ли совпадение, какой процент совпадения, а также некоторые пояснения к рейтингу.

Обратите внимание, что в модели Gemini потоковая передача включена по умолчанию, поэтому фактический ответ распределяется по нескольким строкам:

c2b006aeb3f3a2fc.png

9. Перенесите поиск игрушек в облако без сервера

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

  1. Перейдите в раздел «Функции Cloud Run» в Google Cloud Console, чтобы СОЗДАТЬ новую функцию Cloud Run, или воспользуйтесь ссылкой: https://console.cloud.google.com/functions/add .
  2. Выберите среду как « Функция Cloud Run ». Укажите имя функции « get-toys-alloydb » и выберите регион «us-central1». Установите для параметра Аутентификация значение «Разрешить неаутентифицированные вызовы» и нажмите «ДАЛЕЕ» . Выберите Java 17 в качестве среды выполнения и встроенный редактор для исходного кода.
  3. По умолчанию для точки входа будет установлено значение « gcfv2.HelloHttpFunction ». Замените код-заполнитель в HelloHttpFunction.java и pom.xml вашей функции Cloud Run кодом из HelloHttpFunction.java и pom.xml соответственно.
  4. Не забудьте изменить заполнитель <<YOUR_PROJECT>> и учетные данные подключения AlloyDB на свои значения в файле Java. Учетные данные AlloyDB — это те же учетные данные, которые мы использовали в начале этой лабораторной работы. Если вы использовали другие значения, измените их в файле Java.
  5. Нажмите «Развернуть» .

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

ВАЖНЫЙ ШАГ:

После того как вы приступите к развертыванию, вы сможете увидеть функции в консоли Google Cloud Run Functions . Найдите вновь созданную функцию ( get-toys-alloydb ), щелкните ее, затем нажмите «РЕДАКТИРОВАТЬ» и измените следующее:

  1. Перейдите в раздел «Среда выполнения, сборка, подключения и настройки безопасности».
  2. Увеличьте таймаут до 180 секунд.
  3. Перейдите на вкладку ПОДКЛЮЧЕНИЯ:

4e83ec8a339cda08.png

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

8126ec78c343f199.png

  1. Укажите имя соединителя VPC и убедитесь, что регион совпадает с регионом вашего экземпляра. Оставьте значение «Сеть» по умолчанию и установите «Подсеть» в качестве «Пользовательский диапазон IP-адресов» с доступным диапазоном IP-адресов 10.8.0.0 или чем-то подобным.
  2. Разверните ПОКАЗАТЬ НАСТРОЙКИ МАСШТАБИРОВАНИЯ и убедитесь, что у вас установлена ​​следующая конфигурация:

7baf980463a86a5c.png

  1. Нажмите CREATE, и этот соединитель теперь должен быть указан в настройках исходящего трафика.
  2. Выберите вновь созданный соединитель
  3. Выберите маршрутизацию всего трафика через этот соединитель VPC.
  4. Нажмите «ДАЛЕЕ» , а затем «РАЗВЕРТЫВАТЬ» .

10. Проверьте функцию Cloud Run.

После развертывания обновленной облачной функции вы должны увидеть конечную точку в следующем формате:

https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/get-toys-alloydb

Альтернативно вы можете протестировать функцию Cloud Run следующим образом:

PROJECT_ID=$(gcloud config get-value project)

curl -X POST https://us-central1-$PROJECT_ID.cloudfunctions.net/get-toys-alloydb \
  -H 'Content-Type: application/json' \
  -d '{"search":"I want a standing pink panther toy"}' \
  | jq .

И результат:

23861e9091565a64.png

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

11. Создание клиента веб-приложения!

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

  1. Поскольку мы используем Gemini 2.0 Flash для описания изображения, которое пользователь может загрузить, чтобы найти подходящие игрушки, нам необходимо получить КЛЮЧ API для этого приложения. Для этого перейдите по адресу https://aistudio.google.com/apikey и получите ключ API для активного проекта Google Cloud, в котором вы реализуете это приложение, и сохраните ключ где-нибудь:

ae2db169e6a94e4a.png

  1. Перейдите к терминалу Cloud Shell.
  2. Клонируйте репозиторий с помощью следующей команды:
git clone https://github.com/AbiramiSukumaran/toysearch

cd toysearch
  1. После клонирования репозитория вы сможете получить доступ к проекту из редактора Cloud Shell .
  2. Вам необходимо удалить папки «get-toys-alloydb» и «toolbox-toys» из клонированного проекта, поскольку эти 2 представляют собой код функций Cloud Run, на который можно ссылаться из репозитория, когда они вам понадобятся.
  3. Прежде чем создавать и развертывать приложение, убедитесь, что установлены все необходимые переменные среды. Перейдите к терминалу Cloud Shell и выполните следующие действия:
PROJECT_ID=$(gcloud config get-value project)

export PROJECT_ID $PROJECT_ID

export GOOGLE_API_KEY <YOUR API KEY that you saved>
  1. Создайте и запустите приложение локально:

Убедившись, что вы находитесь в каталоге проекта, выполните следующие команды:

mvn package

mvn spring-boot:run 
  1. Развертывание в облаке
gcloud run deploy --source .

12. Понимание деталей генеративного ИИ

Никаких действий не требуется. Просто для вашего понимания:

Теперь, когда у вас есть приложение для развертывания, потратьте немного времени, чтобы понять, как мы выполнили поиск (текста и изображения) и генерацию.

  1. Пользовательский текстовый векторный поиск:

Эта проблема уже рассмотрена в функциях Cloud Run, которые мы развернули в разделе «Использование веб-приложения Vector Search».

  1. Векторный поиск на основе загрузки изображений:

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

Мы используем Flash-модель Gemini 2.0 от Google, вызываемую с помощью LangChain4j, для анализа изображения и извлечения соответствующего контекста, такого как цвет игрушки, материал, тип и предполагаемая возрастная группа.

Всего за 5 шагов мы использовали мультимодальный ввод данных пользователем для сопоставления результатов с вызовом большой языковой модели с использованием платформы с открытым исходным кодом. Узнайте как:

package cloudcode.helloworld.web;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;

public class GeminiCall {
  public String imageToBase64String(byte[] imageBytes) {
    String base64Img = Base64.getEncoder().encodeToString(imageBytes);
    return base64Img;
  }

  public String callGemini(String base64ImgWithPrefix) throws Exception {
    String searchText = "";

    // 1. Remove the prefix
    String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");

    // 2. Decode base64 to bytes
    byte[] imageBytes = Base64.getDecoder().decode(base64Img);
    String image = imageToBase64String(imageBytes);

    // 3. Get API key from environment variable
        String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
                .orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));

    // 4. Invoke Gemini 2.0
    ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
        .apiKey(apiKey)
        .modelName("gemini-2.0-flash-001")
        .build();

    Response<AiMessage> response = gemini.generate(
        UserMessage.from(
            ImageContent.from(image, "image/jpeg"),
            TextContent.from(
                "The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send  response stating that no toy is found in the input image.")));
   
    // 5. Get the text from the response and send it back to the controller
    searchText = response.content().text().trim();
    System.out.println("searchText inside Geminicall: " + searchText);
    return searchText;
  }
}
  1. Узнайте, как мы использовали Imagen 3 для создания индивидуальной игрушки по запросу пользователя с помощью генеративного искусственного интеллекта.

Затем Imagen 3 генерирует изображение специально разработанной игрушки, предоставляя пользователю четкую визуализацию ее создания. Вот как мы это сделали всего за 5 шагов:

// Generate an image using a text prompt using an Imagen model
    public String generateImage(String projectId, String location, String prompt)
        throws ApiException, IOException {
      final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
      PredictionServiceSettings predictionServiceSettings =
      PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
     
      // 1. Set up the context and prompt
      String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
      prompt = context + prompt;

      // 2. Initialize a client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      try (PredictionServiceClient predictionServiceClient =
          PredictionServiceClient.create(predictionServiceSettings)) {
 
      // 3. Invoke Imagen 3
        final EndpointName endpointName =
            EndpointName.ofProjectLocationPublisherModelName(
                projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
        Map<String, Object> instancesMap = new HashMap<>();
        instancesMap.put("prompt", prompt);
        Value instances = mapToValue(instancesMap);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("sampleCount", 1);
        paramsMap.put("aspectRatio", "1:1");
        paramsMap.put("safetyFilterLevel", "block_few");
        paramsMap.put("personGeneration", "allow_adult");
        paramsMap.put("guidanceScale", 21);
        paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
        Value parameters = mapToValue(paramsMap);
       
      // 4. Get prediction response image
        PredictResponse predictResponse =
            predictionServiceClient.predict(
                endpointName, Collections.singletonList(instances), parameters);

      // 5. Return the Base64 Encoded String to the controller
        for (Value prediction : predictResponse.getPredictionsList()) {
          Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
          if (fieldsMap.containsKey("bytesBase64Encoded")) {
            bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
        }
      }
      return bytesBase64EncodedOuput.toString();
    }
  }

Прогноз цен

В предыдущем разделе мы обсуждали, как Imagen генерирует изображение игрушки, которую пользователь хочет создать самостоятельно. Чтобы они могли ее купить, приложению необходимо установить цену, и мы применили интуитивную логику для определения цены на игрушку, изготовленную на заказ. Логика заключается в том, чтобы использовать среднюю цену пяти наиболее подходящих игрушек (с точки зрения описания) к игрушке, которую разрабатывает пользователь.

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

13. Gen AI Toolbox для баз данных

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

Вот шаги, которые вам нужно выполнить, чтобы иметь возможность настроить это для подготовки вашего инструмента и сделать наше приложение агентом: Ссылка на Toolbox Codelab.

Теперь ваше приложение может использовать эту развернутую конечную точку функции Cloud Run для заполнения цены вместе с сгенерированным результатом Imagen для изображения игрушки, изготовленного по индивидуальному заказу.

14. Проверьте свое веб-приложение

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

https://www.youtube.com/shorts/ZMqUAWsghYQ

Вот как выглядит целевая страница:

241db19e7176e93e.png

15. Очистка

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

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

16. Поздравления

Поздравляем! Вы успешно выполнили контекстный поиск и генерацию в магазине игрушек с использованием AlloyDB, pgvector, Imagen и Gemini 2.0, одновременно используя библиотеки с открытым исходным кодом для создания надежной интеграции. Объединив возможности AlloyDB , Vertex AI и Vector Search , мы сделали гигантский шаг вперед, сделав контекстный и векторный поиск доступным, эффективным и по-настоящему осмысленным.