Свежий сигнал: отказ до вызова модели
21 августа 2026 года в репозитории openai/codex появился Issue #39848. Пользователь сообщил, что Codex Desktop отправляет встроенный инструмент automation_update в форме, которую строгий OpenAI-compatible endpoint отклоняет ещё до первого ответа модели. Сервер возвращает ошибку валидации: корень JSON Schema не распознан как объект.
Речь не о неверном выборе функции моделью и не о промпте. Если провайдер не принимает объявление tools, агентский сценарий останавливается на входном HTTP 400. При маршрутизации между несколькими моделями и API это становится операционным риском: один встроенный инструмент способен заблокировать запрос, хотя пользователь не просил запускать автоматизацию.
Этот эпизод не следует переоценивать. Открытый issue не доказывает, что 21 августа OpenAI изменила генератор схем, и не подтверждает сбой у всех совместимых провайдеров. Однако вместе с более ранним Issue #37786 он указывает на устойчивый класс проблем: совпадение формата API-запроса не означает совпадения правил валидации схем инструментов.
Issue #39848 описывает конкретный сценарий: Codex Desktop на Windows направляет запрос к строгому OpenAI-compatible провайдеру, а тот отклоняет tool schema для automation_update. В сообщении приведён текст ошибки: функция должна иметь JSON Schema с type: "object", но сервер видит type: "None". На странице issue нет назначенного исполнителя, milestone, связанного pull request или публичного подтверждения исправления. Это наблюдение одного репортёра, а не оценка частоты инцидентов.
Критичен момент отказа. Валидация происходит при разборе объявления инструмента, до того как модель начнёт генерировать текст или аргументы функции. Поэтому уточнение system prompt, повторная отправка запроса или смена пользовательской формулировки не должны рассматриваться как способ восстановить workflow. Если набор исходящих tools не меняется, повторный запрос, вероятно, вернёт ту же ошибку.
Под strict здесь понимается режим, в котором endpoint проверяет входную схему по ограниченному набору правил и не пытается интерпретировать намерение клиента. Такая строгость сама по себе не говорит о дефекте провайдера. Документация Azure OpenAI для Structured Outputs также описывает ограничения JSON Schema и требует объектный корень схемы.
- Подтверждённый факт: Issue #39848 открыт 21 августа 2026 года.
- Подтверждённый симптом: endpoint отклоняет schema до ответа модели.
- Не подтверждено, что это новый августовский регресс, признанный OpenAI баг или проблема всех OpenAI-compatible сервисов.
Цитата в переводе«Недопустимая схема для функции «automation_update»: схема должна быть JSON Schema типа «object», получен тип «None.»
Ошибка, приведённая в issue
«Недопустимая схема для функции “automation_update”: схема должна быть JSON Schema типа “object”, получен тип “None”».
Источник: MyQiongbao - автор GitHub Issue #39848
Редакторский вывод: ошибка возникает на этапе приёма описания инструмента, поэтому модель не получает возможности вызвать функцию или сформировать её аргументы.
Цитата в переводе«automation_update отправляется со схемой JSON Schema, где oneOf находится на корневом уровне, а верхнеуровневый «type»: «object» отсутствует.»
Что именно не устраивает валидатор
Полный сериализованный payload из Issue #39848 не опубликован, поэтому восстанавливать все поля automation_update было бы недобросовестно. Однако Issue #37786 точнее описывает форму проблемы: у инструмента есть root-level oneOf, но отсутствует верхнеуровневый ключ "type": "object". Для части серверных валидаторов такой корень оказывается не объектом, а неопределённым значением type null или None.
JSON Schema как общий стандарт допускает выразительные композиции. oneOf означает, что экземпляр должен соответствовать ровно одной из перечисленных ветвей. Но API структурированных ответов и function calling нередко поддерживают не весь язык JSON Schema, а документированное подмножество. В такой модели корневой контейнер аргументов инструмента ожидается в виде объекта: с properties, required и правилами для дополнительных полей. Схема может быть логичной для генератора типов, но неприемлемой на конкретной сетевой границе.
Минимальная форма, которую обычно ожидает строгий валидатор, остаётся объектом даже при пустом наборе аргументов: type object, properties и additionalProperties false. Для объекта с параметрами строгие реализации также требуют явно описывать обязательность. Azure OpenAI указывает, что все поля должны входить в required, а логически необязательное значение следует выражать через nullable-представление, а не отсутствующий ключ.
Суть несовместимости в этом и состоит. Проблема не в названии automation_update и не обязательно в oneOf как конструкции. Конфликт возникает, если фактический wire payload использует union на верхнем уровне вместо объектной оболочки, а маршрут принимает только object-root схемы.
- Проблемная наблюдаемая форма: верхнеуровневый oneOf без type: object.
- Ожидаемая строгим маршрутом форма: корень типа object с ограниченными свойствами.
- Нельзя автоматически считать любой oneOf невалидным JSON Schema: речь о совместимости с ограниченным подмножеством конкретного API.
Форма схемы из связанного issue
«automation_update отправляется со схемой JSON Schema, где oneOf находится на корневом уровне, а верхнеуровневый “type”: “object” отсутствует».
Источник: xjimlinx - автор GitHub Issue #37786
Редакторский вывод: это описание пользователя GitHub, а не официальное объяснение OpenAI, но оно даёт проверяемую гипотезу для анализа исходящего payload.
Почему OpenAI-compatible не означает одинаковую семантику
Маркировка OpenAI-compatible обычно означает, что клиент может использовать знакомые маршруты, заголовки и базовую форму JSON-запроса. Для агентов этого мало. Должны совпадать представление tools, набор поддерживаемых ключевых слов JSON Schema, правила strict mode и поведение при исполнении. В документации SDK OpenAI типы инструментов описываются как отдельная часть API-контракта, а не как произвольное вложение пользовательского JSON.
Совместимость удобно рассматривать на четырёх независимых слоях. Первый слой: транспорт, то есть endpoint, авторизация, формат запроса и ответа. Второй: модель инструмента, включая обычную function, встроенный tool, namespace или иной служебный тип. Третий: schema dialect, то есть поддерживаемый набор конструкций, правила для unions, additionalProperties false и полного required. Четвёртый: runtime-семантика, при которой модель видит функцию, формирует допустимые аргументы, а обработчик принимает их.
Инцидент с automation_update возникает на третьем слое, но последствия проявляются на четвёртом: автоматизация не запускается. Более общий вывод таков: успешный запрос без tools не подтверждает, что маршрут готов к агентной работе. Ответ на простую function schema также не доказывает поддержку built-in tools или сложных union-конструкций. Это инженерная интерпретация сопоставления issue и требований Structured Outputs, а не заявление о едином стандарте рынка.
Поэтому прокси и multi-provider router нельзя оценивать одной отметкой «совместим с OpenAI». Для рабочего профиля важна связка provider, endpoint, режим API, модель, версия клиента и набор инструментов. Изменение любого из этих элементов может повлиять на фактически отправляемую схему или правила её приёма.
- Транспортная совместимость не гарантирует schema-совместимость.
- Schema-совместимость не гарантирует исполнение вызова и соответствие аргументов backend-контракту. Это нужно проверять отдельными тестами.
- Для production важен не исходный тип в приложении, а JSON, который реально ушёл в endpoint.
Strict mode: полезное ограничение, а не универсальный адаптер
Strict mode сужает набор допустимых аргументов и делает вызовы инструментов более предсказуемыми. Но он не превращает произвольную схему в переносимый контракт. Azure OpenAI Structured Outputs перечисляет ограничения поддерживаемого подмножества JSON Schema: для object-узлов требуется additionalProperties false, свойства должны быть объявлены required, а корневой объект не может быть anyOf. Это независимое от GitHub issue подтверждение: ограничения object-root характерны для класса строгих реализаций, а не только для одного сообщения об ошибке.
Различие между oneOf и anyOf в практической диагностике вторично. В Issue #37786 упоминается oneOf, а Azure отдельно оговаривает anyOf на корне. На этом основании нельзя утверждать, что Azure воспроизвёл тот же payload Codex Desktop. Корректнее сказать, что документация Microsoft подтверждает общий принцип: корневая union-конструкция может оказаться за пределами поддерживаемой области strict structured outputs.
Есть рискованная иллюзия быстрого исправления: просто развернуть oneOf в один объект. Иногда это позволяет пройти входную валидацию, но способно изменить смысл контракта. Поля из взаимоисключающих ветвей окажутся рядом, прежде невозможные комбинации станут допустимыми, а правила обязательности потеряют точность. Workaround из пользовательского issue можно исследовать в изолированном окружении, но нельзя считать его универсальным исправлением без тестов для каждого действия инструмента.
Разработчикам следует включать strict mode осознанно, не воспринимая его как автоматическую санитарную обработку схемы на стороне любого провайдера. Нормализация, если она вообще происходит, зависит от конкретного endpoint и может отличаться от OpenAI API или Azure OpenAI.
- Проверяйте object-root отдельно от вложенных unions.
- Для каждого object-узла проверяйте additionalProperties и required по правилам выбранного маршрута.
- Не подменяйте семантическое преобразование схемы косметическим исправлением JSON.
От схемы до действия: почему одного валидатора мало
Даже схема, которую endpoint принял, ещё не делает инструмент надёжным. В агентной цепочке есть как минимум четыре контракта: описание функции, доступное модели; аргументы, сгенерированные моделью; серверный валидатор вызова; код, выполняющий побочный эффект. Разрыв возможен между любыми двумя звеньями. Библиотеки OpenAI для типизированного парсинга и типы Responses API показывают, насколько отдельно описываются формат инструмента и обработка результата.
Поэтому structural validation и execution validation должны стать разными стадиями CI. На первой команда проверяет исходящий JSON: object-root, запрещённые ключевые слова, required, additionalProperties, размер и глубину схемы, если маршрут их ограничивает. На второй инструмент отправляют в настоящий или выделенный тестовый endpoint, просят модель вызвать его в контролируемом сценарии и проверяют, что backend получил ожидаемые аргументы и вернул результат в корректной форме.
Это особенно существенно для инструментов, которые создают или изменяют автоматизации. При schema-400 корректная деградация: явно сообщить, что действие не было создано или обновлено. Нельзя заменять неисполненный side effect убедительным текстом об успехе. Это не особенность automation_update, а базовое требование к наблюдаемости агентных систем.
В предоставленных материалах нет российской статистики по Codex Desktop, automation_update и строгим маршрутам. Поэтому нельзя утверждать, что кейс уже массово затронул российские команды. Но общий вывод применим к любой команде, использующей шлюз, self-hosted proxy или несколько внешних endpoints: проверять нужно не абстрактную совместимость API, а инструментальный контракт каждого конкретного маршрута.
- Structural contract отвечает на вопрос: примет ли endpoint объявление tools?
- Execution contract отвечает на вопрос: завершится ли нужное действие с корректными аргументами?
- Оба контракта нужно проверять после обновления SDK, агента, модели, прокси или провайдера.
Что включить в production-практику уже сейчас
Первое правило: логировать и версионировать фактический outbound payload. Исходная Pydantic-, Zod- или TypeScript-модель не равна JSON, который мог преобразовать SDK, агентская среда или прокси. Полезно сохранять канонизированный JSON схемы с отсортированными ключами и его хеш, а рядом версию агента, SDK, model route и endpoint. Тогда внезапный 400 можно связать с конкретным изменением контракта, а не искать причину в промпте.
Второе правило: вести capability matrix. Для каждого маршрута в ней стоит фиксировать поддержку function tools, strict mode, object-root, unions во вложенных свойствах, namespace-представлений, parallel tool calls и server-side normalization. Azure для Structured Outputs отдельно указывает на необходимость отключать parallel_tool_calls при strict function calling. Это показательный пример того, почему проверки «tools работают» недостаточно.
Третье правило: запускать preflight-набор до переключения трафика. Достаточно нескольких синтетических схем: пустой объект, объект со вложенным объектом, обязательное nullable-поле, union внутри свойства, отрицательный тест с union на корне и namespaced tool, если он используется в продукте. Цель не в доказательстве полной совместимости, а в быстром выявлении критических расхождений на входной валидации.
Четвёртое правило: разделить каноническую модель инструмента и provider adapter. Внутри приложения можно хранить наиболее точную логическую схему, а на границе формировать payload под конкретный capability-профиль. Адаптер не должен молча упрощать oneOf: любое семантическое преобразование требует contract-тестов. Если маршрут не поддерживает встроенный инструмент, безопаснее не отправлять его в tools, чем рассчитывать на игнорирование со стороны сервера.
Наконец, schema-400 следует классифицировать как compatibility failure. Blind retry с тем же toolset почти наверняка добавит лишь задержку, расход токенов или дубли телеметрии. Возможные реакции: направить запрос через заранее протестированный маршрут, отключить несовместимый инструмент, предложить безопасный ручной путь или остановить операцию с диагностикой. В Issue #39848 нет официального workaround от OpenAI, поэтому любые обходы должны маркироваться как временные.
- Снимайте дамп tools после всех преобразований клиента и прокси.
- Тестируйте schema acceptance и реальное выполнение раздельно.
- Маршрутизируйте по capability-профилю, а не по общему ярлыку OpenAI-compatible.
- Не скрывайте сбой автоматизации за текстовым ответом агента.
Чек-лист проверки инструментального маршрута
Этот список можно использовать перед обновлением SDK, агента, модели, маршрутизатора или конфигурации tools.
Фактическая схема
Проверьте JSON, который уходит в endpoint после преобразований SDK, агентской среды и прокси.
Зафиксируйте хеш схемы, версию агента, SDK, модель, endpoint и режим API.
Проверьте object-root, required и additionalProperties по правилам конкретного маршрута.
Приём и выполнение
Отделите тест приёма объявления tools от теста реального вызова функции.
Проверьте, что backend получает ожидаемые аргументы и возвращает результат в корректной форме.
Для инструментов с побочным эффектом убедитесь, что при отказе пользователь получает статус невыполненного действия, а не текстовую имитацию успеха.
Маршрутизация и реакция на ошибку
Поддерживайте capability-профиль для каждого маршрута и не распространяйте один результат теста на все совместимые endpoint.
Добавьте отрицательный тест с union на корне, если такая конструкция может быть сформирована клиентом.
Классифицируйте Invalid schema, type null или None, must be object и unsupported keyword как ошибку совместимости, а не временный сбой.
Не используйте повторную отправку того же toolset как основной способ восстановления операции.
Что этот кейс меняет в подходе к агентам
Ценность Issue #39848 не в том, что он окончательно объясняет внутреннее устройство Codex Desktop. Он этого не делает: полного payload в публикации нет, а официального ответа или исправления на странице issue не видно. Но он показывает, что несовместимость инструментов может быть детерминированной, возникать до обращения к модели и маскироваться под обычную проблему стороннего провайдера.
Связанный Issue #37786 предлагает техническую гипотезу, основанную на наблюдаемой форме: root-level oneOf без type object. Azure OpenAI независимо описывает strict-ограничения, при которых обязательны объектный корень и закрытые object-схемы. Вместе эти источники позволяют уверенно говорить о классе риска, но не дают оснований считать причину окончательно установленной для всех версий Codex и всех endpoint.
Для платформенных команд зрелость агентной интеграции определяется не только качеством модели, числом доступных tools или скоростью failover. Значение имеет управляемый schema supply chain: путь от исходной модели типов к сериализованному payload, от capability-тестов к понятному поведению при отказе. Если этот путь наблюдаем и покрыт контрактными тестами, ошибка вида must be object остаётся локальным инцидентом. Если нет, один лишний встроенный tool может остановить бизнес-процесс ещё до участия модели.
Вывод
Проблема automation_update не означает, что OpenAI-compatible API бесполезны. Она требует точнее определить предмет совместимости: транспорт, типы tools, подмножество JSON Schema или полный цикл выполнения.
Пока Issue #39848 остаётся открытым без публично подтверждённого исправления, наиболее надёжный подход: исключать неподдерживаемые инструменты на проблемных маршрутах, выбирать заранее протестированный endpoint и относиться к schema contract как к версии API.
Источники
- OpenAI Codex: Issue #39848, automation_update tool schema is rejected by strict OpenAI-compatible providers
- OpenAI Codex: Issue #37786
- Microsoft Learn: Structured outputs for Azure OpenAI
- OpenAI Python: типы инструментов Responses API
- OpenAI Agents Python: function and output schema
- OpenAI Node: shared types
- OpenAI Python: типизированный parsing completions
Частые вопросы
Почему повторный запрос не исправляет ошибку schema 400?
Если клиент повторно отправляет тот же набор tools и тот же endpoint применяет те же правила, валидация снова остановит запрос до обращения к модели.
Означает ли OpenAI-compatible полную совместимость инструментов?
Нет. Совпадение маршрута и базового формата запроса не гарантирует одинаковую поддержку типов tools, strict mode, JSON Schema и выполнения вызова.
Можно ли всегда заменить корневой oneOf на object?
Нет. Такое преобразование может изменить смысл взаимоисключающих ветвей и расширить набор допустимых комбинаций аргументов. Оно требует контрактных тестов.
Какие проверки нужны для agent tools в production?
Нужны отдельные проверки принятия фактической schema endpoint и реального выполнения вызова с ожидаемыми аргументами и результатом.
Что должен сообщить агент при недоступности инструмента с побочным эффектом?
Он должен явно сообщить, что действие не создано или не обновлено. Текстовый ответ не должен имитировать успешное выполнение операции.
Практический чек-лист
Чек-лист проверки инструментального маршрута
Подготовить файл downloads/automation-update-tool-schema-checklist.pdf с этим чек-листом в печатной форме. В XLSX на листе Downloads добавить строку: filename=automation-update-tool-schema-checklist.pdf; title=Чек-лист совместимости tool schema; description=Памятка для проверки схем инструментов, strict-валидации и выполнения вызовов на конкретном API-маршруте; buttonLabel=Скачать PDF.
Фактическая схема
- Проверить JSON после преобразований SDK, агентской среды и прокси.
- Зафиксировать хеш схемы, версии агента и SDK, модель, endpoint и режим API.
- Сверить object-root, required и additionalProperties с правилами выбранного маршрута.
Приём и выполнение
- Разделить тест приёма tools и тест фактического вызова функции.
- Проверить аргументы, полученные backend, и форму результата.
- Убедиться, что отказ side effect не выдаётся за успешное действие.
Маршрутизация
- Вести capability-профиль для каждого маршрута.
- Добавить отрицательный тест с union на корне.
- Классифицировать schema-400 как ошибку совместимости, а не временный сбой.
Вопросы и ответы
Почему повторный запрос не исправляет ошибку schema 400?
Если клиент повторно отправляет тот же набор tools и тот же endpoint применяет те же правила, валидация снова остановит запрос до обращения к модели.
Означает ли OpenAI-compatible полную совместимость инструментов?
Нет. Совпадение маршрута и базового формата запроса не гарантирует одинаковую поддержку типов tools, strict mode, JSON Schema и выполнения вызова.
Можно ли всегда заменить корневой oneOf на object?
Нет. Такое преобразование может изменить смысл взаимоисключающих ветвей и расширить набор допустимых комбинаций аргументов. Оно требует контрактных тестов.
Какие проверки нужны для agent tools в production?
Нужны отдельные проверки принятия фактической schema endpoint и реального выполнения вызова с ожидаемыми аргументами и результатом.
Что должен сообщить агент при недоступности инструмента с побочным эффектом?
Он должен явно сообщить, что действие не создано или не обновлено. Текстовый ответ не должен имитировать успешное выполнение операции.