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

008: Агент/Вывод

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

У системы агентов есть два вида вывода: промежуточные результаты Вызовов инструментов, которые записываются в общий контекст (как в черновик), и Финальный вывод, то есть окончательный результат всей работы.

Запись в контекст с помощью Пути вывода

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

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

Это новое сообщение является стандартным Сообщением с данными, но оно содержит два дополнительных элемента, которые скрыты от языковой модели:

  • _call: Оригинальный Вызов инструмента, который сгенерировал этот результат.
  • _date: Точное время, когда результат был записан.
  • _outputMethod: Способ, указанный в первоначальном вызове, который определяет, как эти данные должны быть объединены с другими.

Это оставляет полный, проверяемый след того, как менялся контекст, что очень ценно для отладки и отслеживания логики агента.

Определение Пути вывода

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

Динамический путь (решает ИИ)

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

// Схема инструмента разрешает любую строку для _outputPath
{
  "_outputPath": {
    "type": "string",
    "description": "Путь для сохранения сводки о пользователе.",
    "pattern": "^†"
  }
}

Предписанный путь (задан заранее)

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

// Схема инструмента закрепляет _outputPath за конкретным значением
{
  "_outputPath": {
    "type": "string",
    "const": "†data.user.summary"
  }
}

Динамическое определение переменных

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

Когда нужно найти значение ссылки на переменную, например †data.user.name, движок ищет по сообщениям в обратном хронологическом порядке (от новых к старым).

  • Если движок находит сообщение для нужного пути с методом set (установить) или без метода (так как set — это стандартное поведение), он немедленно останавливается. Значение из этого сообщения и есть финальный результат, а все более старые записи для этого пути игнорируются. Это правило «кто последний, тот и прав».
  • Если движок находит сообщения с методами merge (объединить), push (добавить в конец списка) или concat (соединить), он продолжает поиск вглубь, собирая все такие сообщения, пока не дойдёт до сообщения с set или до самого начала истории. Затем он воссоздаёт финальное значение, применяя все собранные операции в хронологическом порядке (от старых к новым).

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

Пример: Добавление и поиск значения

1. Начальное состояние

Вначале в контексте есть одно сообщение с данными.

[
  {
    "type": "data",
    "data": { "user": { "name": "Alex", "status": "active" } }
  }
]

2. Выполнение вызова инструмента

Вызывается инструмент для обновления статуса пользователя.

// Выполняемый вызов
{
  "_tool": "updateUserStatus",
  "newStatus": "inactive",
  "_outputPath": "†data.user.status"
}

3. Контекст после выполнения

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

[
  // Исходное сообщение с данными
  {
    "type": "data",
    "data": { "user": { "name": "Alex", "status": "active" } }
  },
  // Добавленное сообщение с результатом вызова
  {
    "type": "data",
    "data": { "user": { "status": "inactive" } },
    "_call": {
      "_tool": "updateUserStatus",
      "newStatus": "inactive",
      "_outputPath": "†data.user.status"
    },
    "_date": "2025-10-26T12:00:00Z"
  }
]

4. Поиск значения переменной

  • Чтобы найти †data.user.status, движок сначала проверяет последнее сообщение. Он находит user.status и возвращает "inactive".
  • Чтобы найти †data.user.name, движок проверяет последнее сообщение, не находит user.name, а затем проверяет предыдущее. Он находит его там и возвращает "Alex".

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

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

Вызовы без Пути вывода

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

Временные размышления для скрытых вызовов

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

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

«Сделать и забыть» для явных вызовов

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

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

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

Взаимодействие с другими системами

  • Выражения: Выражения вводят логику прямо в поток данных. Используя || и && в Пути вывода, Вызов инструмента может объявлять условные результаты или направлять свой результат в несколько мест одновременно. Это уводит систему от жёстких, заранее прописанных конвейеров данных к гибкой структуре, которая адаптируется к условиям во время выполнения.
  • План: В контексте Плана Пути вывода действуют как «провода», которые соединяют различные Вызовы инструментов («узлы») в единый граф потока данных. Это позволяет агенту определять и выполнять целую многошаговую стратегию как единый, декларативный объект.
  • Экземплирование: Когда Вызов инструмента включает свойство _instance, любой указанный в нём _outputPath автоматически привязывается к контексту данных именно этого экземпляра. Это обеспечивает изоляцию данных при параллельной обработке, гарантируя, что вывод инструмента, работающего над одним экземпляром, не будет мешать состоянию другого.

От временных выводов к постоянному состоянию

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

Следующий документ, 009: Агент/Состояние, описывает протокол для этой постоянной памяти.