Представляем структурированные выводы в API

Мы представляем функцию структурированных выводов (Structured Outputs) в API — теперь результаты работы моделей надежно соответствуют схемам JSON, заданным разработчиком.

The image shows an abstract pattern of small squares in varying shades of blue, green, and light yellow. The squares are arranged in a grid-like formation, creating a mosaic effect with a soft, pastel color palette.

В прошлом году на DevDay мы представили JSON-режим — полезный инструмент для разработчиков, стремящихся создавать надежные приложения с использованием наших моделей. Хотя JSON-режим повышает надежность модели при генерации валидного вывода в формате JSON, он не гарантирует, что ответ модели будет соответствовать конкретной схеме. Сегодня мы представляем Структурированные выводы (Structured Outputs) в API — новую функцию, разработанную для того, чтобы сгенерированные моделью результаты точно соответствовали предоставленным разработчиками схемам JSON Schema.

Генерация структурированных данных из неструктурированных входных данных — один из ключевых вариантов использования ИИ в современных приложениях. Разработчики используют OpenAI API для создания мощных ассистентов, способных получать данные и отвечать на вопросы посредством вызова функций (function calling), извлекать структурированные данные для их ввода и создавать многошаговые агентные рабочие процессы, позволяющие LLM совершать действия. Разработчики долгое время обходили ограничения LLM в этой области с помощью инструментов с открытым исходным кодом, промптинга и многократного повторения запросов, чтобы гарантировать соответствие вывода модели форматам, необходимым для взаимодействия с их системами. Структурированные выводы решают эту проблему, ограничивая модели OpenAI в соответствии предоставленным разработчиком схемам и обучая наши модели лучше понимать сложные схемы.

При оценке соблюдения сложных схем JSON наша новая модель gpt-4o-2024-08-06 со структурированными выводами набирает идеальные 100%. Для сравнения, gpt-4-0613 набирает менее 40%.

Благодаря структурированным выводам gpt-4o-2024-08-06 достигает 100-процентной надежности в наших оценках, идеально подстраиваясь под выходные схемы.

Как использовать структурированные выводы

Мы представляем структурированные выводы в API в двух формах:

1. Вызов функций (Function calling): структурированные выводы через tools доступны при установке strict: true в определении вашей функции. Эта функция работает со всеми моделями, поддерживающими инструменты, включая все модели gpt-4-0613, а также gpt-3.5-turbo-0613 и более поздние версии. Когда структурированные выводы включены, результаты работы модели будут соответствовать предоставленному определению инструмента.

2. Новый вариант для параметра response_format: теперь разработчики могут передавать JSON Schema с помощью json_schema, нового параметра для response_format. Это полезно, когда модель не вызывает инструмент, а отвечает пользователю в структурированном виде. Эта функция работает с нашими новейшими моделями GPT-4o: gpt-4o-2024-08-06 (выпущенной сегодня) и gpt-4o-mini-2024-07-18. Когда response_format предоставляется вместе с strict: true, результаты работы модели будут соответствовать предоставленной схеме.

Безопасные структурированные выводы

Безопасность является главным приоритетом для OpenAI — новая функциональность структурированных выводов будет соответствовать нашим существующим правилам безопасности и по-прежнему позволит модели отклонять небезопасные запросы. Чтобы упростить разработку, в ответах API появилось новое строковое значение refusal, которое позволяет разработчикам программно определять, сгенерировала ли модель отказ вместо вывода, соответствующего схеме. Если ответ не содержит отказа и работа модели не была преждевременно прервана (как указано в finish_reason), то ответ модели будет надежно генерировать действительный JSON, соответствующий предоставленной схеме.

JSON

1
{
2
"id": "chatcmpl-9nYAG9LPNonX8DAyrkwYfemr3C8HC",
3
"object": "chat.completion",
4
"created": 1721596428,
5
"model": "gpt-4o-2024-08-06",
6
"choices": [
7
{
8
"index": 0,
9
"message": {
10
"role": "assistant",
11
"refusal": "I'm sorry, I cannot assist with that request."
12
},
13
"logprobs": null,
14
"finish_reason": "stop"
15
}
16
],
17
"usage": {
18
"prompt_tokens": 81,
19
"completion_tokens": 11,
20
"total_tokens": 92
21
},
22
"system_fingerprint": "fp_3407719c7f"
23
}

Нативная поддержка SDK

Наши SDK для Python и Node были обновлены и теперь включают встроенную поддержку структурированных выводов. Предоставление схемы для инструментов или в качестве формата ответа так же просто, как передача объекта Pydantic или Zod, а наши SDK позаботятся о преобразовании типа данных в поддерживаемую схему JSON, автоматическом десериализации ответа JSON в типизированную структуру данных и разборе отказов в случае их возникновения.

В следующих примерах показана нативная поддержка структурированных выводов при вызове функций.

Нативная поддержка структурированных выводов также доступна для response_format.

Дополнительные варианты использования

Разработчики часто используют модели OpenAI для генерации структурированных данных для различных сценариев. Вот еще несколько примеров:

Динамическая генерация пользовательских интерфейсов на основе намерений пользователя

Например, разработчики могут использовать структурированные выводы для создания приложений, генерирующих код или интерфейсы (UI). Все следующие примеры используют одну и ту же схему ###NON_TRAN_20### (в оригинале response_format) и могут применяться для создания различных UI на основе пользовательского ввода.

Система
You are a user interface assistant. Your job is to help users visualize their website and app ideas.
Формат ответа
Ассистент

Отделение окончательного ответа от поддерживающих рассуждений или дополнительных комментариев

Может быть полезно выделить модели отдельное поле для цепочки рассуждений (chain of thought), чтобы повысить итоговое качество ответа.

Извлечение структурированных данных из неструктурированных

Например, поручение модели извлекать такие элементы, как задачи, сроки выполнения и поручения из заметок о совещаниях.

Под капотом

Мы применили комплексный подход к повышению надежности результатов работы моделей, соответствующих схеме JSON Schema. Во-первых, мы обучили нашу новейшую модель gpt-4o-2024-08-06 понимать сложные схемы и наилучшим образом создавать соответствующие им выводы. Тем не менее, поведение модели по своей сути не детерминировано — несмотря на улучшения производительности этой модели (93% в нашем бенчмарке), она все же не дотягивала до уровня надежности, необходимого разработчикам для создания надежных приложений. Поэтому мы также использовали детерминированный инженерный подход для ограничения вывода модели с целью достижения 100-процентной надежности.

Ограниченное декодирование (Constrained decoding)

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

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

JSON

1
{
2
"type": "object",
3
"properties": {
4
"value": { "type": "number" }
5
},
6
"required": ["value"],
7
"additionalProperties": false
8
}

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

Для этого мы преобразуем предоставленную схему JSON Schema в контекстно-свободную грамматику (КСГ). Грамматика — это набор правил, определяющих язык, а контекстно-свободная грамматика — это грамматика, которая подчиняется определенным правилам. JSON и JSON Schema можно рассматривать как конкретные языки с правилами, определяющими, что является допустимым в рамках этого языка. Точно так же, как в русском языке предложение без глагола считается некорректным, в JSON недопустима лишняя запятая на конце.

Таким образом, для каждой схемы JSON Schema мы вычисляем грамматику, которая ее представляет, и предварительно обрабатываем ее компоненты, чтобы к ним можно было легко получить доступ во время выборки моделью. Именно поэтому первый запрос с новой схемой влечет за собой задержку — мы должны предварительно обработать схему, чтобы сгенерировать этот артефакт, который мы сможем эффективно использовать в процессе выборки.

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

Альтернативные подходы

Альтернативные подходы к этой проблеме часто используют конечные автоматы (FSM) или регулярные выражения (обычно реализуемые с помощью FSM) для декодирования с ограничениями. Они функционируют аналогичным образом, динамически обновляя список допустимых токенов после генерации каждого токена, однако между ними и подходом на основе КСГ имеются ключевые различия. В частности, КСГ могут выражать более широкий класс языков, чем FSM. На практике это не имеет значения для очень простых схем, таких как схема value, показанная выше. Тем не менее, мы обнаружили, что это различие имеет значение для более сложных схем, включающих вложенные или рекурсивные структуры данных. Например, FSM, как правило, не могут выражать рекурсивные типы, что означает, что подходы на основе FSM могут испытывать трудности с согласованием скобок в глубоко вложенном JSON. Ниже представлен пример рекурсивной схемы, которая поддерживается в OpenAI API с Structured Outputs, но которую невозможно выразить с помощью FSM.

JSON

1
{
2
"name": "ui",
3
"description": "Dynamically generated UI",
4
"strict": true,
5
"schema": {
6
"type": "object",
7
"properties": {
8
"type": {
9
"type": "string",
10
"description": "The type of the UI component",
11
"enum": ["div", "button", "header", "section", "field", "form"]
12
},
13
"label": {
14
"type": "string",
15
"description": "The label of the UI component, used for buttons or form fields"
16
},
17
"children": {
18
"type": "array",
19
"description": "Nested UI components",
20
"items": {
21
"$ref": "#"
22
}
23
},
24
"attributes": {
25
"type": "array",
26
"description": "Arbitrary attributes for the UI component, suitable for any element",
27
"items": {
28
"type": "object",
29
"properties": {
30
"name": {
31
"type": "string",
32
"description": "The name of the attribute, for example onClick or className"
33
},
34
"value": {
35
"type": "string",
36
"description": "The value of the attribute"
37
}
38
}
39
}
40
}
41
},
42
"required": ["type", "label", "children", "attributes"],
43
"additionalProperties": false
44
}
45
}

Обратите внимание, что каждый элемент пользовательского интерфейса может содержать произвольные дочерние элементы, которые ссылаются на корневую схему рекурсивно. Такая гибкость обеспечивается именно благодаря подходу на основе КСГ.

Ограничения

При использовании Structured Outputs следует учитывать несколько ограничений:

  • Structured Outputs поддерживает только подмножество JSON Schema, подробно описанное в нашей документации. Это помогает нам обеспечить наилучшую производительность.
  • Первый ответ API с новой схемой потребует дополнительной задержки, но последующие ответы будут быстрыми и без задержек. Это связано с тем, что во время первого запроса мы обрабатываем схему, как указано выше, а затем кэшируем эти артефакты для быстрого повторного использования в дальнейшем. Обработка типичных схем занимает менее 10 секунд при первом запросе, но для более сложных схем может потребоваться до минуты.
  • Модель может не следовать схеме, если она решит отклонить небезопасный запрос. В случае отказа в возвращаемом сообщении булево значение refusal будет установлено в true для обозначения этого факта.
  • Модель может не следовать схеме, если генерация достигает max_tokens или другого условия остановки до завершения.
  • Structured Outputs не предотвращает все виды ошибок модели. Например, модель все равно может допустить ошибки в значениях объекта JSON (например, ошибиться на каком-то шаге в математическом уравнении). Если разработчики обнаруживают ошибки, мы рекомендуем приводить примеры в системных инструкциях или разбивать задачи на более простые подзадачи.
  • Structured Outputs несовместим с параллельными вызовами функций. Когда генерируется параллельный вызов функции, он может не соответствовать предоставленным схемам. Установите parallel_tool_calls: false, чтобы отключить параллельный вызов функций.
  • Схемы JSON Schema, предоставляемые с Structured Outputs, не подпадают под требования режима Zero Data Retention (ZDR).

Доступность

Функция Structured Outputs теперь общедоступна в API.

Функция Structured Outputs с поддержкой вызова функций доступна на всех моделях, поддерживающих вызов функций в API. Сюда входят наши новейшие модели (gpt-4o, gpt-4o-mini), все модели, начиная с gpt-4-0613 и gpt-3.5-turbo-0613 (включая их самих), а также любые дообученные модели, поддерживающие вызов функций. Эта функциональность доступна в Chat Completions API, Assistants API и Batch API. Structured Outputs с вызовом функций также совместима с визуальными входными данными.

Structured Outputs с форматами ответов доступна в моделях gpt-4o-mini и gpt-4o-2024-08-06, а также в любых дообученных версиях на их основе. Эта функциональность доступна в Chat Completions API, Assistants API и Batch API. Structured Outputs с форматами ответов также совместима с визуальными входными данными.

Перейдя на новую модель gpt-4o-2024-08-06, разработчики экономят 50% на входных данных ($2.50 за 1 млн токенов на входе) и 33% на выходных данных ($10.00 за 1 млн токенов на выходе) по сравнению с gpt-4o-2024-05-13.

Чтобы начать использовать Structured Outputs, ознакомьтесь с нашей документацией.

Выражение признательности

При создании Structured Outputs мы вдохновлялись отличной работой сообщества разработчиков открытого ПО, а именно библиотеками outlines, jsonformer, instructor, guidance и lark.

Автор

Michelle Pokrass

Основные участники разработки

Chris Colby, Melody Guan, Michelle Pokrass, Ted Sanders, Brian Zhang

Благодарности

John Allard, Filipe de Avila Belbute Peres, Ilan Bigio, Owen Campbell-Moore, Chen Ding, Atty Eleti, Elie Georges, Katia Gil Guzman, Jeff Harris, Johannes Heidecke, Beth Hoover, Romain Huet, Tomer Kaftan, Jillian Khoo, Karolis Kosas, Ryan Liu, Kevin Lu, Lindsay McCallum, Rohan Nuttall, Joe Palermo, Leher Pathak, Ishaan Singal, Felipe Petroski Such, Freddie Sulit, David Weedon

Полный текст статьи читайте на OpenAI