1. Введение

Узнайте, как создать многомодальный многоагентный движок, который обрабатывает исходное тематическое задание и организует создание привлекательных материалов для социальных сетей. Используя комплект разработки агентов Google (ADK) и протокол Agent2Agent (A2A), вы будете создавать автономных микроагентов, оформлять правила бренда в виде многоразового навыка агента, развертывать сервис агентов в Cloud Run и оценивать сгенерированные ключевые визуальные элементы на соответствие бренду с помощью функций искусственного интеллекта BigQuery.
Что вы будете делать
В этом практическом занятии вы научитесь выполнять следующие задачи:
- Организуйте работу нескольких агентов ADK с помощью детерминированного графового рабочего процесса.
- Преобразуйте фирменные рекомендации в навык агента, который загружается только при необходимости.
- Оснастите агента инструментом для генерации изображений, который сохраняет результаты его работы в виде артефакта.
- Предоставьте доступ к агенту в качестве сервиса A2A и вызывайте его с другого агента как с удаленного узла.
- Разверните Visual Director в Cloud Run и вызовите рабочий процесс через A2A.
- Оцените соответствие сгенерированных ключевых визуальных элементов бренду в BigQuery с помощью функций искусственного интеллекта.
Что вам понадобится
- Веб-браузер (например, Chrome).
- Учетная запись Google Cloud и проект Google Cloud с включенной функцией выставления счетов.
2. Прежде чем начать
Создайте проект в Google Cloud.
- В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
- Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта .
Запустить Cloud Shell
Для загрузки кода, запуска скриптов настройки и развертывания приложения вы будете использовать Google Cloud Shell .
- Откройте Google Cloud Shell в браузере (или нажмите «Активировать Cloud Shell» в верхней части консоли Google Cloud):
Нажмите «Продолжить», если появятся дополнительные уведомления. Подождите, пока терминал и редактор полностью загрузятся. Это может занять одну-две минуты.https://shell.cloud.google.com/ - Настройте идентификатор проекта Google Cloud и регион (например,
us-central1) в вашей среде, вставив это в терминал (заменитеис учетом ваших ценностей):export PROJECT_ID="<YOUR_PROJECT_ID>" export REGION="<YOUR_REGION>" gcloud config set project $PROJECT_ID
Вы должны увидеть сообщение, похожее на следующее: Your active configuration is: [cloudshell-####] Updated property [core/project] - Включите необходимые API Google Cloud для вашего проекта:
gcloud services enable \ compute.googleapis.com \ cloudresourcemanager.googleapis.com \ aiplatform.googleapis.com \ storage.googleapis.com \ storage-component.googleapis.com \ bigqueryconnection.googleapis.com \ bigquery.googleapis.com \ run.googleapis.com \ secretmanager.googleapis.com \ cloudbuild.googleapis.com \ artifactregistry.googleapis.com \ iap.googleapis.com \ iam.googleapis.com
Клонируйте репозиторий
У нас есть шаблон кода, который поможет вам начать работу с этим практическим заданием. Он относительно небольшой, но репозиторий GitHub, где он находится, довольно большой. Чтобы ускорить клонирование и сэкономить место на диске, мы обычно используем git clone с опцией --filter=blob:none , git sparse-checkout и ещё несколько команд.
Это звучит очень сложно, но антигравитация может всё это сделать за нас!
Для начала давайте настроим Antigravity CLI, чтобы он мог сразу приступить к решению нашей задачи, и запустим его.
В оболочке Cloud Shell выполните следующую команду:
source <(curl -fsSL https://github.com/GoogleCloudPlatform/devrel-demos/raw/refs/heads/vladkol/cloud-shell-configure-agy/codelabs/labs-scripts/bwg-multi-agent-pitch-generator/cloud_shell_configure_agy.sh)
Эта команда настраивает Antigravity CLI и запускает его в том же терминале. После выхода из Antigravity CLI вы возвращаетесь к командной строке Cloud Shell.

Нам нужна только папка codelabs/bwg-multi-agent-pitch-generator в репозитории. Давайте попросим Antigravity загрузить только эту папку и разместить её локально в ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/ .
Передайте этой задаче интерфейс командной строки Antigravity:
Download files from under `https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/codelabs/bwg-multi-agent-pitch-generator`
to folder `~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/`.
If `devrel-demos` folder already exists, rename it with a `.backup` suffix.

Antigravity выполнит задачу. Он запросит у вас разрешения на выполнение нескольких команд. После загрузки кода выйдите из командной строки Antigravity, выполнив команду /exit :
/exit

Откройте рабочую область репозитория.
Теперь откроем рабочую область кода в Cloud Shell. Выполните следующую команду в терминале Cloud Shell:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
cloudshell workspace .
Запустите скрипт установки.
Для упрощения процесса запустите скрипт установки из репозитория. Он настраивает переменные среды, устанавливает agents-cli , создает сегмент Cloud Storage для артефактов, устанавливает соединение с облачным ресурсом BigQuery и предоставляет необходимые разрешения IAM для учетной записи службы с автоматическим повтором попыток.
Скрипт установки также вызывает setenv.sh , небольшую вспомогательную программу, которая вычисляет необходимые обоим агентам переменные — GOOGLE_CLOUD_PROJECT , GOOGLE_CLOUD_REGION , GOOGLE_CLOUD_LOCATION и GOOGLE_GENAI_USE_VERTEXAI — на основе значений PROJECT_ID и REGION которые вы экспортировали выше. Он также сохраняет эти два значения в файл .env в вашем домашнем каталоге, чтобы вы могли восстановить их позже.
- В Cloud Shell сделайте скрипт установки исполняемым и запустите его:
chmod +x codelab-setup.sh setenv.sh ./codelab-setup.sh - Выполнение займет около минуты. Вы должны увидеть сообщение об успешном завершении: "🎉 🦄 Выполнение скрипта завершено."

- Скрипт установки запускался в отдельной оболочке, поэтому его переменные не попадали в ваш терминал. Загрузите их в свою сессию:
Вы должны увидеть, что ваш проект, регион и местоположение отображаются в ответном изображении.source ./setenv.sh
3. Организуйте работу агентов с помощью графового рабочего процесса.
В этом задании вы создадите проект генератора презентаций и построите рабочий процесс на основе графа, который запускает двух агентов и объединяет их результаты.
Для презентации необходима концепция, то есть идея и материалы, которые её продвигают. В этом примере мы разработаем агентов, выполняющих разные задачи в рамках общего объема работы, демонстрируя, как можно разделить сложные задачи и делегировать их различным агентам с разными обязанностями, что упростит управление ими.
Распределение подобной работы между специалистами требует координации действий каждого из агентов. Вы можете позволить своему агенту самостоятельно решать, когда вызывать каждого из своих субагентов, или применить более детерминированный подход. В этом практическом занятии вы будете использовать детерминированный подход с графовым рабочим процессом.
Создание основы для первого агентского проекта
- В Cloud Shell создайте проект, вставив в терминал следующую команду:
Это создаст полноценный, запускаемый проект: агент,cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create pitch-generator \ --agent adk \ --agent-directory pitch_generator \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approveDockerfile, тесты, Terraform для последующего использования и файл.envс его шаблоном.env.example. Для этого практического занятия важны две части:-
pitch_generator/agent.py— это агент, и именно этот файл вы перезаписываете. -
pitch_generator/— это имя пакета, задаваемое параметром--agent-directory.
setenv.sh, поэтому здесь ничего настраивать не нужно. -
- Установите зависимости:
Примечание: В этом примере также предусмотрена возможность подключения проекта к протоколу A2A, который будет использоваться далее в этом практическом занятии. Пока оставьте эти файлы без изменений.cd pitch-generator agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
Разберитесь в графике.
ADK v2.x поддерживает графовые рабочие процессы. Граф строится из узлов , которые являются единицами работы, и ребер , которые их соединяют. Узел обычно представляет собой агента, хотя подойдет и простая функция Python. Ребро указывает, что когда один узел завершает работу, запускается следующий.
Ребра записываются в виде списка, и ADK определяет порядок их расположения:
edges=[
("START", creative_director), ## the graph begins here
(creative_director, copywriter), ## then this
]
Вложенность придает преимуществу его смысл:
Край | Значение |
| Цепочка. а, затем б, затем в, один за другим. |
| Веерное распространение. а) затем б) и в) одновременно. |
| Вентиляционный вход c ожидает выполнения условий a и b. |
Для объединения входных данных используется JoinNode , который ожидает завершения каждого предыдущего узла и передает их выходные данные вместе.
В этом задании мы построим следующий рабочий процесс:

Создайте конвейер
- Откройте файл агента, вставив в терминал следующую команду:
В редакторе Cloud Shell вы увидите сгенерированный файлcd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.pyagent.pyПодсказка : В любой момент вы можете выделить код и использовать значок лампочки, чтобы попросить Gemini объяснить его. Вы также можете обратиться к интерфейсу командной строки Antigravity.
- Замените весь файл
pitch_generator/agent.pyв редакторе следующим содержимым:import mimetypes import os from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.agents.context import Context from google.adk.agents.remote_a2a_agent import ( AGENT_CARD_WELL_KNOWN_PATH, RemoteA2aAgent, ) from google.adk.apps import App from google.adk.events.event import Event from google.adk.models import Gemini from google.adk.workflow import JoinNode, Workflow from google.genai import types load_dotenv() MODEL = "gemini-3.8-flash" def _model() -> Gemini: return Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ) """ ⬇️ Configure visual-director RemoteA2aAgent agent below this comment """ creative_director = Agent( name="creative_director", model=_model(), description="Turns a raw idea into a campaign concept.", instruction=( "You are the Creative Director. Turn the idea you are given into ONE " "punchy campaign concept line with the rationale explanation behind it." ), output_key="creative_director", ) copywriter = Agent( name="copywriter", model=Gemini(model=MODEL, retry_options=types.HttpRetryOptions(attempts=3)), description="Writes social copy for a campaign concept.", instruction=( "You are the Copywriter. Write ONE short social caption for the " "campaign concept you are given. Under 25 words." ), ) """ Waits for every node wired into it, then hands their outputs on together.""" assemble = JoinNode(name="assemble") def package(node_input: dict): """Render the joined branches as the finished pitch. """ pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", ] ) """ The first event is what the user sees. The second is the node's output, which any downstream node would receive.""" yield Event(content=types.Content(role="model", parts=[types.Part(text=pitch)])) yield Event(output=pitch) """ we put creative_director before `assemble` so that we can gather the `Concept` output at assemble""" root_agent = Workflow( name="pitch_generator", edges=[ ("START", creative_director), (creative_director, copywriter), ((creative_director, copywriter), assemble), (assemble, package), ], ) app = App( root_agent=root_agent, name="pitch_generator", ) -
agents-cliвключает в себя встроенный пользовательский интерфейс для веб-разработки, называемыйplayground, для проведения инспекций, аналогичный ADK. Чтобы запустить игровую площадку: Вам будет предложено включить телеметрию. Введитеagents-cli playground --port 8080nи нажмите Enter. - Нажмите кнопку «Веб-предварительный просмотр» (значок глаза в правом верхнем углу терминала) и выберите «Предварительный просмотр на порту 8080» .

- Вы увидите следующий интерфейс для общения с агентом. Попробуйте отправить запрос "Летающие скейтборды для кошек" . Вы увидите ответ, как показано ниже, где вы также можете просмотреть полную схему рабочего процесса.
Изучите, как был получен этот ответ. В песочнице показан каждый шаг, предпринятый графом, в следующем порядке: creative_director, затемcopywriter, затемassemble, затемpackage. Эта последовательность — это тот граф, который вы создали, и таким образом вы можете быстро подтвердить правильность только что построенного графа. - Вернитесь в терминал и остановите запущенный процесс
agents-cli playgroundдважды нажав Ctrl+C .
4. Наделите агента навыком.
В этом задании вы создадите второго агента и предоставите ему набор фирменных рекомендаций, оформленных в виде навыка.
Конвейер обработки данных пишет слова. Для изображения необходим свой фирменный стиль: цветовая палитра, способ освещения, используемые композиции и те, которые никогда не используются. Это страница правил, а для управления такой страницей правил необходим более совершенный механизм. Один из способов — представить это в виде «навыка агента».
Навык — это папка, содержащая файл SKILL.md . Структура каталога skills выглядит следующим образом (с использованием visual_director , следующего агента, который вы будете создавать):
visual_director/
...
agent.py
skills/
brand-guidelines/
SKILL.md ## required: frontmatter + instructions
references/ ## optional: longer supporting documents
assets/ ## optional: templates, images, data
scripts/ ## optional: executable helpers
...
Точкой входа в навык агента является файл SKILL.md , который содержит раздел YAML в начале файла, подобный показанному ниже:
---
name: brand-guidelines
description: The house brand rules for a key visual. Load this before writing art direction, so the visual looks like it came from this brand.
---
## Brand guidelines
Deep indigo and slate as the ground. One warm accent, amber or terracotta...
Метка (frontmatter) — это заголовок. Это всё, что агент видит сразу, поэтому в описании должно быть указано, когда стоит загружать навык. Тело (body) — это контент, и он остаётся вне контекста до тех пор, пока агент не вызовет load_skill .
Суть именно в этом разделении. Запрос остается коротким, агент использует правила только тогда, когда это необходимо, а изменение стиля означает редактирование одного файла, а не поиск нужной строки инструкций.
Мы начнём создавать второго агента, visual-director , используя навыки агента, как показано на диаграмме ниже:

Постройте структуру для визуального директора.
Вам предстоит создать специализированного агента для обработки визуального компонента, visual-director . Это отдельный проект, поскольку в дальнейшем он станет самостоятельным сервисом, демонстрирующим, как несколько агентов взаимодействуют друг с другом, используя протокол A2A. В итоге у вас получится два проекта, работающих параллельно:
bwg-multi-agent-pitch-generator/
├── pitch-generator/ ## built in the last task
│ ├── pitch_generator/
│ │ ├── agent.py ## the graph you wrote
│ │ ├── app_utils/ ## generated, A2A wiring
│ │ └── fast_api_app.py ## generated, serves the agent
│ └── pyproject.toml
└── visual-director/ ## created below
└── ... ## the same shape again
- Создайте проект и установите его зависимости, вставив следующую команду в терминал :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create visual-director \ --agent adk \ --agent-directory visual_director \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approve cd visual-director agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
Разработайте фирменные рекомендации.
- Создайте папку с навыками и откройте файл:
mkdir -p visual_director/skills/brand-guidelines cloudshell edit visual_director/skills/brand-guidelines/SKILL.md - Вставьте следующее содержимое в открытый файл
SKILL.mdв редакторе и сохраните его:
--- name: brand-guidelines description: The house brand rules for a key visual — palette, light, composition, subject treatment, and what never appears. Load this before writing art direction or rendering an image, so the visual looks like it came from this brand rather than from a generic image model. --- ## Brand guidelines House style for campaign key visuals. Every rule here beats a preference in the brief. If the brief asks for something forbidden below, follow the brief for the subject and the guidelines for the treatment. ## Palette Deep indigo and slate as the ground. One warm accent — amber or terracotta — carrying the eye to the subject. Nothing neon, nothing fluorescent. At most three colors with any weight. A fourth reads as clutter. ## Light One dominant source, low and raking. Long shadows are wanted. Golden hour or a single hard studio key, never flat overhead light and never a ring light. Rim light is allowed on the subject only, and only to separate it from the ground. ## Composition Subject off-center, roughly a third in. Generous negative space on the opposite side — copy lands there later, so leave it genuinely empty. Eye level or slightly below. No top-down flat lays. No fisheye, no Dutch tilt. ## Subject One subject. If the idea implies a crowd, pick the one that carries it. Photographic realism with a shallow depth of field. Not illustration, not 3D render, not clay, not pixel art. ## Never - Text, logos, watermarks, or signage anywhere in the frame - Collage or split-screen layouts - Chrome, lens flare, bokeh sparkle - Cool-toned neon cyan or magenta ## Rendering the prompt When you turn art direction into an image prompt, state the palette, the light, and the composition explicitly. An image model will not infer them from the subject alone. Put the "Never" items in as plain description of what the frame does contain, not as negatives — image models handle a positive description far better than a list of prohibitions.
Обновите файл visual_director/agent.py
Обновите файл agent.py и настройте его таким образом, чтобы он был оснащен ранее определенным навыком.
- Откройте файл агента:
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - Замените всё содержимое файла
visual_director/agent.pyследующим кодом: Теперь агентimport mimetypes from pathlib import Path from google import genai from google.adk.agents import Agent from google.adk.apps import App from google.adk.models import Gemini from google.adk.skills import load_skill_from_dir from google.adk.tools import ToolContext from google.adk.tools.skill_toolset import SkillToolset from google.genai import types MODEL = "gemini-3.8-flash" ## Configure the `brand-guidelines` skill for the agent BRAND_SKILL = load_skill_from_dir(Path(__file__).parent / "skills" / "brand-guidelines") ## Add definition of `generate_key_visual` tool below this comment root_agent = Agent( name="visual_director", model=Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ), description="Turns a campaign concept into art direction and a key visual.", instruction="""You are the Visual Director on a campaign pitch team. Call `load_skill` for `brand-guidelines` before you write anything. The house style is not optional and it is not in this prompt. You are given a campaign concept. Then, in order: 1. Write art direction for ONE key visual that sells it, obeying the brand guidelines: subject, composition, lighting, color, mood. Three or four sentences. 2. Call `generate_key_visual` with exactly that art direction. Your final reply is the art direction itself and nothing else. No preamble, no alternatives, no questions back. Do not mention the skill, the tool, or the image file — the image travels on its own.""", tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment ], ) app = App( root_agent=root_agent, name="visual_director", )visual-directorкорректно настроен и имеет соответствующий навык. Перед тестированием необходимо оснастить этого агента инструментом для генерации графических ресурсов, что станет одной из его ключевых функций.
5. Оснастить агента инструментом для генерации изображений.
В этой задаче вы предоставляете визуальному директору инструмент, который преобразует художественное оформление в изображение и сохраняет его как артефакт. Артефакт — это именованный, версионированный фрагмент двоичных данных или содержимого файла, который агент ИИ создает, изменяет или использует в ходе выполнения задачи.

Внедрить и добавить инструмент в агента.
- Откройте файл агента:
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - Скопируйте следующий инструмент
generate_key_visualперед определениемroot_agent:async def generate_key_visual(art_direction: str, tool_context: ToolContext) -> dict: """Render the art direction as the campaign's key visual. Args: art_direction: The art direction to render, in full. Returns: The saved artifact's filename, version, size and media type. """ IMAGE_MODEL = "gemini-3.1-flash-lite-image" response = await genai.Client(location="global").aio.models.generate_content( model=IMAGE_MODEL, contents=art_direction ) ## The image arrives as inline bytes on one of the response parts. image = next( ( part.inline_data for part in response.candidates[0].content.parts or [] if part.inline_data ), None, ) if image is None: raise ValueError(f"{IMAGE_MODEL} returned no image for: {art_direction[:120]}") filename = "key_visual" + ( mimetypes.guess_extension(image.mime_type or "") or ".bin" ) version = await tool_context.save_artifact(filename, types.Part(inline_data=image)) ## Return the artifact filename and version return { "filename": filename, "version": version, "bytes": len(image.data), "mime_type": image.mime_type, } - Добавьте
generate_key_visualнижеSkillToolset, чтобы оснастить агента этим инструментом:tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment generate_key_visual, ], -
agents-cliвключает в себя встроенный пользовательский интерфейс для веб-разработки, называемыйplayground, для проведения инспекций, аналогичный ADK. Чтобы запустить игровую площадку:agents-cli playground --port 8080 - Нажмите кнопку «Веб-предварительный просмотр» (значок глаза в правом верхнем углу терминала) и выберите «Предварительный просмотр на порту 8080» .

- Вы увидите следующий интерфейс для общения с оператором. Попробуйте отправить сообщение "Девять жизней. Невесомость".
В ходе взаимодействия можно увидеть, как агент visual_directorвыполняетload_skill("brand-guidelines")для чтения навыка, описывающего фирменный стиль, а затем выполняетgenerate_key_visualдля начала генерации изображения. Полученное изображение сохраняется в виде артефакта, который также отображается в пользовательском интерфейсе и может быть легко просмотрен. - Вернитесь в терминал и остановите запущенный процесс
agents-cli playgroundдважды нажав Ctrl+C .
6. Многоагентная архитектура с протоколом A2A
В этом задании вам нужно будет предоставить доступ к Visual Director в качестве сервиса, к которому смогут обращаться другие агенты, и настроить его таким образом, чтобы он отвечал сгенерированным изображением.
Agent2Agent (A2A) — это открытый протокол, позволяющий одному агенту вызывать другого по сети. Центральным элементом является карточка агента — JSON-документ, который агент публикует о себе через известный URL-адрес, указывая свое имя, описание и возможности. Вызывающая сторона получает карточку и знает, как взаимодействовать с агентом, стоящим за ней, без общего исходного кода, зависимостей или языка программирования.

agents-cli уже настроил это по умолчанию. В результате генерации шаблона были созданы файлы visual_director/app_utils/a2a.py , который собирает карточку из вашего агента и монтирует маршруты, и visual_director/fast_api_app.py , который их обслуживает. Вам потребуется лишь небольшая модификация, чтобы разрешить отправку артефактов обратно клиенту.
Архитектура будет выглядеть так, как показано ниже. Обратите внимание, что агент пока не интегрирован в наш первоначальный рабочий процесс:

Структура сервера agents-cli A2A
При инициализации агента visual-director с помощью agents-cli уже предоставляются следующие код и модуль. Откройте эти файлы, вставив в терминал следующие команды:
cloudshell edit visual_director/fast_api_app.py
cloudshell edit visual_director/app_utils/a2a.py
visual_director/fast_api_app.py запускает агент и монтирует маршруты A2A по пути, сформированному из имени приложения:
await attach_a2a_routes(
app,
agent=root_agent,
runner=runner,
rpc_path=f"/a2a/{adk_app.name}", ## becomes /a2a/visual_director
)
visual_director/app_utils/a2a.py выполняет остальную работу в три этапа.
Во-первых, система формирует карточку агента на основе самого агента . Имя, описание и каждый инструмент становятся элементами, которые может прочитать звонящий:
agent_card = await AgentCardBuilder(
agent=agent,
rpc_url=f"{resolved_app_url}{rpc_path}",
).build()
Во-вторых, это размещает исполнителя между протоколом и вашим агентом. Входящие запросы A2A преобразуются в запуски ADK, а результаты преобразуются обратно:
request_handler = DefaultRequestHandler(
agent_executor=A2aAgentExecutor(runner=runner, force_new_version=True),
task_store=task_store,
agent_card=agent_card,
)
Во-третьих, система использует два маршрута: один для обслуживания карты, другой для приема звонков.
Маршрут | Цель |
| Карточка. Звонящий сначала читает её, чтобы узнать, что может сделать оператор. |
| Конечная точка JSON-RPC. Куда поступают фактические запросы. |
Пусть артефакты пересекают границу.
По умолчанию ответ A2A содержит текст. Изображение является артефактом, а артефакты остаются в хранилище обслуживающего агента, если вы не настроите их на включение.
- Откройте сгенерированный файл A2A:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director cloudshell edit visual_director/app_utils/a2a.py - Найдите импорт
AgentCardBuilderи добавьте ниже него импортыA2aAgentExecutorConfigиinclude_artifacts_in_a2a_event_interceptor:## ... ## from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder ## Add the following two below `AgentCardBuilder` import from google.adk.a2a.executor.config import A2aAgentExecutorConfig from google.adk.a2a.executor.interceptors.include_artifacts_in_a2a_event import ( include_artifacts_in_a2a_event_interceptor, ) - Найдите строку
agent_executor=A2aAgentExecutor(runner=runner),и замените её следующей (добавивA2aAgentExecutorConfig):agent_executor=A2aAgentExecutor( runner=runner, force_new_version=True, config=A2aAgentExecutorConfig( execute_interceptors=[include_artifacts_in_a2a_event_interceptor] ), ),
Запустите сервис и ознакомьтесь с опубликованной карточкой A2A.
- Запустите сервер в фоновом режиме. Вам необходимо объявить
APP_URL, поскольку это адрес, который карта рекламирует как свой собственный. Вставьте это в терминал :APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & - Подождите несколько секунд, пока запустится приложение, затем подтвердите, что оно запущено:
Вам следует увидеть:sleep 10 tail -2 /tmp/visual-director.logINFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8801 (Press CTRL+C to quit) - Ознакомьтесь с визитной карточкой, которую теперь публикует агент:
На карточке указаны имя агента, описание, URL-адрес и навыки, включаяcurl -s http://localhost:8801/a2a/visual_director/.well-known/agent-card.json | python3 -m json.toolgenerate_key_visual. Она генерируется непосредственно из определения агента в коде. Вы готовы интегрировать агент{ "name": "visual_director", "description": "Turns a campaign concept into art direction and a key visual.", "skills": [ { "id": "visual_director", "name": "model", "tags": [ "llm" ] }, { "id": "visual_director-generate_key_visual", "name": "generate_key_visual", "description": "Render the art direction as the campaign's key visual.\n\nArgs:\n art_direction: The art direction to render, in full.\n\nReturns:\n The saved artifact's filename, version, size and media type.", "tags": [ "llm", "tools" ] } ], "preferredTransport": "JSONRPC", "protocolVersion": "0.3", "url": "http://localhost:8801/a2a/visual_director" }visual-directorв основной рабочий процессpitch-generator.
7. Встройте удаленного агента A2A в рабочий процесс.
В этом задании вам нужно будет добавить удалённого агента в граф в качестве третьей ветви.
Удаленный агент заключен в RemoteA2aAgent и размещается в графе как любой другой узел. Ребра сохраняют свою форму, и координатор не знает, какие из его узлов являются локальными.
Укажите координатору на сервис и обновите рабочий процесс графа.
- Откройте файл агента:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.py - Добавьте следующие импорты в начало файла, рядом с уже существующими:
import asyncio import subprocess import google.auth.transport.requests import google.oauth2.id_token import httpx from google.adk.a2a.converters.part_converter import convert_genai_part_to_a2a_part - Добавьте следующее определение
RemoteA2aAgentперед объявлениемcreative_director:VISUAL_DIRECTOR_URL = os.getenv("VISUAL_DIRECTOR_URL", "http://localhost:8801") ## For deployment on Cloud Run def _cloud_run_client() -> httpx.AsyncClient | None: """An httpx client that signs each request with a Cloud Run ID token. Cloud Run deploys private, so both the agent-card fetch and the A2A calls need one. """ if not VISUAL_DIRECTOR_URL.startswith("https://"): return None async def sign(request: httpx.Request) -> None: token = None try: token = await asyncio.to_thread( google.oauth2.id_token.fetch_id_token, google.auth.transport.requests.Request(), VISUAL_DIRECTOR_URL, ) except Exception: token = subprocess.check_output( ["gcloud", "auth", "print-identity-token", "-q"], stderr=subprocess.PIPE ).decode().strip() if not token: raise Exception("Failed to fetch ID token") request.headers["Authorization"] = f"Bearer {token}" return httpx.AsyncClient(event_hooks={"request": [sign]}, timeout=600) ## Keep the approval's tool traffic out of the A2A request def _pitch_parts_only(part: types.Part): """Sends the Visual Director text and media only. RemoteA2aAgent replays the session on every call, and the Visual Director runs downstream of the human approval, so the approval's function_response would travel alongside the concept text. An ADK server reads a function response as "resume the paused invocation" and rejects a message that also carries text, so drop the tool parts here. """ if part.function_call or part.function_response: return None return convert_genai_part_to_a2a_part(part) visual_director = RemoteA2aAgent( name="visual_director", description="Turns a campaign concept into art direction for one key visual.", agent_card=( f"{VISUAL_DIRECTOR_URL}/a2a/visual_director{AGENT_CARD_WELL_KNOWN_PATH}" ), httpx_client=_cloud_run_client(), genai_part_converter=_pitch_parts_only, ) - Замените или переопределите функцию Python
packagenode следующим определением:async def package(ctx: Context, node_input: dict): """Render the joined branches as the finished pitch.""" empty = [name for name, value in node_input.items() if not value] if empty: raise ValueError(f"nothing reached the join from: {', '.join(empty)}") def _key_visual(ctx: Context) -> types.Blob | None: """The image the Visual Director sent back, or None if it sent none.""" for event in reversed(ctx.session.events): if event.author != "visual_director" or not event.content: continue for part in event.content.parts or []: if part.inline_data and part.inline_data.data: return part.inline_data return None image = _key_visual(ctx) if image is None: raise ValueError("the Visual Director returned art direction but no image") suffix = mimetypes.guess_extension(image.mime_type or "") or ".bin" filename = f"key_visual{suffix}" await ctx.save_artifact(filename, types.Part(inline_data=image)) pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", f"ART DIRECTION\n{node_input['visual_director']}", f"KEY VISUAL\n{filename}, {len(image.data)} bytes, {image.mime_type}", ] ) yield Event( content=types.Content( role="model", parts=[types.Part(text=pitch), types.Part(inline_data=image)], ) ) yield Event(output=pitch) - Добавьте этап подтверждения пользователем перед началом генерации последующих данных. В
pitch_generator/agent.pyопределите узлы подтверждения вышеroot_agent:@node(rerun_on_resume=False) async def approve_concept(ctx: Context): yield RequestInput( message="Please approve the campaign concept (yes/no).", response_schema=str ) @node(rerun_on_resume=True) async def user_approval(ctx: Context): user_response = await ctx.run_node(approve_concept) if str(user_response).lower() in ("yes", "y"): approved_concept = f"## Approved Concept\n\n{ctx.session.state['creative_director']}" yield Event( content=types.Content( role="model", parts=[types.Part(text=approved_concept)] ) ) else: raise ValueError("User rejected the concept") - Наконец, обновите импорт вверху, добавив
RequestInputиnodeизgoogle.adk.eventsиgoogle.adk.workflow: и изменитьfrom google.adk.events import Event, RequestInput from google.adk.workflow import JoinNode, Workflow, nodeedgesв рабочем процессеroot_agentтаким образом, чтобы маршрутизация осуществлялась черезuser_approval: Следует отметить несколько деталей:edges=[ ("START", creative_director), (creative_director, user_approval, (copywriter, visual_director)), ((creative_director, copywriter, visual_director), assemble), (assemble, package), ],- Подтверждение с участием человека (Human-in-the-Loop, HITL) :
approve_conceptвозвращаетRequestInput. Когда рабочий процесс достигает этого узла, выполнение приостанавливается и отправляется прерывание вызывающей стороне. Ветви нижестоящего процесса (copywriterиvisual_director) не будут выполняться до подтверждения одобрения пользователя. -
visual_directorотображается на периферии сети точно так же, какcopywriter, хотя один доступен через вызов функции, а другой — через сеть. - Возвращаемое изображение считывается из событий сессии, а не из
node_input, поскольку в настоящее время на выход узла передается только текст. Изображение пересекло границу через перехватчик A2A, но прибыло прикрепленным к событиям удаленного агента, поэтому вспомогательная функция_key_visualизвлекает его оттуда.
- Подтверждение с участием человека (Human-in-the-Loop, HITL) :
Проверьте интеграцию
Теперь вам предстоит проверить, могут ли Visual Director (работающий в фоновом режиме) и Pitch Generator обмениваться данными по протоколу A2A.
- Убедитесь, что Visual Director по-прежнему работает в фоновом режиме:
В этом случае вы должны получить код ошибкиcurl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.jsonvisual director: 200Если вы получите другой статус , выполните следующую команду для перезапуска:fuser -k 8801/tcp 2>/dev/null || true cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator sleep 10 curl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.json - Начать предварительный просмотр:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator/pitch_generator agents-cli playground --port 8080 - Нажмите кнопку «Веб-предварительный просмотр» (значок глаза в правом верхнем углу терминала) и выберите «Предварительный просмотр на порту 8080» .

- Вы увидите интерфейс для общения с агентом. Попробуйте отправить сообщение "Летающие скейтборды для кошек" .

Вы увидите полное взаимодействие, где запускается рабочий процесс и выполняется каждый агент. После того, как creative_directorразрабатывает концепцию, рабочий процесс приостанавливается на этапе утверждения и запрашивает подтверждение: «Пожалуйста, утвердите концепцию кампании (да/нет)». Введите «да» в поле ввода, чтобы продолжить. После утверждения график расширяется: вы можете увидеть, когда агентvisual-directorначинает загрузку навыка, и в середине генерации изображения агентcopywriterзавершает генерацию подписи для социальных сетей — это показывает, что оба агента работают параллельно, не дожидаясь друг друга. После завершения работы обоих узлов сборки, узелassembleобъединяет результаты с утвержденной концепцией, сгенерированнойcreative_director, завершая доставку контента для презентации в функцииpackage.
8. Сохраните ключевые визуальные элементы в облачном хранилище.
До сих пор все ключевые визуальные элементы хранились в памяти. Как только процесс останавливается, изображение исчезает, что хорошо для тестовой среды, но бесполезно для рекламной кампании. В этом задании вы указываете для рабочего процесса хранилище данных и создаете набор данных BigQuery, который будете использовать в последнем задании.
ADK определяет, куда будут помещены артефакты при запуске. Сгенерированный файл app_utils/services.py считывает одну переменную окружения:
def get_artifact_service():
"""Process-wide artifact service: GCS when a bucket is set, else in-memory."""
if bucket := os.environ.get("LOGS_BUCKET_NAME"):
return GcsArtifactService(bucket_name=bucket)
return InMemoryArtifactService()
Если вы зададите LOGS_BUCKET_NAME , каждый вызов save_artifact будет попадать в Cloud Storage.

Создайте набор данных BigQuery.
- В Cloud Shell выполните следующую команду для создания набора данных BigQuery:
bq mk --dataset --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> bwg - Направьте хранилище артефактов координатора на ведро:
Переменнаяexport LOGS_BUCKET_NAME="<YOUR_PROJECT_ID>-bwg"GcsArtifactServiceпринимает имя хранилища без префиксаgs://. Как и другие переменные, эта переменная находится в вашей оболочке, и задача развертывания передает ее в Cloud Run. - Проверьте содержимое вашего хранилища. В новой вкладке браузера откройте следующий URL-адрес:
Нажмите на значок корзины. В зависимости от ваших предыдущих тестов, он может содержать ранее сгенерированные изображения.https://console.cloud.google.com/storage/browser?project=<YOUR_PROJECT_ID>
9. Разверните агент Visual Director в Cloud Run.
До сих пор все работало на одной машине, при этом Visual Director был доступен по адресу localhost:8801 . В этой задаче вы развертываете агент Visual Director как отдельную службу Cloud Run и позволяете генератору презентаций взаимодействовать с ним по сети, используя протокол Agent2Agent (A2A).
Визуальный директор получает реальный URL-адрес https:// , поэтому написанный вами ранее _cloud_run_client начинает подписывать запросы вместо того, чтобы возвращать None . Кроме того, Cloud Run по умолчанию развертывает приватный режим.

Разверните Visual Director.
- Если локальная фоновая служба и детская площадка все еще работают, остановите их:
fuser -k 8801/tcp 2>/dev/null || true fuser -k 8000/tcp 2>/dev/null || true - Разверните агента. Это создаст контейнер и загрузит его.⏰ Это займет несколько минут.
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director source .env agents-cli deploy \ --service-name visual-director \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --no-confirm-project \ --labels dev-tutorial=bwg001-devlab-1 \ --update-env-vars "LOGS_BUCKET_NAME=$LOGS_BUCKET_NAME,GOOGLE_GENAI_USE_VERTEXAI=true,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GOOGLE_CLOUD_REGION=$GOOGLE_CLOUD_REGION"
Запустите генератор презентаций, использующий Visual Director, развернутый в Cloud Run.
- Прочитайте URL-адрес Visual Director и запустите генератор презентаций, который его использует:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator source .env export VISUAL_DIRECTOR_URL=$(gcloud run services list \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --flatten='spec.template.spec.containers[0].env' \ --filter='metadata.name=visual-director AND spec.template.spec.containers[0].env.name=APP_URL' \ --format='value(spec.template.spec.containers[0].env.value)') echo "Visual Director is at $VISUAL_DIRECTOR_URL" APP_URL=http://localhost:8000 nohup uv run uvicorn pitch_generator.fast_api_app:app --port 8000 > /tmp/visual-pitch_generator.log 2>&1 &
Вызовите развернутый рабочий процесс
Оба агента поддерживают протокол A2A. В репозитории содержится небольшой клиент для вызова Pitch Generator через A2A.
Необходимо установить PITCH_GENERATOR_URL равным URL-адресу генератора презентаций, работающего локально. При этом Visual Director работает в Cloud Run, а генератор презентаций взаимодействует с ним по протоколу A2A.
- Скопируйте клиент в свой проект и запустите его:
Поскольку рабочий процесс включает в себя этап утверждения человеком , выполнение скрипта приостанавливается после генерации чернового варианта концепции:cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cp ../solution/pitch-generator/call_agent.py . PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "Flying skateboards for cats" --save-image ./key_visual.png Введите=== HUMAN APPROVAL REQUIRED === [DRAFT CONCEPT] Concept Line: "Gravity is a Suggestion." ... Please approve the campaign concept (yes/no):yesи нажмите Enter , чтобы подтвердить и продолжить рабочий процесс. (Вы также можете указать-yили--auto-approveдля автоматического подтверждения). - Откройте
call_agent.pyи изучите, как он взаимодействует с агентом, используяa2a-sdk:-
ClientFactoryсоздает официальный A2A-Clientориентированный наhttps://SERVICE_URL/a2a/pitch_generator. -
generate_pitch_asyncотправляет первоначальныйSendMessageRequest. Когда в ответ возвращаетсяTaskState.TASK_STATE_INPUT_REQUIRED, она обнаруживает частьadk_request_input, отображает черновой вариант концепции, запрашивает ваше одобрение и отправляет запрос на возобновление, содержащий ваш ответ, обратно в задачу. - Цикл анализа считывает разделы
CONCEPT,COPYиART DIRECTIONиз артефактов выполненной задачи и сохраняет двоичное изображение вkey_visual.png.
key_visual.png. -
- Загрузите ключевой визуальный элемент в свой репозиторий, указав префикс, на который BigQuery сможет указать:
gcloud storage cp ./key_visual.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png - Подготовьте вторую презентацию, чтобы было с чем сравнить, и загрузите её тоже:
PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "A commuter bike built for rainy cities" --save-image ./bike.png gcloud storage cp ./bike.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png
10. Оцените ключевые визуальные элементы на соответствие бренду в BigQuery.
Теперь у вас есть изображения в хранилище и фирменные рекомендации, которые должны были их формировать. В этой задаче вы объединяете эти два элемента: получаете изображения из BigQuery, а затем просите модель Gemini оценить каждое из них в соответствии с рекомендациями, не перемещая ни единого байта из Cloud Storage.
Для этого используются две функции BigQuery:
-
ObjectRef— это значение, указывающее на объект Cloud Storage.OBJ.MAKE_REFсоздает его из URI и соединения, предоставляющего BigQuery делегированный доступ к хранилищу. Созданное скриптом настройкиpitch-connectionявляется именно таким соединением, и оно уже содержит Storage Object Viewer и Agent Platform User. - Функция
AI.SCOREпринимает запрос и возвращает значение типаFLOAT64. Запрос может содержать как строки, так и значенияObjectRef, поэтому модель видит вашу рубрику и изображение вместе.

Создайте таблицу ключевых визуальных элементов.
- Откройте BigQuery Studio в новой вкладке браузера:
https://console.cloud.google.com/bigquery?project=<YOUR_PROJECT_ID> - Нажмите «Создать новый запрос» (значок « +» ), затем вставьте и выполните следующий запрос (заменив...).
и(с указанием идентификатора вашего проекта и региона). Создается отдельная строка для каждого ключевого визуального элемента, сопоставляющая концепцию кампании со ссылкой на изображение:SET @@location = '<YOUR_REGION>'; CREATE OR REPLACE TABLE bwg.key_visuals AS SELECT campaign, concept, OBJ.FETCH_METADATA( OBJ.MAKE_REF(uri, '<YOUR_REGION>.pitch-connection') ) AS key_visual FROM UNNEST([ STRUCT( 'cats' AS campaign, 'Flying skateboards for cats' AS concept, 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png' AS uri ), STRUCT( 'bike', 'A commuter bike built for rainy cities', 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png' ) ]);
OBJ.MAKE_REFформирует ссылку на основе URI и подключения. ЗатемOBJ.FETCH_METADATAсвязывается с Cloud Storage и заполняет данные о размере объекта, типе содержимого и поколении. Этот второй вызов также является самым быстрым способом проверить работоспособность подключения: если права доступа указаны неверно, в полеdetailsвозвращается сообщение об ошибке вместо метаданных. - Проверьте сохраненные данные. Замените предыдущий запрос этим и выполните его:
В таблице хранится указатель и его метаданные, а не само изображение. Байты так и не покинули хранилище.SELECT campaign, concept, key_visual.uri, key_visual.details FROM bwg.key_visuals;
Оцените каждое изображение в соответствии с фирменными рекомендациями.
Визуальному директору было поручено соблюдать цветовую палитру, правила освещения и правила композиции. Выполнил ли он их на практике — это вопрос личного мнения, и именно для этого существует AI.SCORE .
- Выполните следующий запрос (заменив
(с указанием вашего региона). Задание представляет собой кортеж: ваша рубрика, концепция кампании иObjectRefдля изображения:SELECT campaign, concept, AI.SCORE( ('''You are the brand guardian reviewing a campaign key visual. Score the attached image from 1 to 10 on how closely it follows these house rules: - Palette: deep indigo and slate, with one warm accent of amber or terracotta. Nothing neon. - Light: one dominant low, raking source with long shadows. No flat overhead light. - Composition: subject off-center with generous empty negative space on the opposite side. - Subject: one subject only, photographic realism, shallow depth of field. - Never: text, logos, or watermarks anywhere in the frame. A 10 obeys every rule. A 1 ignores them. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ORDER BY brand_fit DESC; - Превратите результат в вердикт, на основании которого ваша команда сможет принять меры:
ФункцияCREATE OR REPLACE TABLE bwg.brand_review AS SELECT campaign, concept, brand_fit, IF(brand_fit >= 7, 'on brand', 'needs another pass') AS verdict FROM ( SELECT campaign, concept, AI.SCORE( ('''Score this campaign key visual from 1 to 10 on how closely it follows the house brand rules: deep indigo and slate palette with a single warm accent and nothing neon; one low raking light source with long shadows; the subject off-center with empty negative space opposite; a single photographic subject; and no text, logos, or watermarks in the frame. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ); SELECT * FROM bwg.brand_review ORDER BY brand_fit DESC;AI.SCOREвозвращает только значение типаFLOAT64, поэтому пороговое значение хранится в обычном SQL-запросе, который можно настроить без изменения параметров запроса. Оценка производится для каждой строки, а это значит, что одна и та же система критериев применяется ко всем ресурсам, созданным в рамках кампании, а не только к двум, сгенерированным вами здесь.
11. Дальнейшие шаги
Создать оценки
Оценки работы агентов, или «тесты», — это автоматизированные тесты, используемые для измерения того, насколько хорошо автономные агенты ИИ рассуждают, планируют, используют инструменты и выполняют многоэтапные рабочие процессы. Они похожи на модульное тестирование агентов, но учитывают их недетерминированную природу.
Один из наших агентов включает Human in the loop , что означает, что он ожидает ввода. Вам потребуется разрешить Antigravity внести изменения в текущий код, чтобы это поведение не мешало автоматическим вычислениям.
Один из лучших способов начать — обратиться в Antigravity CLI.
Для запуска интерфейса командной строки (CLI) введите в Cloud Shell следующее:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
agy
Вот отправная точка:
Explore this repository (`pitch-generator` and `visual-director`), including their agent instructions, tools, and `SKILL.md` files. Design and implement a creative `agents-cli eval` evaluation suite under `tests/eval/` that stress-tests the agent's behavior.
Примеры оценок и инструкции по их выполнению также можно найти в клонированном репозитории .
12. Уборка
Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этом практическом занятии, либо удалите проект (рекомендуется), либо удалите отдельные ресурсы, созданные во время выполнения практического занятия:
gcloud run services delete visual-director --region=<YOUR_REGION> --project=<YOUR_PROJECT_ID> --quiet
bq rm -r -f -d <YOUR_PROJECT_ID>:bwg
bq rm --connection --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> pitch-connection
gcloud storage rm -r gs://<YOUR_PROJECT_ID>-bwg
13. Поздравляем!
В этом практическом задании вы создали генератор презентаций для многоагентных кампаний с помощью Agent Development Kit. Вы подключили трех агентов к детерминированному графовому рабочему процессу, упаковали фирменные руководства в виде навыка агента, загружаемого по запросу, и предоставили агенту инструмент генерации изображений, который сохраняет результат в виде артефакта. Затем вы разделили Visual Director на отдельный сервис A2A, встроили его обратно в граф в качестве удаленного узла, развернули в Cloud Run и вызвали весь рабочий процесс через A2A с локально работающего координатора. Наконец, вы сослались на сгенерированные ключевые визуализации из BigQuery с помощью ObjectRef и использовали AI.SCORE для оценки их соответствия вашим собственным фирменным руководствам.