1. Введение
В этой лабораторной работе вы выйдете за рамки простых чат-ботов и создадите распределенную многоагентную систему.
Хотя один специалист с дипломом магистра права может ответить на вопросы, в реальных условиях для решения сложных задач часто требуются специализированные роли. Вы же не поручаете бэкенд-разработчику проектировать пользовательский интерфейс, а дизайнеру — оптимизировать запросы к базе данных. Аналогично, мы можем создавать специализированных агентов искусственного интеллекта, которые сосредоточены на одной задаче и координируют свои действия для решения сложных проблем.
Вы разработаете систему создания курсов, состоящую из:
- Агент-исследователь : Использует поиск Google для поиска актуальной информации.
- Эксперт-оценщик : Критическая оценка исследования на предмет качества и полноты.
- Content Builder Agent : Превращение результатов исследования в структурированный курс.
- Агент-оркестратор : Управление рабочим процессом и коммуникацией между этими специалистами.
Что вы узнаете
- Определите агента (исследователя), использующего инструмент и способного осуществлять поиск в интернете.
- Реализуйте структурированный вывод с помощью Pydantic для судьи.
- Подключайтесь к удаленным агентам, используя протокол Agent-to-Agent (A2A).
- Создайте объект LoopAgent для формирования обратной связи между исследователем и судьей.
- Запустите распределенную систему локально, используя ADK.
- Разверните многоагентную систему в Google Cloud Run.
- Используйте модель Gemma на графическом процессоре Cloud Run в качестве агента для создания контента.
Что вам понадобится
- Веб-браузер, например Chrome.
- Проект Google Cloud с включенной функцией выставления счетов.
2. Принципы архитектуры и оркестровки
Для начала давайте разберемся, как эти агенты взаимодействуют друг с другом. Мы создаем конвейер создания курсов .
Проектирование системы

Организация работы с агентами
Стандартные агенты (например, исследователь) работают. Агенты-оркестраторы (например, LoopAgent или SequentialAgent ) управляют другими агентами. У них нет собственных инструментов; их «инструмент» — делегирование.
-
LoopAgent: Этот класс работает как циклwhileв коде. Он запускает последовательность агентов многократно, пока не будет выполнено условие (или не будет достигнуто максимальное количество итераций). Мы используем его для цикла исследований :- Исследователь находит информацию.
- Судья дает ему критику.
- Если Judge выдает "Fail", EscalationChecker позволяет циклу продолжиться.
- Если судья говорит «Пройдено», то EscalationChecker прерывает цикл.
-
SequentialAgent: Это работает как стандартное выполнение скрипта. Он запускает агенты один за другим. Мы используем это для высокоуровневого конвейера :- Сначала запустите цикл исследования (пока он не завершится получением корректных данных).
- Затем запустите конструктор контента (для создания курса).
Сочетая эти элементы, мы создаем надежную систему, способную к самокоррекции перед формированием окончательного результата.
3. Настройка
Настройка проекта
Создайте проект в Google Cloud.
- В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud .
- Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта .
Запустить Cloud Shell
Cloud Shell — это среда командной строки, работающая в Google Cloud и поставляемая с предустановленными необходимыми инструментами.
- В верхней части консоли Google Cloud нажмите кнопку «Активировать Cloud Shell» .
- После подключения к Cloud Shell подтвердите свою аутентификацию:
gcloud auth list - Убедитесь, что ваш проект настроен:
gcloud config get project - Если параметры вашего проекта заданы не так, как ожидалось, настройте их следующим образом:
export PROJECT_ID=<YOUR_PROJECT_ID> gcloud config set project $PROJECT_ID
Настройка среды
- Откройте Cloud Shell : нажмите значок «Активировать Cloud Shell» в правом верхнем углу консоли Google Cloud.
Получите стартовый код
- Клонируйте стартовый репозиторий в свою домашнюю директорию: Перейдите в свою домашнюю директорию
Скопируйте только тот код, который необходим для этого практического занятия, из папки Google Cloud DevRel Demos .cd ~ Перейдите в папку, содержащую код для этого Codelab.git clone --depth 1 --filter=blob:none --sparse https://github.com/GoogleCloudPlatform/devrel-demos.git temp-repo && cd temp-repo && git sparse-checkout set agents/multi-agent-system && cd .. && mv temp-repo/agents/multi-agent-system . && rm -rf temp-repocd multi-agent-system - Включение API : выполните следующую команду, чтобы включить необходимые сервисы Google Cloud:
gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ aiplatform.googleapis.com \ compute.googleapis.com - Откройте эту папку в вашем редакторе.
cloudshell edit .
Настройка среды
- Настройте переменные окружения. Мы создадим файл
.envдля хранения этих переменных, чтобы вы могли легко перезагрузить их, если ваша сессия прервется.cat <<EOF > .env export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) export GOOGLE_CLOUD_LOCATION=europe-west4 export GOOGLE_GENAI_USE_VERTEXAI=true EOF - Укажите переменные среды:
source .env
4. 🕵️ Агент-исследователь

Исследователь — это специалист. Его единственная задача — находить информацию. Для этого ему необходим инструмент: поиск Google.
Зачем отделять исследователя?
Подробный анализ: Почему бы не поручить все задачи одному агенту?
Небольшие, узкоспециализированные агенты проще оценивать и отлаживать . Если исследование проведено плохо, вы продолжаете работу над заданием исследователя. Если форматирование курса плохое, вы продолжаете работу над конструктором контента. В монолитном, универсальном задании исправление одной проблемы часто приводит к поломке другой.
- Если вы работаете в Cloud Shell, выполните следующую команду, чтобы открыть редактор Cloud Shell:
cloudshell workspace . - Откройте файл
agents/researcher/agent.py. - Просмотрите следующий код, определяющий агента-
researcher:# ... existing imports ... # Define the Researcher Agent researcher = Agent( name="researcher", model=MODEL, description="Gathers information on a topic using Google Search.", instruction=""" You are an expert researcher. Your goal is to find comprehensive and accurate information on the user's topic. Use the `google_search` tool to find relevant information. Summarize your findings clearly. If you receive feedback that your research is insufficient, use the feedback to refine your next search. """, tools=[google_search], ) root_agent = researcher
Ключевая концепция: Использование инструментов
Обратите внимание, что мы передаем tools=[google_search] . ADK берет на себя сложность описания этого инструмента для LLM. Когда модель решает, что ей нужна информация, она генерирует структурированный вызов инструмента, ADK выполняет функцию Python google_search и передает результат обратно модели.
5. ⚖️ Агент-судья

Исследователь усердно работает, а магистранты могут быть ленивыми. Нам нужен судья для проверки работы. Судья принимает исследование и выставляет структурированную оценку «зачет/незачет».
Структурированный вывод
Подробный анализ: Для автоматизации рабочих процессов нам необходимы предсказуемые результаты. Сложный текстовый обзор сложно программно обработать. Используя схему JSON (с помощью Pydantic), мы гарантируем, что Judge вернет логическое значение « pass или fail , на основе которого наш код сможет надежно реагировать.
- Откройте файл
agents/judge/agent.py. - Ознакомьтесь с приведенным ниже кодом, определяющим схему
JudgeFeedbackи агентаjudge.# 1. Define the Schema class JudgeFeedback(BaseModel): """Structured feedback from the Judge agent.""" status: Literal["pass", "fail"] = Field( description="Whether the research is sufficient ('pass') or needs more work ('fail')." ) feedback: str = Field( description="Detailed feedback on what is missing. If 'pass', a brief confirmation." ) # 2. Define the Agent judge = Agent( name="judge", model=MODEL, description="Evaluates research findings for completeness and accuracy.", instruction=""" You are a strict editor. Evaluate the 'research_findings' against the user's original request. If the findings are missing key info, return status='fail'. If they are comprehensive, return status='pass'. """, output_schema=JudgeFeedback, # Disallow delegation because it should only output the schema disallow_transfer_to_parent=True, disallow_transfer_to_peers=True, ) root_agent = judge
Ключевая концепция: Ограничивающее поведение агента
Мы установили disallow_transfer_to_parent=True и disallow_transfer_to_peers=True . Это заставляет Judge возвращать только структурированный JudgeFeedback . Он не может решить, «общаться» ли с пользователем в чате или делегировать задачу другому агенту. Это делает его детерминированным компонентом в нашей логической схеме.
6. ✍️ Агент для создания контента

Content Builder — это креативный автор. Он берет утвержденные исследования и превращает их в курс. В нем используется модель Gemma, предоставляемая Cloud Run.
Давайте сначала рассмотрим сервис Cloud Run, который размещает модель.
- Откройте файл
ollama_backend/Dockerfile - Здесь вы можете увидеть, как Dockerfile использует образ Ollama, прослушивает запросы на порту 8080 и сохраняет запрошенную модель в папке /model.
FROM ollama/ollama:latest # Listen on all interfaces, port 8080 (Cloud Run default) ENV OLLAMA_HOST 0.0.0.0:8080 # Store model weight files in /models ENV OLLAMA_MODELS /models
⚙️ При развертывании вам потребуется установить следующие параметры:
- Графический процессор : NVIDIA L4 выбран за отличное соотношение цены и производительности для задач инференции. L4 предоставляет 24 ГБ памяти GPU и оптимизированные операции с тензорами, что делает его идеальным для моделей с 270 миллионами параметров, таких как Gemma.
- Память : 16 ГБ системной памяти для обработки загрузки моделей, операций CUDA и управления памятью Ollama.
- Процессор : 8 ядер для оптимальной обработки операций ввода-вывода и задач предварительной обработки.
- Параллелизм : 4 запроса на экземпляр обеспечивают баланс между пропускной способностью и использованием памяти графического процессора.
- Тайм-аут : 600 секунд — это время, необходимое для первоначальной загрузки модели и запуска контейнера.
Теперь давайте рассмотрим агент Content Builder, использующий модель Gemma.
- Откройте файл
agents/content_builder/agent.py. - Просмотрите следующий код, определяющий агент
content_builder.
# the `ollama-gemma-gpu` Cloud Run service URL which hosts the Gemma model
target_url = os.environ.get("OLLAMA_API_BASE")
# ... existing code ...
# (Note: We use 'ollama/gemma3:270m' to align with ADK's expected prefix)
gemma_model_name = os.environ.get("GEMMA_MODEL_NAME", "gemma3:270m")
model = LiteLlm(
model=f"ollama_chat/{gemma_model_name}",
api_base=target_url
)
# 5. Define the Agent
content_builder = Agent(
name="content_builder",
model=model,
description="Transforms research findings into a structured course.",
instruction="""
You are an expert course creator.
Take the approved 'research_findings' and transform them into a well-structured, engaging course module.
**Formatting Rules:**
1. Start with a main title using a single `#` (H1).
2. Use `##` (H2) for main section headings. These will be used for the Table of Contents.
3. Use `###` (H3) for sub-sections within main sections.
4. Use bullet points and clear paragraphs.
5. Maintain a professional but engaging tone.
**Structure Requirements:**
- Begin with a brief Introduction section explaining what the learner will gain.
- Organize content into 3-5 main sections with clear headings.
- Include Key Takeaways at the end as a bulleted summary.
- Keep each section focused and concise.
Ensure the content directly addresses the user's original request.
Do not include any preamble or explanation outside the course content itself.
""",
)
root_agent = content_builder
Ключевая концепция: Распространение контекста
Вы можете задаться вопросом: «Откуда Content Builder узнает, что обнаружил Researcher?» В ADK агенты в конвейере совместно используют session.state . Позже, в Orchestrator, мы настроим Researcher и Judge так, чтобы они сохраняли свои результаты в это общее состояние. Запрос Content Builder фактически имеет доступ к этой истории.
7. 🎻 Оркестратор

Оркестратор — это руководитель нашей многоагентной команды. В отличие от агентов-специалистов (Исследователь, Судья, Контент-менеджер), выполняющих конкретные задачи, работа Оркестратора заключается в координации рабочего процесса и обеспечении корректного обмена информацией между ними.
🌐 Архитектура: взаимодействие между агентами (A2A)

В этой лабораторной работе мы создаём распределённую систему . Вместо запуска всех агентов в одном процессе Python, мы развертываем их как независимые микросервисы. Это позволяет каждому агенту масштабироваться независимо и выходить из строя без сбоя всей системы.
Для этого мы используем протокол «агент-агент» (A2A) .
Протокол A2A
Подробное описание: В производственной системе агенты работают на разных серверах (или даже в разных облаках). Протокол A2A создает стандартный способ для них обнаруживать друг друга и взаимодействовать по протоколу HTTP. RemoteA2aAgent — это ADK-клиент для этого протокола.
- Откройте файл
agents/orchestrator/agent.py. - Проанализируйте следующий код, определяющий соединения.
# ... existing code ... # Connect to the Researcher (Localhost port 8001) researcher_url = os.environ.get("RESEARCHER_AGENT_CARD_URL", "http://localhost:8001/a2a/agent/.well-known/agent-card.json") researcher = RemoteA2aAgent( name="researcher", agent_card=researcher_url, description="Gathers information using Google Search.", # IMPORTANT: Save the output to state for the Judge to see after_agent_callback=create_save_output_callback("research_findings"), # IMPORTANT: Use authenticated client for communication httpx_client=create_authenticated_client(researcher_url) ) # Connect to the Judge (Localhost port 8002) judge_url = os.environ.get("JUDGE_AGENT_CARD_URL", "http://localhost:8002/a2a/agent/.well-known/agent-card.json") judge = RemoteA2aAgent( name="judge", agent_card=judge_url, description="Evaluates research.", after_agent_callback=create_save_output_callback("judge_feedback"), httpx_client=create_authenticated_client(judge_url) ) # Content Builder (Localhost port 8003) content_builder_url = os.environ.get("CONTENT_BUILDER_AGENT_CARD_URL", "http://localhost:8003/a2a/agent/.well-known/agent-card.json") content_builder = RemoteA2aAgent( name="content_builder", agent_card=content_builder_url, description="Builds the course.", httpx_client=create_authenticated_client(content_builder_url) )
8. 🛑 Проверка эскалации
Для завершения цикла необходим способ его остановки. Если судья выдает «Пройдено», мы хотим немедленно выйти из цикла и перейти к конструктору контента.
Пользовательская логика с использованием BaseAgent
Подробный анализ: Не все агенты используют LLM. Иногда требуется простая логика на Python. BaseAgent позволяет определить агента, который просто выполняет код. В этом случае мы проверяем состояние сессии и используем EventActions(escalate=True) чтобы дать сигнал LoopAgent остановиться.
- Все еще в файле
agents/orchestrator/agent.py. - Просмотрите следующий код, он анализирует замечания судьи и переходит к следующему шагу, когда будет готов.
class EscalationChecker(BaseAgent): """Checks the judge's feedback and escalates (breaks the loop) if it passed.""" async def _run_async_impl( self, ctx: InvocationContext ) -> AsyncGenerator[Event, None]: # Retrieve the feedback saved by the Judge feedback = ctx.session.state.get("judge_feedback") print(f"[EscalationChecker] Feedback: {feedback}") # Check for 'pass' status is_pass = False if isinstance(feedback, dict) and feedback.get("status") == "pass": is_pass = True # Handle string fallback if JSON parsing failed elif isinstance(feedback, str) and '"status": "pass"' in feedback: is_pass = True if is_pass: # 'escalate=True' tells the parent LoopAgent to stop looping yield Event(author=self.name, actions=EventActions(escalate=True)) else: # Continue the loop yield Event(author=self.name) escalation_checker = EscalationChecker(name="escalation_checker")
Ключевая концепция: управление потоком выполнения посредством событий.
Агенты общаются не только с помощью текста, но и с помощью событий . Отправив событие с escalate=True , этот агент посылает сигнал своему родительскому объекту ( LoopAgent ). LoopAgent запрограммирован на перехват этого сигнала и завершение цикла.
9. 🔁 Исследовательский цикл

Нам необходима обратная связь: Исследование -> Оценка -> (Неудача) -> Исследование -> ...
- В
agents/orchestrator/agent.py. - Просмотрите, как следующий код определяет функцию
research_loop.research_loop = LoopAgent( name="research_loop", description="Iteratively researches and judges until quality standards are met.", sub_agents=[researcher, judge, escalation_checker], max_iterations=3, )
Ключевая концепция: LoopAgent
LoopAgent последовательно перебирает своих sub_agents .
-
researcher: Находит данные. -
judge: Оценивает данные. -
escalation_checker: Определяет, следует лиyield Event(escalate=True). Если выполняетсяescalate=True, цикл прерывается досрочно. В противном случае он перезапускается с исследователя (доmax_iterations).
10. 🔗 Финальный трубопровод

Подводя итог всему...
- В
agents/orchestrator/agent.py. - Проверьте, как определяется
root_agentв нижней части файла.root_agent = SequentialAgent( name="course_creation_pipeline", description="A pipeline that researches a topic and then builds a course from it.", sub_agents=[research_loop, content_builder], )
Ключевая концепция: Иерархическая композиция
Обратите внимание, что research_loop сам по себе является агентом ( LoopAgent ). Мы рассматриваем его так же, как и любого другого подагента в SequentialAgent . Такая компонуемость позволяет строить сложную логику, вкладывая простые шаблоны (циклы внутри последовательностей, последовательности внутри маршрутизаторов и т. д.).
11. 🚀 Развертывание в Cloud Run
Мы развернем каждого агента как отдельную службу в Cloud Run, включая службу Cloud Run для пользовательского интерфейса создания курса и службу Cloud Run с использованием графических процессоров для модели Gemma.
Понимание конфигурации развертывания
При развертывании агентов в Cloud Run мы передаем несколько переменных среды для настройки их поведения и подключения:
-
GOOGLE_CLOUD_PROJECT: Гарантирует, что агент использует правильный проект Google Cloud для логирования и вызовов Vertex AI. -
GOOGLE_GENAI_USE_VERTEXAI: Указывает фреймворку агентов (ADK) использовать Vertex AI для вывода модели вместо прямого вызова API Gemini. -
[AGENT]_AGENT_CARD_URL: Этот параметр крайне важен для оркестратора. Он указывает оркестратору, где найти удаленных агентов. Установив его на развернутый URL-адрес Cloud Run (в частности, путь к карточке агента), мы позволяем оркестратору обнаруживать и взаимодействовать с исследователем, судьей и создателем контента через Интернет.
Для развертывания всех агентов в сервисах Cloud Run выполните следующий скрипт.
Во-первых, убедитесь, что скрипт является исполняемым.
chmod u+x ~/multi-agent-system/deploy.sh
Примечание: выполнение этой операции займет несколько минут, поскольку каждая служба развертывается последовательно.
~/multi-agent-system/deploy.sh
12. Создайте курс!
Откройте веб-сайт Course Creator. Сервис Course Creator Cloud Run — последний сервис, развернутый из скрипта. Вы можете определить URL-адрес конструктора курсов как https://course-creator- , которая должна быть последней строкой вывода скрипта развертывания.
И введите название курса, например, "линейная алгебра".
Ваши агенты начнут работу над вашим курсом.

13. Уборка
Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этом практическом задании, выполните следующие шаги для удаления ваших сервисов и образов контейнеров.
1. Удалите службы Cloud Run.
Наиболее эффективный способ очистки — удалить службы, развернутые в Cloud Run.
# Delete the main agent and app services
gcloud run services delete researcher content-builder judge orchestrator course-creator \
--region $REGION --quiet
# Delete the GPU backend (Ollama)
gcloud run services delete ollama-gemma-gpu \
--region $OLLAMA_REGION --quiet
2. Удалите образы артефактов реестра.
При использовании флага --source для развертывания Google Cloud создал репозиторий в реестре артефактов для хранения образов контейнеров. Чтобы удалить эти репозитории и сэкономить на хранении, удалите сам репозиторий:
gcloud artifacts repositories delete cloud-run-source-deploy --location us-east4 --quiet
3. Удалите локальные файлы и окружение.
Чтобы поддерживать чистоту среды Cloud Shell, удалите папку проекта и все локальные конфигурационные файлы:
cd ~
rm -rf multi-agent-system
4. (Необязательно) Удалить проект
Если вы создали проект специально для этого практического занятия, вы можете предотвратить дальнейшее выставление счетов, отключив сам проект через страницу «Управление ресурсами» .
14. Поздравляем!
Вы успешно создали и развернули готовую к производственному использованию распределенную многоагентную систему.
Ваши достижения
- Разложили сложную задачу на составляющие : вместо одного большого задания мы разделили работу на специализированные роли (исследователь, судья, разработчик контента).
- Внедрен контроль качества : Мы использовали
LoopAgentи структурированныйJudge, чтобы гарантировать, что на заключительный этап поступает только высококачественная информация. - Создано для продакшена : Используя протокол Agent-to-Agent (A2A) и Cloud Run , мы создали систему, в которой каждый агент представляет собой независимый, масштабируемый микросервис. Это гораздо надежнее, чем запускать все в одном скрипте Python.
- Оркестрация : Мы использовали
SequentialAgentиLoopAgentдля определения четких шаблонов управления потоком выполнения. *. Графические процессоры для облачных вычислений : Модель Gemma была развернута на графическом процессоре для облачных вычислений.