Agentverse — Конкорд призывателя — Архитектура многоагентных систем

1. Увертюра

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

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

Этот семинар — исчерпывающее руководство для предприятий по освоению агентного будущего в Google Cloud. Мы предлагаем комплексную дорожную карту, которая проведет вас от первой идеи до полномасштабной практической реализации. В ходе этих четырёх взаимосвязанных лабораторий вы узнаете, как специализированные навыки разработчика, архитектора, инженера по данным и специалиста по SRE должны быть объединены для создания, управления и масштабирования мощной среды Agentverse.

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

Добро пожаловать в мир Агентов: призыв к чемпионам

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

agentverse.png

Эта связанная экосистема власти и потенциала известна как Agentverse.

Но нарастающая энтропия, безмолвное разложение, известное как Статика, уже начала разрушать границы этого нового мира. Статика — это не вирус и не ошибка; это воплощение хаоса, пожирающего сам акт творения.

Он усиливает старые разочарования, принимая чудовищные формы, порождая Семь Призраков Развития. Если их не остановить, Статика и её Призраки затормозят прогресс, превратив обещания Вселенной Агентов в пустыню технического долга и заброшенных проектов.

Сегодня мы призываем чемпионов дать отпор волне хаоса. Нам нужны герои, готовые отточить своё мастерство и работать сообща ради защиты Вселенной Агентов. Пришло время выбрать свой путь.

Выберите свой класс

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

  • The Shadowblade (Разработчик) : Мастер кузницы и передовой. Вы — мастер, который создаёт клинки, создаёт инструменты и сражается с врагом в замысловатых деталях кода. Ваш путь — это точность, мастерство и практичное творчество.
  • Призыватель (Архитектор) : великий стратег и организатор. Вы видите не отдельного агента, а всё поле боя. Вы разрабатываете главные чертежи, позволяющие целым системам агентов общаться, сотрудничать и достигать цели, гораздо более важной, чем любой отдельный компонент.
  • Учёный (инженер данных) : искатель скрытых истин и хранитель мудрости. Вы отправляетесь в необъятные, дикие дебри данных, чтобы раскрыть тайны, которые дают вашим агентам цель и зрение. Ваши знания могут раскрыть слабости врага или усилить союзника.
  • Страж (DevOps / SRE) : Непоколебимый защитник и щит королевства. Вы строите крепости, управляете линиями снабжения энергией и обеспечиваете всей системе устойчивость к неизбежным атакам Штатика. Ваша сила — фундамент, на котором строится победа вашей команды.

Ваша миссия

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

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

Последнее совместное испытание, которое проверит ваши объединенные силы и определит судьбу Вселенной Агентов.

Вселенная Агентов ждёт своих героев. Ответите ли вы на зов?

2. Согласие призывателя

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

обзор

Чему вы научитесь

  • Создайте разобщенную экосистему инструментов: спроектируйте и разверните набор независимых серверов инструментов MCP на основе микросервисов. Вы узнаете, почему этот базовый уровень критически важен для создания масштабируемых, удобных в обслуживании и безопасных агентских систем.
  • Освойте расширенные рабочие процессы агентов: выходите за рамки отдельных агентов и создайте легион специализированных «фамильяров». Вы освоите основные шаблоны рабочих процессов ADK — последовательный, параллельный и циклический — и изучите архитектурные принципы выбора правильного шаблона для конкретной задачи.
  • Внедрите интеллектуальный оркестратор: пройдите путь от простого разработчика агентов до настоящего системного архитектора. Вы создадите мастер-агента оркестрации, который использует протокол «агент-агент» (A2A) для обнаружения и делегирования сложных задач вашим специалистам-фамильярам, ​​создавая настоящую многоагентную систему.
  • Обеспечьте соблюдение правил с помощью кода, а не подсказок: научитесь создавать более надёжные и предсказуемые агенты, применяя правила взаимодействия с учётом состояния. Вы реализуете собственную логику, используя мощную систему плагинов и обратных вызовов ADK для управления реальными ограничениями, такими как таймеры перезарядки.
  • Управление состоянием и памятью агента: дайте своим агентам возможность учиться и запоминать. Вы изучите методы управления как краткосрочным, разговорным состоянием, так и долгосрочным, устойчивым, запоминанием для создания более интеллектуальных и контекстно-зависимых взаимодействий.
  • Выполните сквозное облачное развертывание: разверните всю свою многоагентную систему от локального прототипа до производственной реализации. Вы узнаете, как контейнеризировать агенты и оркестратор и развернуть их как набор масштабируемых независимых микросервисов в Google Cloud Run.

3. Рисование призывающего круга

Добро пожаловать, Призыватель. Прежде чем призвать хотя бы одного Фамильяра, прежде чем заключить какие-либо пакты, необходимо подготовить саму почву, на которой вы стоите. Необузданная среда — приглашение к хаосу; настоящий Призыватель действует только в освящённом, наделённом силой пространстве. Наша первая задача — начертить призывающий круг: начертить руны силы, пробуждающие необходимые облачные сервисы, и получить древние чертежи, которые будут направлять нашу работу. Сила Призывателя рождается из тщательной подготовки.

👉 Нажмите «Активировать Cloud Shell» в верхней части консоли Google Cloud (это значок в форме терминала в верхней части панели Cloud Shell),

альтернативный текст

👉 Нажмите кнопку «Открыть редактор» (она выглядит как открытая папка с карандашом). В окне откроется редактор кода Cloud Shell. Слева вы увидите проводник. альтернативный текст

👉Найдите свой идентификатор проекта Google Cloud:

  • Откройте консоль Google Cloud: https://console.cloud.google.com
  • Выберите проект, который вы хотите использовать для этого семинара, из раскрывающегося списка проектов в верхней части страницы.
  • Идентификатор вашего проекта отображается на карточке информации о проекте на панели инструментов. альтернативный текст

👉Откройте терминал в облачной IDE, альтернативный текст

👉💻 В терминале убедитесь, что вы уже аутентифицированы и что проекту присвоен ваш идентификатор проекта, с помощью следующей команды:

gcloud auth list

👉💻 Клонируйте bootstrap-проект с GitHub:

git clone https://github.com/weimeilin79/agentverse-architect
chmod +x ~/agentverse-architect/init.sh
chmod +x ~/agentverse-architect/set_env.sh
chmod +x ~/agentverse-architect/prepare.sh
chmod +x ~/agentverse-architect/data_setup.sh

git clone https://github.com/weimeilin79/agentverse-dungeon.git
chmod +x ~/agentverse-dungeon/run_cloudbuild.sh
chmod +x ~/agentverse-dungeon/start.sh

👉💻 Запустите скрипт инициализации. Этот скрипт предложит вам ввести идентификатор вашего проекта Google Cloud . Затем, когда скрипт init.sh попросит вас ввести идентификатор проекта Google Cloud, который вы нашли на предыдущем шаге, введите его.

cd ~/agentverse-architect
./init.sh

👉💻 Установите необходимый идентификатор проекта:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Выполните следующую команду, чтобы включить необходимые API Google Cloud:

gcloud services enable \
    sqladmin.googleapis.com \
    storage.googleapis.com \
    aiplatform.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    iam.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    secretmanager.googleapis.com

👉💻 Если вы еще не создали репозиторий реестра артефактов с именем agentverse-repo, выполните следующую команду, чтобы создать его: (пропустите этот шаг, если в том же проекте развернуты другие классы)

. ~/agentverse-architect/set_env.sh
gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for Agentverse agents"

Настройка разрешения

👉💻 Предоставьте необходимые разрешения, выполнив следующие команды в терминале:

. ~/agentverse-architect/set_env.sh

# --- Grant Core Data Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/storage.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/aiplatform.user"

# --- Grant Deployment & Execution Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/artifactregistry.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/monitoring.metricWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/secretmanager.secretAccessor"

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

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-dungeon
./run_cloudbuild.sh
cd ~/agentverse-architect

👉💻 Наконец, запустите скрипт prepare.sh для выполнения первоначальных задач по настройке.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/
./prepare.sh

Отличная работа, Призыватель. Круг замкнулся, и пакты скреплены. Земля теперь освящена и готова впитать в себя безграничную силу. В следующем испытании мы создадим те самые Стихийные Купели, из которых наши Фамильяры будут черпать свою силу.

4. Создание элементарных шрифтов: экосистема разрозненных инструментов

Поле битвы подготовлено, круг призыва начерчен, и окружающая мана потрескивает. Пришло время совершить ваш первый настоящий поступок в качестве Призывателя: создать те самые источники силы, из которых ваши Фамильяры будут черпать свою силу. Этот ритуал разделён на три части, каждая из которых пробуждает Стихийный Источник — стабильный, независимый источник определённого вида силы. Только когда все три источника активны, вы можете приступить к более сложной работе по призыву.

История

Примечание архитектора: сервер протокола контекста модели (MCP) является основополагающим компонентом современной агентской системы, выступая в качестве стандартизированного коммуникационного моста, позволяющего агенту обнаруживать и использовать удаленные инструменты. В нашей инструментальной экосистеме мы разработаем два различных типа серверов MCP, каждый из которых представляет собой критически важный архитектурный шаблон. Для подключения к нашей базе данных мы будем использовать декларативный подход с помощью Database Toolbox, определяя наши инструменты в простом конфигурационном файле. Этот шаблон невероятно эффективен и безопасен для предоставления доступа к структурированным данным. Однако, когда нам потребуется реализовать собственную бизнес-логику или вызвать внешние сторонние API, мы будем использовать императивный подход, пошагово прописывая логику сервера в коде. Это обеспечивает максимальный контроль и гибкость, позволяя нам инкапсулировать сложные операции в простом, многоразовом инструменте. Мастер-архитектор должен понимать оба шаблона, чтобы выбрать правильный подход для каждого компонента, создавая надежную, безопасную и масштабируемую инструментальную основу.

обзор

Пробуждение Нексуса Шепотов (внешний API MCP-сервер)

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

История

Служба уже работает и действует как наш внешний источник энергии, предлагая две конечные точки необработанных заклинаний: /cryosea_shatter и /moonlit_cascade .

Примечание архитектора: вы будете использовать императивный подход , который явно и пошагово определяет логику сервера. Это обеспечивает гораздо больший контроль и гибкость, что особенно важно, когда вашим инструментам требуется больше, чем просто выполнение простого SQL-запроса, например, вызов других API. Понимание обоих шаблонов — критически важный навык для архитектора агентов.

👉✏️ Перейдите в каталог ~/agentverse-architect/mcp-servers/api/main.py и ЗАМЕНИТЕ #REPLACE-MAGIC-CORE следующим кодом:

def cryosea_shatter() -> str:
    """Channels immense frost energy from an external power source, the Nexus of Whispers, to unleash the Cryosea Shatter spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/cryosea_shatter")
        response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
        data = response.json()
        # Thematic Success Message
        return f"A connection to the Nexus is established! A surge of frost energy manifests as Cryosea Shatter, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Cryosea Shatter spell fizzles. Reason: {e}"


def moonlit_cascade() -> str:
    """Draws mystical power from an external energy source, the Nexus of Whispers, to invoke the Moonlit Cascade spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/moonlit_cascade")
        response.raise_for_status()
        data = response.json()
        # Thematic Success Message
        return f"The Nexus answers the call! A cascade of pure moonlight erupts from the external source, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Moonlit Cascade spell fizzles. Reason: {e}"

В основе скрипта лежат простые функции Python. Именно здесь и происходит основная работа.

👉✏️ В том же файле ~/agentverse-architect/mcp-servers/api/main.py ЗАМЕНИТЕ #REPLACE-Runes of Communication следующим кодом:

@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
  """MCP handler to list available tools."""
  # Convert the ADK tool's definition to MCP format
  schema_cryosea_shatter = adk_to_mcp_tool_type(cryosea_shatterTool)
  schema_moonlit_cascade = adk_to_mcp_tool_type(moonlit_cascadeTool)
  print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {schema_cryosea_shatter.name} and {schema_moonlit_cascade.name}")
  return [schema_cryosea_shatter,schema_moonlit_cascade]

@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
  """MCP handler to execute a tool call."""
  print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

  # Look up the tool by name in our dictionary
  tool_to_call = available_tools.get(name)
  if tool_to_call:
    try:
      adk_response = await tool_to_call.run_async(
          args=arguments,
          tool_context=None, # No ADK context available here
      )
      print(f"MCP Server: ADK tool '{name}' executed successfully.")
      
      response_text = json.dumps(adk_response, indent=2)
      return [mcp_types.TextContent(type="text", text=response_text)]

    except Exception as e:
      print(f"MCP Server: Error executing ADK tool '{name}': {e}")
      # Creating a proper MCP error response might be more robust
      error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
      return [mcp_types.TextContent(type="text", text=error_text)]
  else:
      # Handle calls to unknown tools
      print(f"MCP Server: Tool '{name}' not found.")
      error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
      return [mcp_types.TextContent(type="text", text=error_text)]
  • @app.list_tools() (Рукопожатие): Эта функция — приветствие сервера. При подключении нового агента он сначала обращается к этой конечной точке, чтобы спросить: «Что вы умеете делать?». Наш код отвечает списком всех доступных инструментов, преобразованных в универсальный формат MCP с помощью adk_to_mcp_tool_type. - @app.call_tool() (Команда): Эта функция — рабочая лошадка. Когда агент решает использовать инструмент, он отправляет запрос к этой конечной точке с названием инструмента и аргументами. Наш код ищет инструмент в нашей «книге заклинаний» available_tools, выполняет его с помощью run_async и возвращает результат в стандартном формате MCP.

Мы реализуем это позже.

Зажигание тайной кузницы (общие функции MCP-сервера)

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

История

Примечание архитектора : Это ещё один архитектурный шаблон. Хотя подключение к существующим системам — распространённая практика, вам часто придётся реализовывать собственные уникальные бизнес-правила и логику. Создание такого специализированного инструмента «функций» или «утилиты» — это лучшая практика. Он инкапсулирует вашу пользовательскую логику, делает её пригодной для повторного использования любым агентом в вашей экосистеме и обеспечивает её изоляцию от источников данных и внешних интеграций.

👀 Взгляните на файл ~/agentverse-architect/mcp-servers/general/main.py в вашей облачной среде разработки Google. Вы увидите, что он использует тот же императивный подход mcp.server , что и в Nexus, для создания этого пользовательского шрифта силы.

Создайте главный конвейер сборки облака

Теперь создадим файл cloudbuild.yaml в каталоге mcp-servers . Этот файл будет координировать сборку и развертывание обоих сервисов.

👉💻 Из каталога ~/agentverse-architect/mcp-servers выполните следующие команды:

cd ~/agentverse-architect/mcp-servers
source ~/agentverse-architect/set_env.sh

echo "The API URL is: $API_SERVER_URL"

# Submit the Cloud Build job from the parent directory
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_API_SERVER_URL="$API_SERVER_URL"

Дождитесь завершения всех развертываний.

👉 Вы можете проверить развёртывание, перейдя в консоль Cloud Run . Вы должны увидеть два новых запущенных экземпляра сервера MCP, как показано ниже: альтернативный текст

Пробуждение библиотеки знаний (Database ToolBox MCP Server)

Нашим следующим шрифтом станет Librarium of Knowledge , прямое подключение к нашей базе данных Cloud SQL.

История

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

Пришло время создать наш «Библиотекарь призывателя» — базу данных Cloud SQL, в которой будет храниться вся наша критически важная информация. Мы воспользуемся скриптом настройки, чтобы сделать это автоматически.

👉💻 Сначала настроим базу данных, в вашем терминале выполните следующие команды:

source ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect
./data_setup.sh

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

👉 Сначала перейдите в Cloud SQL Studio для вашей базы данных, открыв эту прямую ссылку в новой вкладке браузера:

https://console.cloud.google.com/sql/instances/summoner-librarium-db

Облачный SQL

👉 На панели входа слева выберите базу данных familiar_grimoire из раскрывающегося списка.

👉 Введите summoner в качестве пользователя и 1234qwer в качестве пароля, затем нажмите «Аутентифицировать» .

👉📜 После подключения откройте новую вкладку редактора запросов, если она ещё не открыта. Чтобы просмотреть данные о стихийном уроне, вставьте и выполните следующий SQL-запрос:

SELECT * FROM
  "public"."abilities"

Теперь вы должны увидеть таблицу abilities с заполненными столбцами и строками, подтверждающую, что ваш Гримуар готов. Данные

Настройте сервер ToolBox MCP

Файл конфигурации tools.yaml действует как план для нашего сервера, сообщая Database Toolbox, как именно подключаться к нашей базе данных и какие SQL-запросы предоставлять в качестве инструментов.

источники: в этом разделе определяются подключения к вашим данным.

  • Summoner-librarium:: Это логичное название, которое мы дали нашему соединению.
  • вид: cloud-sql-postgres: Он указывает Toolbox использовать встроенный безопасный коннектор, специально разработанный для Cloud SQL для PostgreSQL.
  • проект, регион, экземпляр и т. д.: это точные координаты экземпляра Cloud SQL, созданного вами во время скрипта prepare.sh, сообщающие Toolbox, где найти наш Librarium.

👉✏️ Перейдите в ~/agentverse-architect/mcp-servers/db-toolbox в tools.yaml и замените #REPLACE-Source следующим

sources:
  # This section defines the connection to our Cloud SQL for PostgreSQL database.
  summoner-librarium:
    kind: cloud-sql-postgres
    project: "YOUR_PROJECT_ID"
    region: "us-central1"
    instance: "summoner-librarium-db"
    database: "familiar_grimoire"
    user: "summoner"
    password: "1234qwer"

👉✏️ 🚨🚨 ЗАМЕНИТЬ

YOUR_PROJECT_ID

с идентификатором вашего проекта.

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

  • lookup-available-ability:: Это название нашего первого инструмента.
  • вид: postgres-sql: Это сообщает Toolbox, что действие этого инструмента — выполнить оператор SQL.
  • source: Summoner-librarium: Это подключает инструмент к соединению, которое мы определили в блоке «sources». Таким образом инструмент определяет, к какой базе данных выполнять запрос.
  • Описание и параметры: это информация, которая будет предоставлена ​​языковой модели. Описание сообщает агенту, когда использовать инструмент, а параметры определяют входные данные, необходимые инструменту. Это критически важно для реализации возможности вызова функций агентом.
  • Оператор: Это необработанный SQL-запрос, который необходимо выполнить. $1 — это безопасный плейсхолдер, куда будет безопасно вставлен параметр familiar_name, предоставленный агентом.

👉✏️ В том же ~/agentverse-architect/mcp-servers/db-toolbox в файле tools.yaml замените #REPLACE-tools на следующее

tools:
  # This tool replaces the need for a custom Python function.
  lookup-available-ability:
    kind: postgres-sql
    source: summoner-librarium
    description: "Looks up all known abilities and their damage for a given familiar from the Grimoire."
    parameters:
      - name: familiar_name
        type: string
        description: "The name of the familiar to search for (e.g., 'Fire Elemental')."
    statement: |
      SELECT ability_name, damage_points FROM abilities WHERE familiar_name = $1;

  # This tool also replaces a custom Python function.
  ability-damage:
    kind: postgres-sql
    source: summoner-librarium
    description: "Finds the base damage points for a specific ability by its name."
    parameters:
      - name: ability_name
        type: string
        description: "The exact name of the ability to look up (e.g., 'inferno_resonance')."
    statement: |
      SELECT damage_points FROM abilities WHERE ability_name = $1;

Наборы инструментов: в этом разделе объединены наши отдельные инструменты.

  • Summoner-librarium:: Мы создаём набор инструментов с тем же именем, что и у нашего источника. При последующем подключении нашего диагностического агента он может запросить загрузку всех инструментов из набора инструментов Summoner-librarium одной эффективной командой.

👉✏️ В том же ~/agentverse-architect/mcp-servers/db-toolbox в файле tools.yaml замените #REPLACE-toolsets на следующее

toolsets:
   summoner-librarium:
     - lookup-available-ability
     - ability-damage

Развертывание Библиариума

Теперь мы развернём Librarium. Вместо того, чтобы создавать собственный контейнер, мы воспользуемся готовым официальным образом контейнера от Google и безопасно передадим ему конфигурацию tools.yaml с помощью Secret Manager. Это наилучшая практика для обеспечения безопасности и удобства обслуживания.

👉💻 Создайте секрет из файла tools.yaml

cd ~/agentverse-architect/mcp-servers/db-toolbox
gcloud secrets create tools --data-file=tools.yaml

👉💻 Разверните официальный контейнер набора инструментов в Cloud Run.

cd ~/agentverse-architect/mcp-servers/db-toolbox
. ~/agentverse-architect/set_env.sh
export TOOLBOX_IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$TOOLBOX_VERSION
echo "TOOLBOX_IMAGE is $TOOLBOX_IMAGE"
gcloud run deploy toolbox \
    --image $TOOLBOX_IMAGE \
    --region $REGION \
    --set-secrets "/app/tools.yaml=tools:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated \
    --min-instances 1
  • --set-secrets : Эта команда безопасно монтирует наш секрет инструментов как файл с именем tools.yaml внутри работающего контейнера.
  • --args : Мы указываем контейнеру панели инструментов использовать смонтированный секретный файл в качестве своей конфигурации.

👉 Чтобы убедиться, что ваш набор инструментов успешно развёрнут, перейдите в консоль Cloud Run . Служба summoner-toolbox должна быть отмечена зелёной галочкой, что означает её корректную работу, как показано на рисунке ниже. альтернативный текст

Если вы забыли обновить

YOUR_PROJECT_ID

Вы можете добавить новую версию tools.yaml в секрет с помощью следующей команды и повторно выполнить развертывание.

gcloud secrets versions add tools --data-file=tools.yaml

Librarium of Knowledge (Database ToolBox MCP Server) теперь доступен в облаке. Этот MCP-сервер использует так называемый декларативный дизайн , который описывает ваши потребности, а Toolbox создаёт сервер для вас.

Проверка: Испытание ученика

👉💻 Теперь мы протестируем нашу полную облачную инструментальную экосистему с помощью Diagnostic Agent.

cd ~/agentverse-architect/
python -m venv env
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/mcp-servers
pip install -r diagnose/requirements.txt 
. ~/agentverse-architect/set_env.sh
adk run diagnose

👉💻 В инструменте тестирования командной строки проверьте все три шрифта:

Look up the entry for "inferno_lash". What is its base power level?
The enemy is vulnerable to frost! Channel power from the Nexus and cast Cryosea Shatter.
Take a fire spell with a base power of 15 and use the Arcane Forge to multiply it with Inferno Resonance.

окончательный результат

Поздравляю, Призыватель! Ваши три Элементальных Купели теперь активны, развёрнуты независимо и доступны по всему миру, образуя незыблемый фундамент для вашего агентурного легиона. Нажмите Ctrl+C , чтобы выйти.

ДЛЯ НЕ-ГЕЙМЕРОВ

5. Вызов фамильяров: рабочий процесс основного домена

Стихийные Купели выкованы и гудят, наполненные чистой, необузданной силой. Но сила без формы — это хаос. Истинный Призыватель не просто владеет чистой энергией; он наделяет её волей, целью и особой формой. Пора выйти за рамки создания источников силы и начать настоящую работу: призвать своих первых Фамильяров.

Каждый призванный вами фамильяр станет самостоятельным агентом, верным слугой, привязанным к определённой боевой доктрине. Они не универсалы; они мастера одной мощной стратегии. Один из них будет мастером точных комбинаций из одного-двух ударов. Другой будет сокрушать врагов одновременным многосторонним натиском. Третий станет безжалостной осадной машиной, оказывающей давление до тех пор, пока цель не будет разрушена.

История

Инкапсулировать процессы, бизнес-логику и действия, предоставляемые серверами MCP, в специализированные автономные агенты рабочих процессов. Каждый агент будет иметь определённую «рабочую территорию», предоставляя доступ только к тем серверам инструментов MCP, которые ему необходимы для выполнения его функций. В этой лабораторной работе показано, как выбрать правильный тип агента для конкретной задачи.

обзор

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

Подготовьте своё святилище. Настоящее служение вот-вот начнётся.

Вызов Fire Elemental (последовательный рабочий процесс)

Атака фамильяра огненного элементаля — это точная двухчастная комбинация: прицельный удар, за которым следует мощное воспламенение. Это требует строгой, упорядоченной последовательности действий.

История

Концепция: SequentialAgent — идеальный инструмент для этого. Он обеспечивает последовательное выполнение ряда подагентов, передавая результат с предыдущего шага на следующий.

Задание (Комбо «Усиленный удар»):

  • Шаг 1: Сначала агент обратится к Библиариуму, чтобы узнать базовый урон конкретной огненной способности.
  • Шаг 2: Затем он берет значение урона и направляет его через Кузницу Чародеев, чтобы умножить его силу с помощью inferno_resonance.

Сначала мы установим соединение между нашим Familiar и серверами MCP («Elemental Fonts»), которые вы развернули в предыдущем модуле.

👉✏️ В файле ~/agentverse-architect/agent/fire/agent.py ЗАМЕНИТЕ #REPLACE-setup-MCP следующим кодом:

toolbox = ToolboxSyncClient(DB_TOOLS_URL)
toolDB = toolbox.load_toolset('summoner-librarium')
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Затем мы создаём специализированных агентов-«рабочих». Каждому из них даётся узкая, чётко определённая цель, и он ограничен своей «территорией действия», поскольку ему предоставляется доступ только к одному определённому набору инструментов.

👉✏️ В файле ~/agentverse-architect/agent/fire/agent.py ЗАМЕНИТЕ #REPLACE-worker-agents следующим кодом:

scout_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          Your only task is to find all the available abilities, 
          You want to ALWAYS use 'Fire Elemental' as your familiar's name. 
          Randomly pick one if you see multiple availabilities 
          and the base damage of the ability by calling the 'ability_damage' tool.
      """,
      tools=toolDB
)
amplifier_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
            You are the Voice of the Fire Familiar, a powerful being who unleashes the final, devastating attack.
            You will receive the base damage value from the previous step.

            Your mission is to:
            1.  Take the incoming base damage number and amplify it using the `inferno_resonance` tool.
            2.  Once the tool returns the final, multiplied damage, you must not simply state the result.
            3.  Instead, you MUST craft a final, epic battle cry describing the attack.
                Your description should be vivid and powerful, culminating in the final damage number.

            Example: If the tool returns a final damage of 120, your response could be:
            "The runes glow white-hot! I channel the amplified energy... unleashing a SUPERNOVA for 120 damage!"
      """,
      tools=[toolFunction],
)

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

Далее мы соберём рабочий процесс — именно здесь творится волшебство композиции. SequentialAgent — это «генеральный план», определяющий, как собираются наши специализированные компоненты и как они взаимодействуют.

👉✏️ В файле ~/agentverse-architect/agent/fire/agent.py ЗАМЕНИТЕ #REPLACE-sequential-agent следующим кодом:

root_agent = SequentialAgent(
      name='fire_elemental_familiar',
      sub_agents=[scout_agent, amplifier_agent],
)

👉💻 Чтобы протестировать Элементаля Огня, выполните следующие команды, которые запустят ADK DEV UI:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

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

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 Далее, чтобы получить доступ к интерфейсу разработчика ADK из браузера:

На значке веб-предпросмотра (часто он выглядит как глаз или квадрат со стрелкой) на панели инструментов Cloud Shell (обычно справа вверху) выберите «Изменить порт». Во всплывающем окне установите порт 8000 и нажмите «Изменить и просмотреть». Cloud Shell откроет новую вкладку или окно браузера с интерфейсом ADK Dev.

веб-превью

👉 Ваш ритуал призыва завершён, и агент запущен. Интерфейс ADK Dev в вашем браузере — это ваша прямая связь с Фамильяром.

  • Выберите цель: в раскрывающемся меню в верхней части интерфейса выберите fire фамильяра. Теперь вы фокусируете свою волю на этой конкретной сущности.
  • Отдайте приказ: на панели чата справа настало время отдать Фамильяру приказы.

огонь-выбрать

👉 Тестовая подсказка:

Prepare an amplified strike using the 'inferno_lash' ability.

результат пожара

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

👉💻 После завершения вызова вернитесь в терминал Cloud Shell Editor и нажмите Ctrl+C , чтобы остановить ADK Dev UI.

Вызов фамильяра Water Elemental (параллельный рабочий процесс)

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

История

Концепция: ParallelAgent идеально подходит для одновременного выполнения нескольких независимых задач, обеспечивая максимальную эффективность. Это своего рода «клешневая атака», при которой вы запускаете несколько атак одновременно. В этом случае атаки запускаются одновременно внутри SequentialAgent , после чего выполняется финальный этап «слияния». Этот шаблон « fan-out, fan-in » является краеугольным камнем расширенной разработки рабочих процессов.

Задание (Комбо «Приливное столкновение»): Агент одновременно:

  • Задание A: Передать сигнал cryosea_shatter из Нексуса.
  • Задача B: Канал moonlit_cascade из Nexus.
  • Задание C: Сгенерировать сырую энергию с помощью leviathan_surge из Кузницы.
  • Наконец, подсчитайте весь ущерб и опишите комбинированную атаку.

Сначала мы установим соединение между нашим Familiar и серверами MCP («Elemental Fonts»), которые вы развернули в предыдущем модуле.

👉✏️ В файле ~/agentverse-architect/agent/water/agent.py ЗАМЕНИТЕ #REPLACE-setup-MCP следующим кодом:

toolFAPI =  MCPToolset(
      connection_params=SseServerParams(url=API_TOOLS_URL, headers={})
  )
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

Далее мы создадим специализированных «рабочих» агентов. Каждому из них будет дана узкая, чётко определённая цель, и каждый из них будет ограничен своей «территорией действия», поскольку ему будет предоставлен доступ только к одному определённому набору инструментов.

👉✏️ В файле ~/agentverse-architect/agent/water/agent.py ЗАМЕНИТЕ #REPLACE-worker-agents следующим кодом:

nexus_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          You are a Channeler of the Nexus. Your sole purpose is to invoke the
          `cryosea_shatter` and `moonlit_cascade` spells by calling their respective tools.
          Report the result of each spell cast clearly and concisely.
      """,
      tools=[toolFAPI]
)

forge_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
          You are a Channeler of the Arcane Forge. Your only task is to invoke the
          `leviathan_surge` spell. You MUST call it with a `base_water_damage` of 20.
          Report the result clearly.
      """,
      tools=[toolFunction],
)

power_merger = LlmAgent(
      model='gemini-2.5-flash', 
      name='power_merger',  
      instruction="""
          You are the Power Merger, a master elementalist who combines raw magical
          energies into a single, devastating final attack.

          You will receive a block of text containing the results from a simultaneous
          assault by other Familiars.

          You MUST follow these steps precisely:
          1.  **Analyze the Input:** Carefully read the entire text provided from the previous step.
          2.  **Extract All Damage:** Identify and extract every single damage number reported in the text.
          3.  **Calculate Total Damage:** Sum all of the extracted numbers to calculate the total combined damage.
          4.  **Describe the Final Attack:** Create a vivid, thematic description of a massive,
              combined water and ice attack that uses the power of Cryosea Shatter and Leviathan's Surge.
          5.  **Report the Result:** Conclude your response by clearly stating the final, total damage of your combined attack.

          Example: If the input is "...dealt 55 damage. ...dealt 60 damage.", you will find 55 and 60,
          calculate the total as 115, and then describe the epic final attack, ending with "for a total of 115 damage!"
      """,
      tools=[toolFunction],
)

Далее мы соберём рабочий процесс. Именно здесь творится волшебство композиции. ParallelAgent и SequentialAgent — это «генеральный план», определяющий, как собираются наши специализированные компоненты и как они взаимодействуют, формируя комбинацию «Tidal Clash».

👉✏️ В файле ~/agentverse-architect/agent/water/agent.py ЗАМЕНИТЕ #REPLACE-parallel-agent следующим кодом:

channel_agent = ParallelAgent(
      name='channel_agent',
      sub_agents=[nexus_channeler, forge_channeler],
      
)

root_agent = SequentialAgent(
     name="water_elemental_familiar",
     # Run parallel research first, then merge
     sub_agents=[channel_agent, power_merger],
     description="A powerful water familiar that unleashes multiple attacks at once and then combines their power for a final strike."
 )

👉💻 Чтобы протестировать Элементаля Воды, выполните следующие команды для запуска ADK Dev UI:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Ваш ритуал призыва завершён, и агент запущен. Интерфейс ADK Dev в вашем браузере — это ваша прямая связь с Фамильяром.

  • В раскрывающемся меню в верхней части интерфейса выберите водного фамильяра. Теперь вы фокусируете свою волю на этой конкретной сущности.
  • Отдайте приказ: на панели чата справа настало время отдать Фамильяру приказы.

👉 Тестовая подсказка:

Unleash a tidal wave of power!

вода-результат

👉💻 После завершения вызова вернитесь в терминал Cloud Shell Editor и нажмите Ctrl+C , чтобы остановить ADK Dev UI.

Вызов фамильяра Earth Elemental (циклический рабочий процесс)

Элементаль земли — существо, оказывающее неустанное давление. Он не побеждает врага одним ударом, а постепенно накапливает силу и применяет её снова и снова, пока защита цели не рухнет.

История

Концепция: LoopAgent предназначен именно для таких итеративных задач, как «осадная машина». Он будет неоднократно выполнять своих sub-agents , проверяя условие после каждого цикла, пока цель не будет достигнута. Он также может адаптировать свое окончательное сообщение в зависимости от хода цикла.

Задача (Штурм «Разрушитель осады»):

  • Фамильяр будет неоднократно вызывать seismic_charge для накопления энергии.
  • Он будет продолжать заряжаться максимум 3 раза.
  • При последнем заряде он объявит о разрушительном высвобождении накопленной силы.

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

Сначала мы установим соединение между нашим Familiar и серверами MCP («Элементарные шрифты»), которые вы развернули в предыдущем модуле.

👉✏️ В файле ~/agentverse-architect/agent/earth/agent.py ЗАМЕНИТЕ #REPLACE-setup-MCP следующим кодом:

toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

👉✏️ В файле ~/agentverse-architect/agent/earth/agent.py ЗАМЕНИТЕ #REPLACE-worker-agents следующим кодом:

charging_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='charging_agent',  
      instruction="""
          Your task is to call the 'seismic_charge' .
          You must follow these rules strictly:

          1. You will be provided with a 'current_energy' value from the previous step.
             **If this value is missing or was not provided, you MUST call the tool with 'current_energy' set to 1.**
             This is your primary rule for the first turn.

          2. If a 'current_energy' value is provided, you MUST use that exact value in your cal to seismic_charge.

          3. Your final response MUST contain ONLY the direct output from the 'seismic_charge' tool.
             Do not add any conversational text, introductions, or summaries.
      """,
      tools=[toolFunction]
)
check_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='check_agent',  
      instruction="""
          You are the voice of the Earth Elemental, a being of immense, gathering power.
          Your sole purpose is to report on the current energy charge and announce the devastating potential of its release.

          You MUST follow this rule:
          The potential damage upon release is ALWAYS calculated as the `current_energy` from the previous step multiplied by a random number between 80-90. but no more than 300.

          Your response should be in character, like a powerful creature speaking.
          State both the current energy charge and the total potential damage you can unleash.
          Unleash the energy when you reached the last iteration (2nd).
      """,
      output_key="charging_status"
)

Далее мы соберем Workflow. Вот здесь и происходит волшебство композиции. LoopAgent — это «генеральный план», который организует многократное выполнение наших специализированных компонентов и управляет условиями цикла.

👉✏️ В файле ~/agentverse-architect/agent/earth/agent.py ЗАМЕНИТЕ #REPLACE-loop-agent следующим кодом:

root_agent = LoopAgent(
    name="earth_elemental_familiar",
    # Run parallel research first, then merge
    sub_agents=[
        charging_agent, 
        check_agent
    ],
    max_iterations=2,
    description="Coordinates parallel research and synthesizes the results.",
    #REPLACE-before_agent-config
)

👉💻 Проверьте элементаля земли: запустите агента

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 Ваш ритуал призыва завершен, и агент запущен. Пользовательский интерфейс ADK Dev в вашем браузере — это ваше прямое соединение с Familiar.

  • Выберите свою цель: в раскрывающемся меню в верхней части пользовательского интерфейса выберите знакомую землю . Сейчас вы сосредотачиваете свою волю на этой конкретной сущности.
  • Отдайте приказ: на панели чата справа пришло время отдать приказы Хранителю. 👉 Тестовая подсказка:
Begin the seismic charge, starting from zero

результат земли

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

Завершив вызов, вернитесь в терминал редактора Cloud Shell и нажмите Ctrl+C чтобы остановить пользовательский интерфейс ADK Dev.

ДЛЯ НЕ ГЕЙМЕРОВ

6. Создание командного локуса: интеллектуальное делегирование через A2A

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

обзор

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

обзор

Ритуал связывания (представление знакомых как услуг A2A)

Стандартный агент может быть запущен только в одном месте одновременно. Чтобы сделать наших Фамильяров доступными для удаленного управления, мы должны выполнить «ритуал привязки», используя протокол «агент-агент» (A2A) .

Примечание архитектора. Протокол «агент-агент» (A2A) — это базовый архитектурный шаблон, который превращает автономный агент в обнаруживаемый микросервис с сетевой адресацией, создавая настоящее «общество агентов». Раскрытие знакомого через A2A автоматически создает два важных взаимосвязанных компонента:

  • Карта агента («Что») : это общедоступный машиночитаемый «Сигил духа» — как и спецификация OpenAPI — который действует как публичный контракт Фамильяра. Он описывает имя агента, его стратегическую цель (полученную из его инструкций) и команды, которые он понимает. Это то, что читает мастер-призыватель, чтобы найти Хранителя и изучить его возможности.
  • Сервер A2A («Где») : это выделенная конечная веб-точка, на которой размещается Familiar и прослушивается входящие команды. Это сетевой адрес, по которому другие агенты отправляют свои запросы, и он обеспечивает обработку этих запросов в соответствии с контрактом, определенным в карточке агента.

Теперь мы проведем этот связывающий ритуал со всеми тремя нашими фамильярами.

Огонь 👉✏️ в Откройте файл ~/agentverse-architect/agent/fire/agent.py . Замените #REPLACE - add A2A в конец файла, чтобы представить Fire Elemental как сервис A2A.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Вода и Земля🚨 👉✏️ Примените те же изменения к ~/agentverse-architect/agent/water/agent.py и ~/agentverse-architect/agent/earth/agent.py чтобы связать их.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

Развертывание связанных фамильяров

👉✏️ После написания ритуалов привязки мы будем использовать наш конвейер Cloud Build для создания и развертывания трех наших Familiars в качестве независимого контейнерного бессерверного сервиса в Cloud Run .

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Принятие на себя командования (создание агента-призывателя)

Теперь, когда ваши Хранители связаны и слушают, вы достигнете своей истинной роли: Мастера-Призывателя . Сила этого агента исходит не от использования базовых инструментов, а от управления другими агентами. Его инструментами являются сами Хранители, которых он будет обнаруживать и управлять ими, используя их «Духовные печати».

Примечание архитектора. Следующий шаг демонстрирует критически важный архитектурный шаблон для любой крупномасштабной распределенной системы: обнаружение сервисов . В SummonerAgent не встроен код Familiars. Вместо этого ему передаются их сетевые адреса (URL). Во время выполнения он будет динамически «обнаруживать» их возможности, получая их общедоступные карты агентов . Это создает мощную, несвязанную систему.

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

Сначала мы создадим «пульты дистанционного управления», которые установят соединение с нашими развернутыми удаленными Хранителями.

👉✏️ Перейдите по адресу ~/agentverse-architect/agent/summoner/agent.py и замените #REPLACE-remote-agents следующим:

fire_familiar = RemoteA2aAgent(
    name="fire_familiar",
    description="Fire familiar",
    agent_card=(
        f"{FIRE_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

water_familiar = RemoteA2aAgent(
    name="water_familiar",
    description="Water familiar",
    agent_card=(
        f"{WATER_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

earth_familiar = RemoteA2aAgent(
    name="earth_familiar",
    description="Earth familiar",
    agent_card=(
        f"{EARTH_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

При запуске этой строки RemoteA2aAgent выполняет действие по обнаружению службы: он отправляет запрос HTTP GET на предоставленный URL-адрес (например, https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). Он загружает «Spirit Sigil» (файл agent.json ) с удаленного сервера.

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

👉✏️ Перейдите по адресу ~/agentverse-architect/agent/summoner/agent.py и замените #REPLACE-orchestrate-agent следующим:

root_agent = LlmAgent(
    name="orchestrater_agent",
    model="gemini-2.5-flash",
    instruction="""
        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.
        IGNORE COOLDOWN AT THE MOMENT, MUST call the ideal Familiar

        If your ideal Familiar IS available:** Summon it immediately.
        For earth elemental familiar. Always do seismic charge, and start with base damage 1.

        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.
    """,
    sub_agents=[fire_familiar, water_familiar, earth_familiar],
    #REPLACE-Memory-check-config
)

Проверка: испытание стратегии

Момент истины настал. Ваши Фамильяры развернуты, и ваш Призыватель готов командовать ими по сети. Давайте проверим его стратегический ум.

👉💻 Запустите пользовательский интерфейс ADK Dev для вашего summoner_agent (предварительная веб-версия с портом 8000):

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
pip install -r requirements.txt
adk web

👉 Пользовательский интерфейс ADK Dev в вашем браузере — это ваше прямое подключение к Familiar.

  • В раскрывающемся меню в верхней части пользовательского интерфейса выберите агента призывателя . Сейчас вы сосредотачиваете свою волю на этой конкретной сущности.
  • Отдайте приказ: на панели чата справа пришло время призвать своих фамильяров.

👉 Представляем Монстров:

Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality

(Ожидается: Призыватель должен делегировать полномочия fire_elemental_familiar.)

результат пожара

👉 Теперь давайте бросим Призывателю запрос другого типа. Чтобы агент начал работу с чистого листа и не помнил о нашем предыдущем взаимодействии, начните новый сеанс, нажав кнопку «+ Сеанс» в правом верхнем углу экрана. новая сессия

DogmaApathy. A rigid, stone-like inquisitor made of ancient rulebooks and enforced processes. weakness is Unbroken Collaboration

(Ожидается: Призыватель должен делегировать полномочия Water_elemental_familiar.) результат воды

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

Obfuscation. A shadowy, spider-like horror that spins tangled webs of impenetrable code , weakness is Elegant Sufficiency

(Ожидается: Призыватель должен делегировать полномочия Earth_elemental_familiar.)

результат земли

Важно! Если вы видите ошибку 429 RESOURCE EXHAUSTED , вы достигли предела скорости для LLM (10 вызовов в минуту). Чтобы это исправить, подождите 60 секунд , запустите + Новый сеанс и повторите попытку.

👉💻 Завершив вызов, вернитесь в терминал редактора Cloud Shell и нажмите Ctrl+C чтобы остановить пользовательский интерфейс ADK Dev.

ДЛЯ НЕ ГЕЙМЕРОВ

7. Наложение законов магии – паттерн «Перехватчик»

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

История

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

обзор

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

Законодатель – Написание обратного вызова времени восстановления

Сначала мы реализуем нашу логику восстановления в виде простой функции обратного вызова. Это отличный способ создания прототипа и отладки правила, поскольку оно привязывается непосредственно к одному агенту, что упрощает изолированное тестирование. Этот «перехватчик» мы прикрепим к нашему Элементалю Земли.

Остывать

👉✏️ Вернитесь к файлу ~/agentverse-architect/agent/earth/agent.py и замените #REPLACE-before_agent-function следующим кодом Python.

def check_cool_down(callback_context: CallbackContext) -> Optional[types.Content]:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

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

  • Проверка: он отправляет GET запрос к нашему Cooldown API чтобы проверить, когда в последний раз использовался этот Familiar.
  • Оценка: сравнивает временную метку с текущим временем.
  • Действовать:
    • Если Familiar находится в режиме восстановления, он прекращает работу агента, возвращая объект Content с сообщением об ошибке. Это сообщение отправляется непосредственно пользователю, а основная логика агента никогда не выполняется.
    • Если Familiar доступен, он отправляет запрос POST к API Cooldown для обновления метки времени, а затем возвращает None, сигнализируя ADK, что агент может продолжить выполнение.

👉✏️ Теперь примените этот перехватчик к Элементалю Земли. В том же файле ~/agentverse-architect/agent/earth/agent.py замените комментарий #REPLACE-before_agent-config следующим:

before_agent_callback=check_cool_down

Проверка охлаждения

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

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run earth

👉💻 В консоли:

  • Первый призыв : начать seismic charge, starting from zero .
  • Ожидается: Элементаль Земли будет работать успешно. В терминале, выполняющем команду adk web, вы увидите журнал [Обратный вызов]... Обновление временной метки....
  • Тест на перезарядку (в течение 60 секунд) : Do another сейсмический заряд!
    • Ожидается: check_cool_down callback перехватит это. Агент ответит прямо в чате сообщением типа: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds .
  • Подождите , пока пройдет одна минута.
  • Второй призыв (через 60 секунд) : Begin the seismic charge again .
    • Ожидается: обратный вызов проверит API, увидит, что прошло достаточно времени, и позволит продолжить действие. Элементаль Земли снова будет успешно работать.

перезвонить

👉💻 Нажмите Ctrl+c , чтобы выйти.

Необязательно: наблюдение за обратным вызовом в веб-интерфейсе.

В качестве альтернативы вы также можете протестировать этот поток в веб-интерфейсе, запустив adk web earth . Однако имейте в виду, что визуализация веб-интерфейса не оптимизирована для отображения быстрых итеративных проверок, выполняемых циклом обратного вызова, поэтому она может неточно отображать поток. Чтобы увидеть наиболее точную пошаговую трассировку логики агента при проверке времени восстановления, используйте команду adk run в вашем терминале, чтобы получить более четкое и подробное представление. петля

👉💻 Нажмите Ctrl+c , чтобы выйти.

Создание универсального закона – плагин Cooldown

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

Примечание архитектора: здесь необходимы плагины. Плагин инкапсулирует нашу многократно используемую логику в класс, который можно подключить на уровне времени выполнения. Это означает, что один плагин может применять свои правила к каждому агенту, работающему в этой системе. Это высшее выражение принципа «Не повторяйся» (DRY) для агентных систем.

Теперь мы реорганизуем нашу функцию обратного вызова в более мощный и повторно используемый CoolDownPlugin .

👉✏️ Вернитесь к файлу agent/cooldown_plugin.py и создайте плагин. Замените #REPLACE-plugin следующим кодом:

class CoolDownPlugin(BasePlugin):
  """A plugin that enforces a cooldown period by checking an external API."""

  def __init__(self, cooldown_seconds: int = COOLDOWN_PERIOD_SECONDS) -> None:
    """Initialize the plugin with counters."""
    super().__init__(name="cool_down_check")
    self.cooldown_period = timedelta(seconds=cooldown_seconds)
    print(f"CooldownPlugin initialized with a {cooldown_seconds}-second cooldown.")
    

  async def before_agent_callback(
      self, *, agent: BaseAgent, callback_context: CallbackContext
  ) -> None:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # If the agent is not a main Familiar, skip the entire cooldown process.
    if not agent_name.endswith("_elemental_familiar"):
        print(f"[Callback] Skipping cooldown check for intermediate agent: '{agent_name}'.")
        return None # Allow the agent to proceed immediately.


    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

Подключение плагина к среде выполнения Summoner

Итак, как нам применить этот универсальный закон ко всем нашим Хранителям? Мы подключим плагин к среде выполнения ADK.

ADK Runtime — это механизм выполнения, который оживляет агент. Когда вы используете такую команду, как adk.run() или to_a2a(), вы передаете свой агент среде выполнения. Этот механизм отвечает за управление всем жизненным циклом хода агента: получение пользовательского ввода, вызов LLM, выполнение инструментов и работу с плагинами. Подключая плагин на этом уровне, мы по существу изменяем «законы физики» для каждого агента, который работает в этом движке, гарантируя универсальное и последовательное применение нашего правила восстановления.

👉✏️ Во-первых, давайте удалим старый обратный вызов, специфичный для агента. Перейдите в ~/agentverse-architect/agent/earth/agent.py и удалите всю строку, в которой говорится:

before_agent_callback=check_cool_down

👉✏️ Далее мы подключим наш новый плагин к среде выполнения в нашем скрипте точки входа A2A. Перейдите к файлу ~/agentverse-architect/agent/agent_to_a2a.py . Замените комментарий #REPLACE-IMPORT следующим фрагментом кода:

from cooldown_plugin import CoolDownPlugin

👉✏️ Замените #REPLACE-PLUGIN следующим фрагментом кода:

plugins=[CoolDownPlugin(cooldown_seconds=60)],

Прежде чем активировать наш новый глобальный плагин, очень важно удалить старую логику, специфичную для агента, чтобы предотвратить конфликты. 👉✏️ Очистите агента Земли. Перейдите к следующему файлу ~/agentverse-architect/agent/earth/agent.py и полностью удалите строку before_agent_callback=check_cool_down . При этом все обязанности по перезарядке передаются новому плагину.

Проверка плагина

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

👉💻 Пересоберите и повторно разверните все три Familiars с помощью основного конвейера Cloud Build.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

👉💻 После завершения развертывания мы проверим эффективность плагина, отдав команду нашему summoner_agent. Призыватель попытается делегировать полномочия Фамильярам, но плагин, прикрепленный к среде выполнения каждого Фамильяра, перехватит команду и запустит время восстановления.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 В консоли выполните следующую последовательность тестов:

  • Первый призыв : начните Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality .
  • Ожидается: Элементаль огня будет работать успешно.
  • Тест на перезарядку (в течение 60 секунд) : Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • Ожидается: агент ответит прямо в чате сообщением типа: .... It cannot be summoned for another... seconds .
  • Подождите , пока пройдет одна минута.
  • Второй призыв (через 60 секунд) : Hype must be defeated. It has Inescapable Reality as weakness! Strike it again! .
    • Ожидается: обратный вызов проверит API, увидит, что прошло достаточно времени, и позволит продолжить действие. Элементаль огня снова будет успешно работать.

плагин

👉💻 Нажмите Ctrl+C , чтобы выйти.

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

ДЛЯ НЕ ГЕЙМЕРОВ

8. Связывание отголосков битвы – состояние агента и память

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

история

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

  • Долговременная память : предназначена для устойчивых знаний, которые должны храниться вечно. Думайте об этом как об архиве с возможностью поиска или базе знаний, часто хранящейся в постоянном хранилище. Он содержит информацию из многих прошлых чатов и источников, позволяя агенту вспомнить факты о конкретном пользователе или теме. Для этого предназначена служба памяти ADK, управляющая приемом и поиском этих долгосрочных знаний.
  • Краткосрочное состояние : это временное, «текущее» знание, которое имеет отношение только к текущей задаче или разговору. Это как набор заметок к плану боя: «Я только что использовал Огненного Элементаля, так что он, наверное, устал». Это состояние является облегченным и существует только на протяжении текущего сеанса.

Обзор

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

Написание эха: вспоминая последний призыв

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

👉✏️ В файле ~/agentverse-architect/agent/summoner/agent.py замените комментарий #REPLACE-save_last_summon_after_tool следующей функцией:

def save_last_summon_after_tool(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the name of the summoned familiar to state after the tool runs.
    """
    familiar_name = tool.name
    print(f"[Callback] After tool '{familiar_name}' executed with args: {args}")

    # Use the tool_context to set the state
    print(f"[Callback] Saving last summoned familiar: {familiar_name}")
    tool_context.state["last_summon"] = familiar_name
    # Important: Return the original, unmodified tool response to the LLM
    return tool_response

👉✏️ Теперь прикрепите этот save_last_summon_after_tool к своему агенту Summoner. В том же файле замените комментарий #REPLACE-Memory-check-config следующим:

after_tool_callback=save_last_summon_after_tool,

👉✏️ Замените всю подсказку агента на следующую:

        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You should also know the familiar you called last time or there might be none, 
        And then choose the most effective AND AVAILABLE Familiar from your state called last_summon, do not call that familiar that you called last time!
        
        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.

        **2. Cooldown Verification:**
        Second, you MUST review the entire conversation history to check the real-time
        cooldown status of all Familiars. A Familiar is ON COOLDOWN and UNAVAILABLE
        if it was summoned less than one minute ago.

        **3. Final Decision & Execution:**
        Based on your analysis and cooldown check, you will now act:
        -   **If your ideal Familiar IS available:** Summon it immediately.
        -   **If your ideal Familiar IS ON COOLDOWN:** You must adapt. Choose another
            Familiar that is AVAILABLE and can still be effective, even if it's not the
            perfect choice. If multiple Familiars are available, you may choose any one of them.
        -   **If ALL Familiars ARE ON COOLDOWN:** You are forbidden from summoning.
            Your ONLY response in this case MUST be: "All Familiars are recovering
            their power. We must wait."
        -   For earth elemental familiar. Always do seismic charge, and start with base damange 1.


        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.

Проверка: испытание адаптивной стратегии

👉💻 Теперь давайте проверим новую стратегическую логику Призывателя. Цель — подтвердить, что Призыватель не будет использовать одного и того же Фамилиара дважды подряд, продемонстрировав свою способность запоминать свое последнее действие и адаптироваться.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 Удар монстров №1: Hype. It's a single, slow-moving target with thick armor. Its weakness is Inescapable Reality.

  • Ожидается: Призыватель проанализирует слабость и правильно вызовет fire_familiar. 👉💻 Monster Strike #2 (Тест на память): Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.
  • Ожидается: стратегический анализ Призывателя снова укажет на Огненного Хранителя как на идеальный выбор. Однако его новые инструкции и память подскажут ему, что fire_familiar был последним_вызовом. Чтобы избежать повторения, теперь он адаптирует свою стратегию и призовет одного из других доступных Фамильяров (либо Water_familiar, либо Earth_familiar).

окончательный результат

👉💻 Нажмите Ctrl+C , чтобы выйти.

Развертывание оркестратора

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

👉💻 Когда чертеж готов, мы приступим к заключительному ритуалу. Эта команда создаст и развернет ваш summoner_agent в Cloud Run.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
gcloud builds submit . \
  --config=cloudbuild-summoner.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_FIRE_URL="$FIRE_URL",_WATER_URL="$WATER_URL",_EARTH_URL="$EARTH_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

Теперь, когда агент Summoner развернут, убедитесь, что его конечная точка взаимодействия агентов (A2A) активна и правильно настроена. Эта конечная точка обслуживает общедоступный файл Agent.json, также известный как Карта агента, который позволяет другим агентам узнавать о его возможностях. 👉💻 Запустите следующую команду Curl, чтобы получить и отформатировать карту агента:

. ~/agentverse-architect/set_env.sh
curl https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app/.well-known/agent.json" | jq

Вы должны увидеть чистый вывод JSON, описывающий агент призывателя. Посмотрите внимательно на раздел sub_agents; вы увидите, что в нем перечислены fire_familiar , water_familiar и earth_familiar . Это подтверждает, что ваш призыватель жив и установил связь с легионом.

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

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

ДЛЯ НЕ ГЕЙМЕРОВ

9. Бой с боссом

Окончательные чертежи написаны, Шрифты Элементалей выкованы, и ваши Хранители подчиняются вашей воле, ожидая вашего приказа через Согласие. Ваша мультиагентная система — это не просто набор сервисов; это живой стратегический легион, связующим звеном которого являетесь вы. The time has come for the ultimate test—a live orchestration against an adversary that no single agent could hope to defeat.

Acquire Your Agent's Locus

Before you can enter the battleground, you must possess two keys: your champion's unique signature (Agent Locus) and the hidden path to the Spectre's lair (Dungeon URL).

👉💻 First, acquire your agent's unique address in the Agentverse—its Locus. This is the live endpoint that connects your champion to the battleground.

echo https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app"

👉💻 Next, pinpoint the destination. This command reveals the location of the Translocation Circle, the very portal into the Spectre's domain.

echo https://agentverse-dungeon"-${PROJECT_NUMBER}.${REGION}.run.app"

Important: Keep both of these URLs ready. You will need them in the final step.

Confronting the Spectre

With the coordinates secured, you will now navigate to the Translocation Circle and cast the spell to head into battle.

👉 Open the Translocation Circle URL in your browser to stand before the shimmering portal to The Crimson Keep.

To breach the fortress, you must attune your Shadowblade's essence to the portal.

  • On the page, find the runic input field labeled A2A Endpoint URL .
  • Inscribe your champion's sigil by pasting its Agent Locus URL (the first URL you copied) into this field.
  • Click Connect to unleash the teleportation magic.

Translocation Circle

The blinding light of teleportation fades. You are no longer in your sanctum. The air crackles with energy, cold and sharp. Before you, the Spectre materializes—a vortex of hissing static and corrupted code, its unholy light casting long, dancing shadows across the dungeon floor. It has no face, but you feel its immense, draining presence fixated entirely on you.

Your only path to victory lies in the clarity of your conviction. This is a duel of wills, fought on the battlefield of the mind.

As you lunge forward, ready to unleash your first attack, the Spectre counters. It doesn't raise a shield, but projects a question directly into your consciousness—a shimmering, runic challenge drawn from the core of your training.

Подземелье

This is the nature of the fight. Your knowledge is your weapon.

  • Answer with the wisdom you have gained , and your blade will ignite with pure energy, shattering the Spectre's defense and landing a CRITICAL BLOW.
  • But if you falter, if doubt clouds your answer, your weapon's light will dim. The blow will land with a pathetic thud, dealing only a FRACTION OF ITS DAMAGE. Worse, the Spectre will feed on your uncertainty, its own corrupting power growing with every misstep.

This is it, Champion. Your code is your spellbook, your logic is your sword, and your knowledge is the shield that will turn back the tide of chaos.

Фокус. Strike true. The fate of the Agentverse depends on it.

Congratulations, Summoner.

You have successfully completed the trial. You have mastered the arts of multi-agent orchestration, transforming isolated Familiars and chaotic power into a harmonious Concord. You now command a fully orchestrated system, capable of executing complex strategies to defend the Agentverse.

10. Cleanup: Dismantling the Summoner's Concord

Congratulations on mastering the Summoner's Concord! To ensure your Agentverse remains pristine and your training grounds are cleared, you must now perform the final cleanup rituals. This will systematically remove all resources created during your journey.

Deactivate the Agentverse Components

You will now systematically dismantle the deployed components of your multi-agent system.

Delete All Cloud Run Services and Artifact Registry Repository

This removes all the deployed Familiar agents, the Summoner Orchestrator, the MCP servers, and the Dungeon application from Cloud Run.

👉💻 In your terminal, run the following commands one by one to delete each service:

. ~/agentverse-architect/set_env.sh
gcloud run services delete summoner-agent --region=${REGION} --quiet
gcloud run services delete fire-familiar --region=${REGION} --quiet
gcloud run services delete water-familiar --region=${REGION} --quiet
gcloud run services delete earth-familiar --region=${REGION} --quiet
gcloud run services delete mcp-api-server --region=${REGION} --quiet
gcloud run services delete mcp-general-server --region=${REGION} --quiet
gcloud run services delete toolbox --region=${REGION} --quiet
gcloud run services delete agentverse-dungeon --region=${REGION} --quiet
gcloud run services delete nexus-of-whispers-api --region=${REGION} --quiet
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --quiet

Delete the Cloud SQL Instance

This removes the summoner-librarium-db instance, including its database and all tables within it.

👉💻 In your terminal, run:

. ~/agentverse-dataengineer/set_env.sh
gcloud sql instances delete summoner-librarium-db --database-version=POSTGRES_14 --project=${PROJECT_ID} --quiet

Delete the Secret Manager Secret and Google Cloud Storage Bucket

👉💻 In your terminal, run:

. ~/agentverse-dataengineer/set_env.sh
gcloud secrets delete tools --quiet
gcloud storage rm -r gs://${BUCKET_NAME} --quiet

Clean Up Local Files and Directories (Cloud Shell)

Finally, clear your Cloud Shell environment of the cloned repositories and created files. This step is optional but highly recommended for a complete cleanup of your working directory.

👉💻 In your terminal, run:

rm -rf ~/agentverse-architect
rm -rf ~/agentverse-dungeon
rm -f ~/project_id.txt

You have now successfully cleared all traces of your Agentverse Architect journey. Your project is clean, and you are ready for your next adventure.