AI-разработка

Как OpenAI Agents API ведёт долгоживущего AI-агента? Context, Tools, Subagents и JSON-состояние (2026)

Около 16 мин

Публичная бета 10 сентября — не «ещё один чат». OpenAI отдал harness, на котором Codex уже шёл сутками: Session продолжается, контекст уплотняется, у каждого субагента своё окно. Здесь только о том, как длинная задача выживает: какой JSON хранить, что сжимает OpenAI, какие items читать после обрыва.

Перед чтением

Объект Что делает Что хранить
Session Устойчивый экземпляр на часы и окна session_id
Turn Асинхронная работа от одного ввода turn_id / финальные события
Items Сохранённые сообщения и вызовы инструментов Повтор после обрыва
Compact Автосжатие у предела окна Ключевые поля — у вас
Subagent Свой контекст, параллельная работа Потолок параллелизма

Простаивающая session — не успех. Смотрите события turn и items, не последнее предложение.

Длинная задача живёт в Session, не в более длинном prompt

Ответ Agents API конкретен: создать устойчивую session и слать дальнейший ввод на тот же session_id. Близко к пределу контекста harness сам уплотняет раннюю работу. Независимые подзадачи можно отдать субагенту. Полный чат заново не собираете.

  • Продолжить: привязать session_id к вашему разговору. Не открывать вторую session на тот же случай.
  • Обрыв: поток не переигрывается. Забрать session и items. Не считать, что клиент помнит прошлый прыжок.
  • Деньги и номера: compact роняет детали. Номера заказов, суммы, согласования — в вашем JSON.

Как Session стыкуется с JSON инструментов: Разбор OpenAI Agents API. Кому держать цикл: Agents API vs Responses API. Если Agent и Function Calling ещё одно слово — сначала Полный гид по AI-агенту.

Session продолжается; Turn идёт асинхронно

Создать один раз: модель, инструменты, среду, multi_agent. Официально: POST /v1/agents/sessions с OpenAI-Beta: agents=v1. Хостинг-песочница: openai_hosted:

{
  "agent": {
    "model": "gpt-6-astra",
    "instructions": "Look up orders. Confirm before any refund. Delegate independent lookups to subagents.",
    "tools": [
      {
        "type": "function",
        "name": "lookup_order",
        "parameters": {
          "type": "object",
          "properties": {
            "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
          },
          "required": ["order_id"],
          "additionalProperties": false
        }
      },
      { "type": "web_search" }
    ],
    "multi_agent": { "enabled": true, "max_concurrent_subagents": 3 }
  },
  "environment": { "type": "openai_hosted", "workspace_directory": "/workspace" },
  "input": [
    {
      "role": "user",
      "content": [{ "type": "input_text", "text": "Look up A-1042 and keep the case open." }]
    }
  ]
}

Ещё одно agent.session.input.message в ту же session. Простой открывает новый turn; активный направляет текущий. Отмена — agent.session.input.cancel: session и сохранённая работа остаются:

{
  "events": [
    {
      "type": "agent.session.input.message",
      "input": [
        {
          "role": "user",
          "content": [
            { "type": "input_text", "text": "Warehouse marked A-1042 packed. Continue." }
          ]
        }
      ]
    }
  ]
}

Смотреть исход, не «простоит ли». Официальные события: agent.session.turn.completed, failed, cancelled. Завершённый turn не значит, что каждый инструмент успешен. Нужен результат функции — читать required_actions.

Цепочка инструментов тянется часами; запись назад — всё ещё JSON

На длинной задаче модель по-прежнему только заполняет аргументы. Когда ваша функция настала, harness останавливается; вы возвращаете результат по turn_id / call_id. Через четыре часа форма та же:

{
  "type": "tool_result",
  "turn_id": "turn_4",
  "call_id": "call_3c91",
  "success": true,
  "output": "{\"order_id\":\"A-1042\",\"status\":\"packed\"}"
}

Функции нужны вы. MCP и web_search может выполнить harness. Субагенты наследуют MCP и веб-поиск; function-инструменты не наследуют. Побочные эффекты по вашим заказам остаются у главного агента.

Дверь по-прежнему Schema. Широкий object на длинном прогоне опаснее: после compact модель чаще выдумает номер. MCP — ещё одна таблица инструментов; граница в MCP Tool Schema vs Function Calling.

Compact сжимает окно, не вашу книгу учёта

Официально: когда session подходит к пределу, Agents API сам уплотняет ранний контекст, чтобы работа перешла через окна. Этот компрессор писать не нужно. Это не слой context_management / /responses/compact у Responses.

  • Agents API: session сжимает себя. Забрать items и проверить, что номер заказа ещё там.
  • Responses: включить compact или вызвать endpoint compact. Зашифрованный compaction item передать дальше, не обрезать руками.
  • Оба: сжатие роняет детали. Суммы, подтверждения, выпуски пишет хозяин.

Если order_id живёт только в чате, книгу учёта отдали сводке. Schema как дверь: Зачем ИИ нужен JSON Schema.

Субагенты: параллельно, но контекст раздельный

С multi_agent.enabled harness даёт create, message, wait и interrupt. Эти инструменты не объявляете. Координация видна как items:

{
  "data": [
    {
      "type": "function_call",
      "turn_id": "turn_4",
      "call_id": "call_3c91",
      "name": "lookup_order",
      "arguments": "{\"order_id\":\"A-1042\"}"
    },
    {
      "type": "create_subagent_call",
      "agent_id": "agent_main",
      "task": "Compare A-1042 packing notes with the invoice."
    }
  ]
}
  • Свой контекст: у каждого субагента один. Главный агент закрывает create / message / wait / interrupt.
  • Ограничить параллелизм: по умолчанию 6, без координатора. В проде закрепить меньшее число.
  • Готовый item ≠ готовая подзадача: завершённый create_subagent_call значит только «отправлено». Смотреть agent.session.subagent.created и items этого субагента.

Handoff должен быть проверяемым JSON, не «передайте в биллинг». Как уложить в Schema: JSON Schema и рабочие процессы агента.

Держите своё состояние; не просите compact его помнить

OpenAI хранит конфигурацию session, разговор и сохранённую работу. Вам всё равно нужен деловой объект, который соберётся после обрыва:

{
  "session_id": "sess_8f21",
  "order_id": "A-1042",
  "last_turn_id": "turn_4",
  "last_call_id": "call_3c91",
  "awaiting": "tool_result",
  "compact_checkpoint": "after_turn_3"
}

Этот объект — не Session, не SDK session, не Responses conversation и не sandbox. Удаление одного не чистит остальные. Резидентность данных пока только США; своя песочница не делает API ZDR.

Пять шагов, чтобы закрыть задачу через окна

Не восстанавливать демо задом наперёд. Идти по объектам:

  1. Создать одну session и записать session_id в разговор. Таблицу инструментов и Schema затянуть один раз.
  2. Подписаться, потом слать дальше. Открыть поток до agent.session.input.message, иначе ранние события пропадут.
  3. На required_actions писать назад. Тот же turn_id / call_id. Не повторять на новой session.
  4. После обрыва — список items. Поток не переигрывается. order=asc и сверить номер заказа и открытые вызовы.
  5. После compact снова сверить книгу. Если сводка потеряла A-1042, следующий прыжок выдумает номер.

Все пять стоят на объектах. Пропустить шаг — поставить на то, что окно ещё не полное.

Разбирать длинную задачу — разложить два JSON-следа

Большинство сбоев — несовпадение объектов, не более глупая модель.

  • формат items session рядом с локальным состоянием. Проверить, что session_id / call_id сходятся.
  • извлечь JSONPath вытащить order_id, turn_id и agent_id субагента.
  • JSON Diff items до и после compact. Номер поплыл — сначала сжатие, потом модель.
  • Items главного агента и субагента — отдельными списками. В одной странице координация прилипнет не к тому.
  • Не вставлять заказы, session и внутренний MCP в публичный форматтер. JSONSort работает в браузере локально.

Если оба следа собираются заново, задачу продолжили. Иначе снова угадали.

Частые ловушки

  • Считать простой успехом. Сначала turn.completed / failed / cancelled, потом результаты инструментов.
  • Ждать переигрывания потока после обрыва. Официально: нет. Забрать session и items.
  • Оставить номер заказа только в чате. После compact сводка может потерять A-1042.
  • Включить multi_agent без потолка. Умолчание 6 всё равно разворачивает токены и побочные эффекты.
  • Отдать function субагенту. Субагенты не поддерживают function-инструменты. Поиск заказа — у главного агента.
  • Считать Session и Conversation одним ресурсом. Удаление одного не чистит другое.

FAQ

Долгий прогон — это просто более длинный prompt?

Нет. Это устойчивая session, автоматический compact и деловой JSON, который держите вы. Более длинный системный prompt не поднимает предел окна.

Можно смешивать compact Agents и compact Responses?

Нельзя. Session Agents сжимает себя. Responses использует context_management или /responses/compact. Два ресурса, два следующих входа окна.

Как восстановиться после обрыва?

Загрузить session и items по сохранённому session_id. Поток не переигрывает пропущенные события. Выровнять last_turn_id и открытый call_id, затем записать назад или послать следующее сообщение.

Может ли субагент вызвать мой lookup_order?

Нет. Официально: function-инструменты не поддерживаются. Наследуют MCP, веб-поиск и файлы / команды среды. Поиск своих заказов остаётся у главного агента.

Своя песочница даёт Zero Data Retention?

Нет. Официально: Agents API сейчас только с резидентностью в США и без ZDR. Self-hosted песочница этого не меняет.

Вывод

Долгий прогон — не более умная модель. Это устойчивая Session, автоматический compact и JSON-состояние, которое держите вы. Аргументы инструментов, события turn, items субагента — объекты на этой цепи.

Сначала запишите, соберёте ли A-1042 после обрыва. Если да, задача жива. Модели сменятся; session_id и Schema должны устояться раньше.

Дальше

Журнал изменений: Первая публикация