Акты Становления

012: Агент/Делегат

Это как правила для создания отдельной «комнаты» для выполнения задачи. Когда в Вызове есть специальное свойство _delegate, система понимает, что нужно выполнить Действие или новый Запрос в этой отдельной, изолированной «комнате». А свойство _scopes — это как «пропуск», который даёт контролируемый доступ к информации из основной программы.

Делегирование — это способ решения важной проблемы: как сделать так, чтобы агенты (наши ИИ-помощники) могли становиться умнее и выполнять всё более сложные задачи, состоящие из множества частей. Это как дать агенту «песочницу», где он может безопасно использовать свои Инструменты. В этой «песочнице» нет ничего лишнего, так что агент не запутается (это называется «утечка контекста»), а сами инструменты можно будет легко использовать в других задачах. Когда мы «делегируем» Вызов кому-то другому (например, другому Запросу или Действию в подзадаче), система может собирать очень сложное поведение из маленьких, независимых «кубиков».

Проблема: Гигантские инструменты и «утечка контекста»

Когда у агента становится слишком много способностей, хранить все его Инструменты в одной большой «коробке» становится неудобно.

  1. Огромные инструкции: Представь, что у тебя есть инструкция на 1000 страниц. Мозг просто не сможет удержать всё сразу. Так же и у больших языковых моделей (LLM) есть предел тому, сколько информации об инструментах они могут обработать за раз. Если инструментов слишком много, модель может запутаться.
  2. «Утечка контекста»: Если все Инструменты лежат в одной куче, ИИ может случайно использовать информацию из одного инструмента при работе с другим, что приведёт к ошибкам. Это как если бы ты, готовя пирог, случайно добавил в него соль, потому что солонка стояла рядом с сахарницей.
  3. Сложно использовать повторно: Инструмент, созданный для одного агента, трудно просто так взять и отдать другому. Придётся тащить с собой всю «коробку» с инструкциями, даже если нужен всего один маленький молоточек.

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

Как вызвать Делегата

Чтобы поручить задачу делегату, используется специальное свойство _delegate в инструкции к Инструменту. Это свойство — сигнал для системы, что задачу нужно не выполнять на месте, а передать кому-то другому.

Свойство _delegate — это строка, и её можно использовать двумя способами:

  • Сохранённый, готовый к повторному использованию Запрос — это самая частая форма Идеи. Делегирование — это основной способ соединять такие Идеи в более сложные системы. Подробнее см. в 101: Концепция/Идея.

    Указать на сохранённый Запрос: Строка может быть адресом (путём или ссылкой в интернете) к файлу, который описывает отдельный, самодостаточный Запрос. Это как дать Инструменту визитку другого специалиста, чтобы тот выполнил свою часть работы.

  • Создать анонимного делегата: Если в строке написано 'anonymous', это сигнал создать совершенно новую, чистую «комнату» для выполнения Вызова. Это полезно, когда не нужна целая инструкция, а просто требуется изолированное место для одного действия.

Выполнение в изолированной среде

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

Именно здесь ключевую роль играет Контекст с ограниченным доступом (scope). Свойство _scopes в инструкции Инструмента работает как «пропуск», который точно указывает, какие именно данные из мастерской родителя нужно принести в рабочую комнату делегата. Это даёт главному агенту полный контроль над тем, что видит делегат, предотвращая «утечку контекста» и делая каждый компонент по-настоящему независимым.

Работа с большими инструкциями

Делегирование также помогает, когда у Инструмента очень сложный результат работы. Вместо того чтобы описывать этот огромный результат (схему _output) в главной инструкции и занимать место, можно определить Инструмент только с параметрами для входа и указателем _delegate.

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

Стратегии определения Делегата

Инструмент становится Делегатом, как только в его описании появляется свойство _delegate. Это сигнал, что Вызов нужно передать. Главный вопрос — когда система решает, что это за делегат. Есть два подхода: один гибкий, другой — строгий.

1. Определение во время выполнения (по умолчанию)

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

Этот метод позволяет делать то, что не умеет обычный код: ИИ выступает в роли умного «переводчика». Агент может сделать Вызов с параметрами, которые не совсем точно совпадают с тем, что ожидает делегат. Во время выполнения система собирает всё вместе — контекст делегата и данные от вызывающего — и просит ИИ в подзадаче «договориться».

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

Процесс выглядит так:

  1. Агент создаёт Вызов к модульному Инструменту.
  2. Система-исполнитель видит свойство _delegate и начинает процесс делегирования.
  3. Сборка контекста: Исполнитель находит файл с описанием делегата и собирает его базовый контекст. Затем он использует _scopes для добавления нужной информации от вызывающего.
  4. Сопоставление данных: Параметры из Вызова упаковываются во Входное сообщение и добавляются в контекст. Здесь и происходит магия «переводчика»: ИИ будет использовать эти данные для выполнения задачи делегата, даже если их формат не совпадает идеально.
  5. Выполнение: Создаётся новый, изолированный Запрос с собранным контекстом. Результат возвращается как итог изначального Вызова.

2. Определение заранее (опционально)

В ситуациях, где нужна стопроцентная надёжность, делегата можно определить заранее, ещё до того, как основной Запрос отправляется агенту.

В этом режиме система заранее загружает описание делегата и объединяет его требования к входным данным с параметрами Инструмента. Это позволяет главному ИИ сразу видеть точные требования делегата и сгенерировать идеально правильный Вызов. Важно, что при этом можно также заранее узнать, какой будет выходной результат (_output), что даёт строгий контракт на всю работу.

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

Пример: Гибкое сопоставление данных во время выполнения

Этот пример показывает, как работает концепция «ИИ-переводчика». Делегат успешно выполняется, даже если Вызов от агента не идеально совпадает с его ожиданиями. Это стандартное поведение.

Что видит вызывающий

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

// ВЫЗОВ, СОЗДАННЫЙ ДИРИЖЁРОМ
{
  "_tool": "sendMessage",
  "_delegate": "http://example.com/agents/speaker_EN",
  "userId": "u_123",
  "text": "Hello, world!"
}

Что видит делегат и итоговый контекст

Делегат speaker_EN — это отдельный Запрос. Во время выполнения система упаковывает параметры от дирижёра в свойство input Входного сообщения. Но при этом она также добавляет своё описание ожидаемых данных (schema), которое не совпадает с тем, что пришло. Теперь задача ИИ внутри делегата — понять эту разницу: догадаться, что userId — это recipientId, а text — это messageBody. Это не программная замена, а смысловое сопоставление, которое происходит внутри ИИ.

// ИТОГОВЫЙ КОНТЕКСТ ДЛЯ ПОДЗАДАЧИ
[
  {
    "type": "system",
    "message": "Ты — эксперт по отправке сообщений на английском языке."
  },
  {
    "type": "input",
    // Это «сырые» данные, которые предоставил вызывающий агент.
    "input": {
      "userId": "u_123",
      "text": "Hello, world!"
    },
    // А это ожидаемый формат входных данных для делегата
    "schema": {
      "type": "object",
      "properties": {
        "recipientId": { "type": "string" },
        "messageBody": { "type": "string" }
      }
    }
  }
]

Пример: Создатели музыки

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

Представим процесс создания музыки с двумя делегатами-специалистами: Композитором и Звукорежиссёром.

  • Звукорежиссёр — это узкий специалист. Он знает всё о физике звука и умеет работать с синтезаторами, чтобы создавать конкретные звуки.

  • Композитор — специалист среднего звена. Его работа — сочинить песню. Он использует свои инструменты, чтобы создать мелодию и структуру. А чтобы эту мелодию услышать, он делает Вызовы к Звукорежиссёру, чтобы тот синтезировал нужные звуки.

Такая двухуровневая система очень распространена. Но настоящая сила делегатов — в их гибкости.

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

Продюсер

Композитор

Звукорежиссёр

Теперь введём главного — Продюсера. Его цель — создать готовую пластинку. В зависимости от задачи Продюсер может руководить своими делегатами по-разному:

  • Иерархическое управление: Чтобы создать песню, Продюсер может сделать один Вызов к Композитору. Он даёт общее указание («Мне нужна грустная баллада»), а Композитор уже сам выполняет всю свою работу, включая вызовы к Звукорежиссёру. Продюсеру в этом случае даже не нужно знать о существовании Звукорежиссёра.

  • Параллельное управление: Если Продюсеру нужны ещё и спецэффекты для записи (например, шум дождя), он может делать Вызовы напрямую к Звукорежиссёру для этих задач, одновременно с тем, как Композитор пишет музыку.

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

От Делегирования к Областям видимости (Scopes)

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