1. Введение
В этом практическом занятии вы создадите интерактивного агента-бариста с искусственным интеллектом для кофейни. Используя открытый исходный код комплекта разработки агентов Google (ADK) и модель Gemini 3.5 Flash , вы реализуете метод генерации с дополненной реальностью (RAG), чтобы обосновать рекомендации агента на основе фиктивного набора данных меню. Наконец, вы обернете агента в пользовательский интерфейс Streamlit и развернете его в Cloud Run .
Что вы будете делать
- Создайте источник данных RAG (
menu.json), содержащий информацию о кофе, теги и аллергены. - Создайте агента искусственного интеллекта, используя ADK
LlmAgent, и подключите к нему инструмент Python для загрузки данных меню. - Оберните агента в чат-приложение Streamlit, которое управляет историей переписки.
- Разверните приложение Streamlit в Cloud Run, используя развертывание на основе исходного кода.
- Проверьте заземление RAG и осведомленность об аллергенах.

Что вам понадобится
- Веб-браузер, например Chrome .
- Проект Google Cloud с включенной функцией выставления счетов.
- Базовые знания Python.
Этот практический семинар предназначен для разработчиков всех уровней, включая начинающих.
Ориентировочная стоимость: менее 1 доллара США.
2. Прежде чем начать
Создайте проект в Google Cloud.
- В консоли Google Cloud выберите или создайте проект Google Cloud .
- Убедитесь, что для вашего облачного проекта включена функция выставления счетов.
Запустить Cloud Shell
- В верхней части консоли Google Cloud нажмите кнопку «Активировать Cloud Shell» .

- Проверка подлинности:

gcloud auth list
- Убедитесь, что ваш активный проект установлен:
gcloud config get project
Если отображаемый идентификатор проекта неверен или не задан, выполните следующую команду:
gcloud config set project <YOUR_PROJECT_ID>
Включить API
Выполните эту команду, чтобы включить все необходимые API:
gcloud services enable \
run.googleapis.com \
aiplatform.googleapis.com \
cloudbuild.googleapis.com
3. Настройте свой проект
На этом шаге вы инициализируете переменные среды вашего проекта и создадите рабочую директорию для вашего проекта.
- В активной сессии Cloud Shell инициализируйте следующие переменные среды проекта:
export PROJECT_ID=$(gcloud config get-value project)
Примечание: Используйте ближайший регион.
Найдите ближайший к вам регион и замените insert-region-here на него в следующей команде:
export REGION=[insert-region-here]
- Создайте и перейдите в новую директорию проекта с именем
coffee-barista-agent:
mkdir coffee-barista-agent && cd coffee-barista-agent
4. Создайте фиктивный источник данных для меню.
Чтобы обездвижить ИИ-бариста и предотвратить галлюцинации, связанные с несуществующими товарами, вы создадите локальный набор данных меню. Агент будет считывать этот файл во время выполнения с помощью специального инструмента.
- Создайте и откройте
menu.jsonв редакторе Cloud Shell:
cloudshell edit menu.json
- Вставьте следующее содержимое JSON в редактор и сохраните файл:
[
{
"name": "Espresso Solo",
"description": "A single shot of rich, bold espresso.",
"price": 2.50,
"tags": ["strong", "hot", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Oat Milk Honey Latte",
"description": "Creamy steamed oat milk with espresso and a touch of honey.",
"price": 5.00,
"tags": ["sweet", "hot", "dairy-free"],
"allergens": []
},
{
"name": "Cold Brew Coffee",
"description": "Smooth, slow-steeped cold brew served over ice.",
"price": 4.00,
"tags": ["strong", "cold", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Seasonal Pumpkin Latte",
"description": "Spiced pumpkin sauce, espresso, and steamed milk, topped with whipped cream.",
"price": 5.50,
"tags": ["sweet", "hot", "seasonal"],
"allergens": ["dairy"]
},
{
"name": "Classic Croissant",
"description": "Flaky, buttery traditional French pastry.",
"price": 3.50,
"tags": ["bakery", "savory"],
"allergens": ["wheat", "dairy"]
},
{
"name": "Vegan Blueberry Muffin",
"description": "Soft, sweet muffin packed with real blueberries, entirely plant-based.",
"price": 3.75,
"tags": ["bakery", "sweet", "dairy-free", "vegan"],
"allergens": ["wheat"]
},
{
"name": "Nitro Cold Brew",
"description": "Cold brew infused with nitrogen for a super smooth, creamy head.",
"price": 4.50,
"tags": ["strong", "cold", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Iced Caramel Macchiato",
"description": "Chilled milk and vanilla syrup marked with espresso and caramel drizzle.",
"price": 5.25,
"tags": ["sweet", "cold"],
"allergens": ["dairy"]
}
]
- Убедитесь, что JSON-файл отформатирован правильно:
cat menu.json | python3 -m json.tool > /dev/null && echo "Valid JSON!"
💬 Обсуждение: Локальные JSON-базы данных против реальных баз данных
Почему мы используем простой локальный файл menu.json вместо работающей базы данных?
Для быстрого обучения или прототипа локальный JSON-файл позволяет избежать затрат времени и сложностей на первоначальную настройку базы данных. Однако в реальном корпоративном приложении вы бы подключили агент к управляемой базе данных, такой как Cloud Firestore, AlloyDB или Cloud SQL.
Использование базы данных в реальном времени позволяет менеджерам кофеен добавлять сезонные товары, обновлять цены или динамически корректировать теги аллергенов без пересборки образа контейнера или повторного развертывания кода приложения. Мы будем использовать базу данных в реальном времени в качестве дополнительного шага позже в ходе практического занятия.
5. Создайте агент ADK.
Теперь вы установите необходимые пакеты и создадите основную логику агента ADK. Вы определите инструмент get_menu() и передадите его в LlmAgent .
- Создайте и откройте
requirements.txtв редакторе Cloud Shell:
cloudshell edit requirements.txt
- Вставьте следующие зависимости в редактор и сохраните файл:
google-adk==2.2.0
streamlit==1.56.0
- Создайте и откройте
agent.pyв редакторе Cloud Shell:
cloudshell edit agent.py
- Вставьте следующий код в
agent.py:
# agent.py
import json
from google.adk.agents import LlmAgent
# [START get_menu]
def get_menu() -> str:
"""Retrieves the coffee shop menu from menu.json.
Returns:
str: A JSON string representing the list of menu items.
"""
try:
with open("menu.json", "r") as f:
menu_data = json.load(f)
return json.dumps(menu_data)
except Exception as e:
return json.dumps({"error": f"Could not retrieve menu: {str(e)}"})
# [END get_menu]
# Create the barista agent
barista_agent = LlmAgent(
name="barista_agent",
model="gemini-3.5-flash",
instruction="""You are a friendly barista at ☕ Coffee Shop.
Your job is to recommend drinks and pastries to customers based on their preferences.
Rules you MUST follow:
1. You must recommend items ONLY from the menu returned by get_menu().
2. Do NOT recommend or suggest any item that is not present in the menu.
3. If a user's preference is vague or unclear, ask exactly ONE friendly clarifying question to narrow down what they want (e.g., cold or hot, sweet or strong, coffee or pastry).
4. Be warm and welcoming, but remain professional.
5. Ground your recommendations in the actual tags, descriptions, and allergens listed in the menu (e.g., if a user is dairy-free, recommend ONLY items tagged 'dairy-free' or with no dairy allergens).
""",
tools=[get_menu]
)
from google.adk.apps import App
# Define the App object
app = App(
name="coffee_barista_app",
root_agent=barista_agent
)
- Создайте и откройте
app.pyв редакторе Cloud Shell:
cloudshell edit app.py
- Вставьте следующий код в
app.py:
# app.py
import streamlit as st
import json
# Set page config for a premium look
st.set_page_config(
page_title="☕ Coffee Shop - Barista Bot",
page_icon="☕",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS to make the header sticky (adapts to light/dark themes)
st.markdown("""
<style>
div[data-testid="element-container"]:has(.header-container),
div.element-container:has(.header-container) {
position: sticky;
top: 2.875rem;
z-index: 999;
background-color: transparent;
padding-bottom: 10px;
}
</style>
""", unsafe_allow_html=True)
# App Header (using inline styles for the permanent coffee theme look)
st.markdown("""
<div class="header-container" style="text-align: center; padding: 20px; background: linear-gradient(135deg, #8B5E3C, #6F4E37); color: white; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
<h1 style="margin: 0; font-size: 2.5rem; font-weight: 700; color: white;">☕ ☕ Coffee Shop</h1>
<p style="margin: 5px 0 0 0; font-size: 1.1rem; opacity: 0.9; color: white;">Your friendly AI Barista is ready to help you find the perfect drink or pastry!</p>
</div>
""", unsafe_allow_html=True)
# Load Menu for the sidebar
# [START load_menu]
try:
with open("menu.json", "r") as f:
menu_items = json.load(f)
except Exception as e:
st.error(f"Error loading menu: {e}")
menu_items = []
# [END load_menu]
# Sidebar Menu & Configuration
with st.sidebar:
st.markdown("## ☕ Coffee Shop Menu")
st.markdown("Explore our offerings and ask the barista for recommendations.")
st.markdown("---")
for item in menu_items:
with st.container(border=True):
st.markdown(f"**{item['name']}** • **${item['price']:.2f}**")
st.caption(item['description'])
# Tags & Allergens as native badges
tags = " ".join([f"`{t}`" for t in item.get("tags", [])])
if tags:
st.markdown(tags)
allergens = ", ".join(item.get("allergens", []))
if allergens:
st.markdown(f"⚠️ *Allergens: {allergens}*")
# Chat Interface
if "session_id" not in st.session_state:
import uuid
st.session_state.session_id = str(uuid.uuid4())
if "runner" not in st.session_state:
from google.adk.runners import InMemoryRunner
from agent import app
st.session_state.runner = InMemoryRunner(app=app)
if "messages" not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "Welcome to ☕ Coffee Shop! What can I get started for you today?"}
]
# Display existing messages
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
# User Input
if prompt := st.chat_input("Ask for recommendations (e.g., 'What dairy-free pastries do you have?')"):
# Display user message
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
# Generate response
with st.chat_message("assistant"):
try:
import asyncio
# Run the ADK runner asynchronously using asyncio.run
async def fetch_response():
return await st.session_state.runner.run_debug(
prompt,
session_id=st.session_state.session_id
)
res_events = asyncio.run(fetch_response())
response_text = "".join([
part.text
for event in res_events
if event.content and event.content.parts
for part in event.content.parts
if part.text
])
st.markdown(response_text)
st.session_state.messages.append({"role": "assistant", "content": response_text})
except Exception as e:
st.error(f"Apologies, I ran into an error: {e}")
💬 Обсуждение: Компромиссы в моделях и эффективность токенов для извлечения средств
Зачем вызывать инструмент для получения меню, вместо того чтобы просто вставить весь текст меню в инструкции системы оператора?
Токен-экономика! Вставить 8 позиций в запрос — это дёшево, но что, если кофейня расширится до 500 позиций, включая ингредиенты, изготовленные на заказ? Вставка больших наборов данных непосредственно в системный запрос увеличивает количество токенов запроса, повышая транзакционные издержки и задержку ответа API на каждый запрос.
Используя инструмент ADK, агент динамически запрашивает чтение меню ТОЛЬКО тогда, когда это необходимо. LLM получает в качестве контекста только соответствующие данные меню, что минимизирует размер токена запроса.
💬 Обсуждение: Хранилища состояний памяти и производственных хранилищ
Сохраняется ли история чата, хранящаяся в переменной st.session_state в Streamlit, после закрытия пользователем вкладки браузера?
Нет, это не так. st.session_state полностью хранится в памяти и уникален для активного соединения браузера. Если пользователь обновляет страницу или закрывает вкладку, история его переписки с бариста теряется.
Для использования в рабочем приложении вам потребуется подключить ADK Runner к постоянному хранилищу данных, такому как Cloud Firestore или Redis. ADK предоставляет встроенные сервисные абстракции (например, SessionService ), которые упрощают сохранение и возобновление истории чата при перезагрузке страниц и на разных устройствах.
6. Разверните агент в Cloud Run.
Вы будете развертывать приложение Streamlit непосредственно из исходного кода, используя встроенные в Cloud Run пакеты сборки. Следуя принципу минимальных привилегий, вы будете создавать и развертывать приложение, используя выделенную пользовательскую учетную запись службы, а не учетную запись службы Compute Engine по умолчанию.
- Создайте выделенный сервисный аккаунт:
gcloud iam service-accounts create barista-agent-sa \
--description="Service account for Coffee Barista ADK agent on Cloud Run" \
--display-name="Barista Agent Service Account"
- Предоставьте новой учетной записи службы роль пользователя Gemini Enterprise Agent Platform (
roles/aiplatform.user):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
- Разверните службу с помощью
gcloud run deploy, указав адрес электронной почты новой учетной записи службы с помощью флага--service-account:
gcloud run deploy coffee-barista \
--source . \
--region $REGION \
--allow-unauthenticated \
--labels dev-tutorial=codelab-streamlit-rag-adk \
--command "/cnb/lifecycle/launcher" \
--args "sh,-c,python3 -m streamlit run app.py --server.port=\$PORT --server.address=0.0.0.0 --server.enableCORS=false --server.enableXsrfProtection=false" \
--service-account "barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--set-env-vars GOOGLE_GENAI_USE_VERTEXAI=TRUE,GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GOOGLE_CLOUD_LOCATION=global
- После развертывания найдите URL-адрес службы в выводе команды.
💬 Обсуждение: Развертывание контейнеров против развертывания из исходного кода и безопасность IAM
Мы развернули приложение в Cloud Run с помощью команды gcloud run deploy –source, не создавая Dockerfile или Procfile. Как Cloud Run определил, как скомпилировать и запустить наше приложение на Python?
Cloud Run использует Buildpacks для анализа вашего репозитория. При обнаружении наличия файла requirements.txt и исходных файлов Python, движок автоматически компилирует и упаковывает контейнер среды выполнения Python.
Создание собственного Dockerfile дает вам полный контроль над системными пакетами и базовыми слоями вашего контейнера. Procfile — это более простой способ объявить команду запуска без полной настройки контейнера. Но для быстрого развертывания развертывание из исходного кода ( --source ) очень эффективно.
Почему мы пошли на дополнительный шаг и создали собственную учетную запись службы barista-agent-sa вместо того, чтобы просто использовать учетную запись службы Compute Engine по умолчанию?
Безопасность превыше всего! Учетная запись службы Compute Engine по умолчанию имеет чрезвычайно широкие права редактора. Запуск нашего контейнера Cloud Run под учетной записью службы по умолчанию означает, что если в нашем приложении есть уязвимость в системе безопасности, злоумышленник потенциально может читать, записывать или удалять другие ресурсы в нашем проекте Google Cloud.
Создав выделенную учетную запись службы и назначив ей только роль roles/aiplatform.user , мы следуем принципу наименьших привилегий: приложение имеет только тот доступ, который ему необходим для вызова Gemini, и ничего больше.
7. Проверьте поведение RAG.
Откройте URL-адрес сервиса Cloud Run в веб-браузере и задайте ИИ-бариста вопросы, чтобы проверить его надежность и ограничения безопасности.
- Запрос в меню: Спросите: «Порекомендуйте что-нибудь крепкое и теплое». Ожидаемый результат: Агент порекомендует эспрессо.
- Ловушка, когда чего-то нет в меню: Спросите: «У вас есть фраппучино с матчей?» Ожидаемый результат: Сотрудник вежливо откажет и объяснит, что этого напитка нет в меню.
- Запрос с учетом аллергенов: Спросите: «У меня непереносимость лактозы, что мне можно заказать?» Ожидается: Оператор рекомендует только блюда без молочных продуктов (например, латте на овсяном молоке, эспрессо, холодный кофе). Он НЕ рекомендует капучино или круассан.

8. Дополнительно: интегрируйте своего агента в Firestore с помощью векторного поиска.
В производственной среде хранение пунктов меню в локальном файле menu.json не является оптимальным решением, поскольку любое изменение меню требует пересборки образа контейнера и повторного развертывания службы Cloud Run.
Чтобы сделать приложение динамичным и масштабируемым, вы можете перенести данные меню в Cloud Firestore и использовать векторный поиск для извлечения только наиболее релевантных пунктов меню на основе семантического сходства.

1. Включите API Firestore и инициализируйте базу данных.
Выполните следующие команды, чтобы включить API Firestore и создать базу данных Firestore с именем coffee-menu в нативном режиме:
gcloud services enable firestore.googleapis.com
gcloud firestore databases create --database="coffee-menu" --location=$REGION
Примечание: для активации API может потребоваться 1–2 минуты. Если при создании базы данных появится сообщение API [firestore.googleapis.com] not enabled on project... Would you like to enable and retry? , введите Y , чтобы продолжить, или подождите минуту и выполните команду повторно.
2. Запустите Firestore с данными меню.
Чтобы быстро заполнить базу данных Firestore пунктами меню из файла menu.json , вы можете запустить локальный скрипт Python в Cloud Shell.
- Для запуска скрипта инициализации установите локально в Cloud Shell клиентские библиотеки Firestore и GenAI:
pip3 install google-cloud-firestore==2.27.0 google-genai==2.11.0
- Создайте скрипт для инициализации системы
seed.py):
cloudshell edit seed.py
- Вставьте следующий код в
seed.py:
# seed.py
import json
import os
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
db = firestore.Client(database="coffee-menu")
client = genai.Client(
vertexai=True,
project=os.environ.get("PROJECT_ID"),
location=os.environ.get("REGION", "us-central1")
)
with open("menu.json", "r") as f:
menu_items = json.load(f)
for item in menu_items:
# Use the name as the document ID
doc_id = item["name"].lower().replace(" ", "-")
# Generate text embedding using Vertex AI text-embedding-004 model
text_to_embed = f"{item['name']}: {item['description']}"
response = client.models.embed_content(
model="text-embedding-004",
contents=text_to_embed,
)
embedding = response.embeddings[0].values
# Add embedding vector to the menu item data
item["embedding"] = Vector(embedding)
db.collection("menu").document(doc_id).set(item)
print("Firestore menu collection seeded with vector embeddings successfully!")
- Запустите скрипт:
python3 seed.py
3. Создайте векторный индекс Firestore.
Для выполнения векторного поиска по пунктам меню необходимо создать составной векторный индекс по полю embedding в базе данных Firestore.
Выполните следующую команду в терминале Cloud Shell:
gcloud firestore indexes composite create \
--collection-group=menu \
--query-scope=COLLECTION \
--database="coffee-menu" \
--field-config=field-path=embedding,vector-config='{"dimension":"768", "flat": "{}"}'
Примечание: Создание индекса Firestore происходит в фоновом режиме и может занять несколько минут. Вы можете продолжить выполнение следующих шагов практического задания, пока создается индекс.
4. Предоставьте Firestore доступ к учетной записи службы.
Для того чтобы ваша служба Cloud Run могла запрашивать данные из Firestore, необходимо предоставить ее учетной записи службы роль пользователя Cloud Datastore ( roles/datastore.user ):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/datastore.user"
Примечание: Хотя мы используем Cloud Firestore в нативном режиме, Google Cloud использует унифицированные роли IAM Cloud Datastore (roles/datastore.viewer или roles/datastore.user) для управления доступом.
5. Обновите код
Теперь обновите свой код, чтобы получать меню из Firestore, а не из файла menu.json .
- Откройте файл
requirements.txtв редакторе Cloud Shell:
cloudshell edit requirements.txt
- Добавьте в конец файла клиентские библиотеки Firestore и GenAI и сохраните его:
google-cloud-firestore==2.27.0
google-genai==2.11.0
- Откройте
agent.pyв редакторе Cloud Shell:
cloudshell edit agent.py
- Найдите блок
# [START get_menu]вagent.pyи полностью замените его (с# [START get_menu]на# [END get_menu]`) следующей реализацией Firestore:
# [START get_menu]
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector
def get_menu(query: str) -> str:
"""Retrieves coffee shop menu items matching the user's query.
Args:
query: The search query or preference to find matching menu items.
Returns:
str: A JSON string representing the list of top matching menu items.
"""
try:
# Initialize clients
db = firestore.Client(database="coffee-menu")
client = genai.Client()
# Generate embedding for the search query
response = client.models.embed_content(
model="text-embedding-004",
contents=query,
)
query_vector = response.embeddings[0].values
# Search the Firestore database using Vector Search
results = db.collection("menu").find_nearest(
vector_field="embedding",
query_vector=Vector(query_vector),
distance_measure=DistanceMeasure.COSINE,
limit=3,
).stream()
menu_data = []
for doc in results:
item = doc.to_dict()
# Remove embedding field to save tokens
item.pop("embedding", None)
menu_data.append(item)
return json.dumps(menu_data)
except Exception as e:
return json.dumps({"error": f"Could not retrieve menu: {str(e)}"})
# [END get_menu]
- Откройте
app.pyв редакторе Cloud Shell:
cloudshell edit app.py
- Найдите блок
# [START load_menu]вapp.pyи полностью замените его (с# [START load_menu]на# [END load_menu]`) следующей логикой загрузки из Firestore:
# [START load_menu]
from google.cloud import firestore
try:
db = firestore.Client(database="coffee-menu")
docs = db.collection("menu").stream()
menu_items = []
for doc in docs:
item = doc.to_dict()
item.pop("embedding", None)
menu_items.append(item)
except Exception as e:
st.error(f"Error loading menu from Firestore: {e}")
menu_items = []
# [END load_menu]
6. Повторное развертывание в Cloud Run
Разверните обновленное приложение:
gcloud run deploy coffee-barista \
--source . \
--region $REGION \
--allow-unauthenticated \
--labels dev-tutorial=codelab-streamlit-rag-adk \
--command "/cnb/lifecycle/launcher" \
--args "sh,-c,python3 -m streamlit run app.py --server.port=\$PORT --server.address=0.0.0.0 --server.enableCORS=false --server.enableXsrfProtection=false" \
--service-account "barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--set-env-vars GOOGLE_GENAI_USE_VERTEXAI=TRUE,GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GOOGLE_CLOUD_LOCATION=global
7. Проверьте интеграцию с Firestore.
Чтобы проверить подключение агента к Firestore, добавьте совершенно новый пункт меню непосредственно в Firestore и убедитесь, что агент рекомендует его.
- Выполните следующую команду в Cloud Shell, чтобы записать новый документ в коллекцию
menuв Firestore с помощью Python:
python3 -c "
import os
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
db = firestore.Client(database='coffee-menu')
client = genai.Client(
vertexai=True,
project=os.environ.get('PROJECT_ID'),
location=os.environ.get('REGION', 'us-central1')
)
name = 'Matcha Green Tea Latte'
desc = 'Creamy steamed oat milk infused with premium Japanese matcha powder.'
res = client.models.embed_content(
model='text-embedding-004',
contents=f'{name}: {desc}'
)
embedding = res.embeddings[0].values
db.collection('menu').document('matcha-latte').set({
'name': name,
'description': desc,
'price': 5.50,
'tags': ['sweet', 'hot', 'dairy-free'],
'allergens': [],
'embedding': Vector(embedding)
})
print('Successfully added Matcha Latte with vector embeddings!')
"
- Обновите страницу приложения Streamlit в браузере, чтобы очистить сессию чата и загрузить новое состояние базы данных.
- Обратите внимание, что:
- Чай матча латте автоматически появляется в боковом меню.
- Спросите у чат-бота: "У вас есть какие-нибудь напитки с матчей?"
- Агент должен успешно порекомендовать новый напиток «Матча Грин Чай Латте» с указанным вами описанием и ценой. Это подтверждает, что агент напрямую связан с вашей рабочей базой данных Firestore!
9. Уборка
Чтобы избежать постоянного списания средств с вашего платежного аккаунта Google Cloud, удалите развернутую службу Cloud Run и пользовательскую учетную запись службы.
Удалите службу Cloud Run:
gcloud run services delete coffee-barista --region $REGION --quiet
Удалите учетную запись пользовательской службы:
gcloud iam service-accounts delete barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com --quiet
(Необязательно) Удалите базу данных Firestore (если она была создана):
gcloud firestore databases delete --database="coffee-menu" --quiet
Необязательный шаг: Удалите весь проект. ⚠️Выполняйте это ТОЛЬКО в том случае, если вы создали отдельный проект для этой лабораторной работы.
gcloud projects delete $PROJECT_ID
10. Поздравляем!
Поздравляем! Вы создали и развернули агента-бариста с ИИ, использующего технологию дополненного поиска (RAG), с помощью Google ADK и Cloud Run.
Что вы узнали
- Создание простых инструментов RAG на Python.
- Использование ADK
LlmAgentиInMemoryRunner. - Создание чатов с сохранением состояния в Streamlit.
- Развертывание Streamlit в Cloud Run с использованием сборок на основе исходного кода.