Формат ответа OpenAI harmony
gpt-oss
модели обучались с использованием формата ответа harmony для определения структур диалога, генерации рассуждений и структурирования вызовов функций. Если вы не используете gpt-oss
напрямую, а через API или поставщика, например Ollama, вам не придется беспокоиться об этом, так как ваше решение для инференса само обработает форматирование. Если вы строите собственное решение для инференса, это руководство поможет вам с форматом промпта. Формат разработан так, чтобы имитировать OpenAI Responses API, поэтому, если вы раньше использовали этот API, формат должен показаться вам знакомым. gpt-oss
не следует использовать без формата harmony, так как он не будет работать корректно.
Концепции
Роли
Каждое сообщение, которое обрабатывает модель, имеет связанную с ним роль. Модель знает пять типов ролей:
Роль | Назначение |
---|---|
system | Системное сообщение используется для указания усилий по рассуждению, метаинформации, такой как дата ограничения знаний, и встроенных инструментов |
developer | Сообщение разработчика используется для предоставления информации об инструкциях для модели (то, что обычно считается «системным промптом») и доступных инструментах функций |
user | Обычно представляет ввод для модели |
assistant | Вывод модели, который может быть вызовом инструмента или сообщением. Вывод может быть также связан с определённым «каналом», указывающим намерение сообщения. |
tool | Сообщения, представляющие вывод вызова инструмента. В роли сообщения будет использовано название конкретного инструмента. |
Эти роли также отражают иерархию информации, которую модель применяет в случае конфликтов в инструкциях: system
> developer
> user
> assistant
> tool
Каналы
Сообщения ассистента могут выводиться в трёх разных «каналах». Они используются для разделения ответов, ориентированных на пользователя, и внутренних сообщений.
Канал | Назначение |
---|---|
final | Сообщения, помеченные как final channel, предназначены для отображения конечному пользователю и представляют собой ответы модели. |
analysis | Сообщения, которые модель использует для своей цепочки рассуждений (Chain of Thought, CoT). Важно: Сообщения в analysis channel не соответствуют тем же стандартам безопасности, что и финальные сообщения. Избегайте их показа конечным пользователям. |
commentary | Любой вызов функции обычно инициируется в commentary канале, тогда как встроенные инструменты обычно вызываются в analysis канале. Однако иногда встроенные инструменты могут также выводиться в commentary . Иногда этот канал используется моделью для генерации преамбулы для вызова нескольких функций. |
Библиотека renderer harmony
Рекомендуется использовать наш harmony renderer через PyPI или crates.io, так как он автоматически подготовит ваши сообщения в нужном формате и преобразует их в токены для обработки моделью.
Ниже приведён пример использования renderer для построения системного промпта и короткого диалога.
<<<FENCE_0>>>
Кроме того, библиотека openai_harmony включает StreamableParser для парсинга и декодирования во время генерации новых токенов моделью. Это может быть полезно, например, для потоковой передачи вывода и обработки юникодных символов при декодировании.
<<<FENCE_1>>>
Формат промпта
Если вы решите создать собственный renderer, нужно будет придерживаться следующего формата.
Специальные токены
Модель использует набор специальных токенов для идентификации структуры вашего ввода. Если вы используете tiktoken, эти токены кодируются в кодировке o200k_harmony
. Все специальные токены следуют формату <|type|>
.
Специальный токен | Назначение | ID токена |
---|---|---|
<|start|> | Обозначает начало сообщения. Следует за «заголовком» сообщения, начинающимся с роли | 200006 |
<|end|> | Обозначает конец сообщения | 200007 |
<|message|> | Обозначает переход от «заголовка» сообщения к его содержимому | 200008 |
<|channel|> | Обозначает переход к информации о канале заголовка | 200005 |
<|constrain|> | Обозначает переход к определению типа данных в вызове инструмента | 200003 |
<|return|> | Обозначает, что модель закончила выборку ответа. Действительный «стоп-токен», указывающий на необходимость остановить инференс | 200002 |
<|call|> | Обозначает, что модель хочет выполнить вызов инструмента. Действительный «стоп-токен», указывающий на необходимость остановить инференс | 200012 |
Формат сообщения
Формат ответа harmony состоит из «сообщений», при этом модель может сгенерировать несколько сообщений за раз. Общая структура сообщения:
<<<FENCE_2>>>
{header}
содержит набор метаинформации, включая роль. <|end|>
указывает конец полностью сформированного сообщения, но модель может использовать и другие стоп-токены, такие как <|call|>
для вызова инструмента и <|return|>
для обозначения окончания генерации.
Формат чат-диалога
Следуя формату сообщения, самый базовый формат чата состоит из сообщения user
и начала сообщения assistant
.
Пример ввода
<<<FENCE_3>>>
Вывод начнётся с указания channel
. Например, analysis
для вывода цепочки рассуждений. Модель может вывести несколько сообщений (в основном сообщений с цепочкой рассуждений), которые она разделяет токеном <|end|>
.
После окончания генерации она завершит либо токеном <|return|>
, указывающим на завершение итогового ответа, либо <|call|>
, указывающим необходимость вызова инструмента. В любом случае это значит, что нужно прекратить инференс.
Пример вывода
<<<FENCE_4>>>
Канал final
будет содержать ответ на запрос вашего пользователя. Подробнее о цепочке рассуждений читайте в разделе reasoning.
Примечание по реализации: <|return|>
— это стоп-токен только во время декодирования. Когда вы добавляете сгенерированный ответ ассистента в историю диалога для следующего шага, замените конечный <|return|>
на <|end|>
, чтобы хранящиеся сообщения были полностью сформированы как <|start|>{header}<|message|>{content}<|end|>
. Соответственно, предыдущие сообщения в промптах должны заканчиваться <|end|>
. Для руководимых целей/тренировочных примеров окончание через <|return|>
подходит; для сохранённой истории нормализуйте к <|end|>
.
Формат системного сообщения
Системное сообщение используется для предоставления общей информации системе. Это отличается от того, что обычно принято называть «системным промптом» в других форматах. Для этого смотрите формат developer message.
Мы используем системное сообщение, чтобы задать:
- Идентичность модели — должна всегда оставаться
You are ChatGPT, a large language model trained by OpenAI.
. Если хотите изменить идентичность модели, используйте инструкции в developer message. - Мета даты — конкретно
Knowledge cutoff:
иCurrent date:
. - Усилия по рассуждению — указываются уровни
high
,medium
,low
. - Доступные каналы — для лучшей производительности их следует сопоставить с
analysis
,commentary
, иfinal
. - Встроенные инструменты — модель обучена на
python
иbrowser
инструментах. Подробнее в разделе built-in tools.
Если вы определяете функции, в системном сообщении должна быть также запись, что все вызовы функций должны идти в канал commentary
.
Для лучшей производительности придерживайтесь этого формата как можно точнее.
Пример системного сообщения
Самое базовое системное сообщение выглядит так:
<<<FENCE_5>>>
Если в разделе developer message присутствуют вызовы функций, используйте:
<<<FENCE_6>>>
Формат сообщения разработчика
Сообщение разработчика представляет то, что обычно считается «системным промптом». Оно содержит инструкции для модели и опционально список доступных функций или формат вывода, которому должна следовать модель для структурированных ответов.
Если вы не используете вызовы функций, ваше сообщение разработчика будет выглядеть так:
<<<FENCE_7>>>
Где {instructions}
заменяется вашим «системным промптом».
Для определения функций см. раздел по вызову функций.
Для задания формата вывода для структурированных ответов см. этот раздел.
Рассуждения
Модели gpt-oss — модели рассуждений. По умолчанию модель выполняет рассуждения среднего уровня. Чтобы контролировать уровень рассуждений, в системном сообщении можно указать уровень рассуждений как low
, medium
, или high
. Рекомендуемый формат:
<<<FENCE_8>>>
Модель выводит необработанную цепочку рассуждений (CoT) как сообщения ассистента в канал analysis
, а окончательный ответ в канал final
.
Например, для вопроса What is 2 + 2?
вывод модели может выглядеть так:
<<<FENCE_9>>>
В этом случае цепочка рассуждений:
<<<FENCE_10>>>
А сам ответ:
<<<FENCE_11>>>
Важное предупреждение:
Модель не обучена по тем же стандартам безопасности для цепочки рассуждений, что и для итогового вывода. Не следует показывать цепочку рассуждений пользователям, так как она может содержать вредоносный контент. Подробнее в карточке модели.
Обработка вывода рассуждений при последующих сэмплированиях
В общем случае вы должны отбросить предыдущий CoT при последующем сэмплировании, если вывод ассистента закончился сообщением в канал final
. Например, если первый ввод был:
<<<FENCE_12>>>
и привёл к выводу:
<<<FENCE_13>>>
Для корректной работы модели следующий ввод должен быть:
<<<FENCE_14>>>
Исключением являются вызовы инструментов/функций. Модель может вызывать инструменты в своей цепочке рассуждений, и поэтому предыдущую цепочку рассуждений следует передавать в качестве входных данных при последующих сэмплированиях. Смотрите полный пример в разделе function calling.
Вызов функций
Определение доступных инструментов
Все функции, доступные модели, должны быть определены в сообщении разработчика в выделенном разделе Tools
.
Для определения функций используется синтаксис, похожий на TypeScript, и функции оборачиваются в пространство имён functions
. Важно строго придерживаться этого формата для повышения точности вызова функций. Вы можете ознакомиться с кодовой базой harmony renderer, чтобы понять, как JSON схему аргументов превращают в этот формат, но основные правила:
- Определяйте функцию как
type {function_name} = () => any
если она не принимает аргументов - Для функций с аргументами называйте аргумент
_
и описывайте его тип inline - Добавляйте комментарии с описаниями строкой выше определения поля
- Всегда используйте
any
как тип возвращаемого значения - Оставляйте пустую строку после каждого определения функции
- Оборачивайте функции в пространство имён, обычно
functions
— это пространство имён, чтобы не конфликтовать с встроенными инструментами модели
Пример полного ввода с определением двух функций:
<<<FENCE_15>>>
Приём вызовов инструментов
Если модель решит вызвать инструмент, в заголовке сообщения будет определён recipient
с форматом to={name}
. Например, если она выбирает вызвать функцию get_current_weather
из вышеописанных, в заголовке будет to=functions.get_current_weather
и канал будет commentary
согласно системному сообщению. Получатель может быть указан в разделе роли или канала заголовка.
Модель также может использовать токен <|constrain|>
для указания типа ввода для вызова инструмента. В данном случае при передаче JSON <|constrain|>
устанавливается в json
.
<<<FENCE_16>>>
Обработка вызовов инструментов
После выполнения вызова функции нужно вернуть результат модели, указав новое сообщение с выводом после сообщения вызова.
Сообщение инструмента имеет следующий формат:
<<<FENCE_17>>>
В нашем примере:
<<<FENCE_18>>>
После получения вывода вызова инструмента вы можете выполнить инференс с полным содержимым:
<<<FENCE_19>>>
Как видно, в модель передаётся не только вывод функции, но и предыдущая цепочка рассуждений («Need to use function get_current_weather.»), чтобы предоставить модели необходимую информацию для продолжения рассуждений или выдачи окончательного ответа.
Преамбулы
Иногда модель может подготовить «преамбулу», чтобы уведомить пользователя о предстоящих вызовах функций, например, если планируется вызвать несколько функций. В этом случае она создаст сообщение ассистента в канале commentary
, которое, в отличие от цепочки рассуждений, предназначено для отображения конечному пользователю.
<<<FENCE_20>>>
В данном примере модель сформировала план действий, чтобы проинформировать пользователя о нескольких шагах, которые она собирается выполнить.
Структурированный вывод
Чтобы управлять поведением вывода модели, можно задать формат ответа в конце сообщения разработчика со следующей структурой:
<<<FENCE_21>>>
Имя формата функционирует аналогично имени, которое указывают для своей схемы в Responses API, а схема — это JSON Schema.
В качестве примера, вот сообщение разработчика, определяющее схему для списка покупок:
<<<FENCE_22>>>
Однако этот промпт лишь влияет на поведение модели, но не гарантирует полного соблюдения схемы. Для этого вам нужно построить собственную грамматику и обеспечить соблюдение схемы во время сэмплирования.
Встроенные инструменты
Во время обучения gpt-oss
моделей они обучались работе с двумя распространёнными инструментами: браузером для поиска информации и исполнением кода на Python для улучшения результатов.
Если вы хотите воссоздать эту функциональность, используйте следующий формат для повышения надёжности и точности.
Эти инструменты должны быть определены в системном сообщении, а не в сообщении разработчика, путём добавления раздела # Tools
.
Инструмент браузера
Чтобы добавить инструмент браузера, добавьте его в секцию системного промта:
<<<FENCE_23>>>
Если модель решит вызвать действие браузера, она будет использовать тот же формат, что и для вызова функций, с двумя важными отличиями:
- Запросы будут отправляться в канал
analysis
- Получателем будет
browser.search
,browser.open
,browser.find
соответственно
Инструмент Python
<<<FENCE_24>>>
Если модель решит выполнить Python-код, она будет использовать тот же формат, что и для вызова функций, с двумя важными отличиями:
- Запросы будут отправляться в канал
analysis
- Получателем всегда будет
python