Создание многоагентной системы

1. Введение

В этой лабораторной работе вы выйдете за рамки простых чат-ботов и создадите распределенную многоагентную систему.

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

Вы разработаете систему создания курсов, состоящую из:

  • Агент-исследователь : Использует поиск Google для поиска актуальной информации.
  • Эксперт-оценщик : Критическая оценка исследования на предмет качества и полноты.
  • Content Builder Agent : Превращение результатов исследования в структурированный курс.
  • Агент-оркестратор : Управление рабочим процессом и коммуникацией между этими специалистами.

Что вы узнаете

  • Определите агента (исследователя), использующего инструмент и способного осуществлять поиск в интернете.
  • Реализуйте структурированный вывод с помощью Pydantic для судьи.
  • Подключайтесь к удаленным агентам, используя протокол Agent-to-Agent (A2A).
  • Создайте объект LoopAgent для формирования обратной связи между исследователем и судьей.
  • Запустите распределенную систему локально, используя ADK.
  • Разверните многоагентную систему в Google Cloud Run.
  • Используйте модель Gemma на графическом процессоре Cloud Run в качестве агента для создания контента.

Что вам понадобится

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

2. Принципы архитектуры и оркестровки

Для начала давайте разберемся, как эти агенты взаимодействуют друг с другом. Мы создаем конвейер создания курсов .

Проектирование системы

Архитектурная схема

Организация работы с агентами

Стандартные агенты (например, исследователь) работают. Агенты-оркестраторы (например, LoopAgent или SequentialAgent ) управляют другими агентами. У них нет собственных инструментов; их «инструмент» — делегирование.

  1. LoopAgent : Этот класс работает как цикл while в коде. Он запускает последовательность агентов многократно, пока не будет выполнено условие (или не будет достигнуто максимальное количество итераций). Мы используем его для цикла исследований :
    • Исследователь находит информацию.
    • Судья дает ему критику.
    • Если Judge выдает "Fail", EscalationChecker позволяет циклу продолжиться.
    • Если судья говорит «Пройдено», то EscalationChecker прерывает цикл.
  2. SequentialAgent : Это работает как стандартное выполнение скрипта. Он запускает агенты один за другим. Мы используем это для высокоуровневого конвейера :
    • Сначала запустите цикл исследования (пока он не завершится получением корректных данных).
    • Затем запустите конструктор контента (для создания курса).

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

3. Настройка

Настройка проекта

Создайте проект в Google Cloud.

  1. В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud .
  2. Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта .

Запустить Cloud Shell

Cloud Shell — это среда командной строки, работающая в Google Cloud и поставляемая с предустановленными необходимыми инструментами.

  1. В верхней части консоли Google Cloud нажмите кнопку «Активировать Cloud Shell» .
  2. После подключения к Cloud Shell подтвердите свою аутентификацию:
    gcloud auth list
    
  3. Убедитесь, что ваш проект настроен:
    gcloud config get project
    
  4. Если параметры вашего проекта заданы не так, как ожидалось, настройте их следующим образом:
    export PROJECT_ID=<YOUR_PROJECT_ID>
    gcloud config set project $PROJECT_ID
    

Настройка среды

  1. Откройте Cloud Shell : нажмите значок «Активировать Cloud Shell» в правом верхнем углу консоли Google Cloud.

Получите стартовый код

  1. Клонируйте стартовый репозиторий в свою домашнюю директорию: Перейдите в свою домашнюю директорию
      cd ~
    
    Скопируйте только тот код, который необходим для этого практического занятия, из папки Google Cloud DevRel Demos .
    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-repo
    
    Перейдите в папку, содержащую код для этого Codelab.
    cd multi-agent-system
    
  2. Включение API : выполните следующую команду, чтобы включить необходимые сервисы Google Cloud:
    gcloud services enable \
        run.googleapis.com \
        artifactregistry.googleapis.com \
        cloudbuild.googleapis.com \
        aiplatform.googleapis.com \
        compute.googleapis.com
    
  3. Откройте эту папку в вашем редакторе.
    cloudshell edit .
    

Настройка среды

  1. Настройте переменные окружения. Мы создадим файл .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
    
  2. Укажите переменные среды:
    source .env
    

4. 🕵️ Агент-исследователь

Исследовательский агент

Исследователь — это специалист. Его единственная задача — находить информацию. Для этого ему необходим инструмент: поиск Google.

Зачем отделять исследователя?

Подробный анализ: Почему бы не поручить все задачи одному агенту?

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

  1. Если вы работаете в Cloud Shell, выполните следующую команду, чтобы открыть редактор Cloud Shell:
    cloudshell workspace .
    
  2. Откройте файл agents/researcher/agent.py .
  3. Просмотрите следующий код, определяющий агента- 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 , на основе которого наш код сможет надежно реагировать.

  1. Откройте файл agents/judge/agent.py .
  2. Ознакомьтесь с приведенным ниже кодом, определяющим схему 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, который размещает модель.

  1. Откройте файл ollama_backend/Dockerfile
  2. Здесь вы можете увидеть, как 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.

  1. Откройте файл agents/content_builder/agent.py .
  2. Просмотрите следующий код, определяющий агент 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)

Архитектура A2A

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

Для этого мы используем протокол «агент-агент» (A2A) .

Протокол A2A

Подробное описание: В производственной системе агенты работают на разных серверах (или даже в разных облаках). Протокол A2A создает стандартный способ для них обнаруживать друг друга и взаимодействовать по протоколу HTTP. RemoteA2aAgent — это ADK-клиент для этого протокола.

  1. Откройте файл agents/orchestrator/agent.py .
  2. Проанализируйте следующий код, определяющий соединения.
    # ... 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 остановиться.

  1. Все еще в файле agents/orchestrator/agent.py .
  2. Просмотрите следующий код, он анализирует замечания судьи и переходит к следующему шагу, когда будет готов.
    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. 🔁 Исследовательский цикл

Исследовательский цикл

Нам необходима обратная связь: Исследование -> Оценка -> (Неудача) -> Исследование -> ...

  1. В agents/orchestrator/agent.py .
  2. Просмотрите, как следующий код определяет функцию 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 .

  1. researcher : Находит данные.
  2. judge : Оценивает данные.
  3. escalation_checker : Определяет, следует ли yield Event(escalate=True) . Если выполняется escalate=True , цикл прерывается досрочно. В противном случае он перезапускается с исследователя (до max_iterations ).

10. 🔗 Финальный трубопровод

Финальный трубопровод

Подводя итог всему...

  1. В agents/orchestrator/agent.py .
  2. Проверьте, как определяется 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- . .run.app , которая должна быть последней строкой вывода скрипта развертывания.

И введите название курса, например, "линейная алгебра".

Ваши агенты начнут работу над вашим курсом.

Финальный трубопровод

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 была развернута на графическом процессоре для облачных вычислений.