Статьи

Гайд по gpt-oss: как запустить новые модели OpenAI

Опенсорс LLM

OpenAI выкатила в опенсорс две новые модели — gpt-oss-120b и gpt-oss-20b. Бенчмарки, сравнения, громкие заголовки. Но кому-то хочется не только прочитать про релиз, а попробовать самому всё запустить. А если вы просто скачаете gpt-oss и попробуете запустить ее, как любую другую модель с Hugging Face, вас ждет разочарование. Она будет выдавать полную дичь.

Почему? Потому что эти модели не работают со стандартными промптами. Они требуют особого, проприетарного формата общения под названием Harmony Response Format. Давайте разберемся, как эта штука работает на самом деле, запустим ее с нуля, посмотрим на код и поймем все подводные камни.

Что такое gpt-oss?

Итак, что мы имеем?

  • Две модели: gpt-oss-120b (117B параметров) для дата-центров и gpt-oss-20b (21B параметров) для десктопов и ноутбуков.
  • Лицензия: Apache 2.0. Это значит — полная свобода. Модели можно использовать в коммерческих проектах, дообучать, кастомизировать без головной боли о копилефте.
  • Назначение: Модели заточены под "агентные" задачи. Они отлично следуют инструкциям и умеют пользоваться инструментами (function calling), включая поиск в вебе и исполнение Python-кода.
  • Полный CoT: Вы получаете доступ к полной "цепочке рассуждений" модели (Chain-of-Thought). Это плюс для отладки и повышения доверия к результатам.

Архитектура под капотом: что отличает gpt-oss от других

Здесь начинается самое интересное. OpenAI не просто выложила очередную LLM, а упаковала в нее несколько крутых и не самых очевидных решений.

MoE: Больше параметров, меньше вычислений

Обе модели — это Mixture-of-Experts (MoE). Если упрощать, то внутри модели сидит не один большой "мозг", а комитет из нескольких более мелких "экспертов". Для обработки каждого токена активируется не вся модель, а лишь небольшая часть этих экспертов.

  • gpt-oss-120b имеет 117B общих параметров, но только 5.1B активных параметров на токен.
  • gpt-oss-20b имеет 21B общих параметров, но всего 3.6B активных.

[!INFO] Что это дает на практике? Колоссальную экономию вычислительных ресурсов при инференсе. Модель сохраняет "знания" и сложность большой архитектуры, но требует значительно меньше вычислений, чем классическая плотная модель того же размера.

Квантизация MXFP4: Как 120B модель помещается на одну GPU

Еще одна ключевая фишка — 4-битная квантизация весов MoE-слоев в формате mxfp4. Это специальный 4-битный формат чисел с плавающей точкой, который позволяет очень сильно сжать веса с минимальными потерями в точности.

Результат впечатляет:

  • gpt-oss-120b умещается на одной GPU NVIDIA H100 (80 ГБ).
  • gpt-oss-20b запускается на железе с 16 ГБ видеопамяти, что делает ее доступной для мощных потребительских видеокарт.

Внимание, еще раз внимание: RoPE, Sliding Window и Attention Sinks

Механизм внимания тоже не так прост:

  • RoPE (Rotary Position Embeddings): Уже ставший стандартом индустрии способ кодирования позиций токенов.
  • Чередующиеся слои внимания: Модель использует слои с полным контекстом (до 128k токенов) и слои со "скользящим окном" в 128 токенов. Это еще один трюк для оптимизации вычислений на длинных последовательностях.
  • Attention Sinks: Специальная техника, которая помогает модели лучше фокусироваться на начальных токенах, что особенно важно для длинных контекстов. Интересно, что для ее поддержки в transformers добавили кастомный, сверхоптимизированный Flash Attention 3 кернел.

Разобрались с железом. Теперь к главному — к софту.

Главный подвох: формат Harmony

Как я уже писал, если вы попробуете подать в gpt-oss обычный промпт в формате [{"role": "user", "content": "..."}], как вы делаете для других моделей, вы получите несвязный бред.

Модели были натренированы на специальном, строго структурированном формате Harmony Response Format. Он имитирует OpenAI Responses API, но реализован через систему специальных токенов. Без соблюдения этого формата модель вас просто не поймет.

Что же это за формат такой? Он строится на двух ключевых концепциях: Роли и Каналы.

Роли (Roles)

Каждое сообщение в диалоге имеет строго определенную роль. Вот основные:

  • system: Мета-информация для модели (текущая дата, уровень детализации рассуждений).
  • developer: То, что мы привыкли называть "системным промптом". Здесь лежат инструкции для модели и описание доступных инструментов (functions).
  • user: Сообщение от пользователя.
  • assistant: Ответ от модели.
  • tool: Результат выполнения функции (tool call).

Важно, что роли имеют иерархию на случай конфликта инструкций: system > developer > user > assistant > tool.

Каналы (Channels)

Ответы ассистента (assistant) могут идти по трем разным "каналам", что позволяет разделять внутренние рассуждения модели и финальный ответ для пользователя.

  • final: Финальный ответ, который показывается пользователю.
  • analysis: Внутренние рассуждения модели, ее Chain-of-Thought. Эти сообщения нельзя показывать пользователям, так как на них не распространяются те же стандарты безопасности, что и на final-ответы.
  • commentary: Канал для вызова функций и вывода комментариев о плане действий.

Вся эта структура кодируется с помощью специальных токенов вроде <|start|>, <|end|>, <|message|>, <|channel|>. Собирать такие промпты вручную — адский труд. К счастью, OpenAI предоставила для этого специальную библиотеку.

Запуск gpt-oss: код и оптимизации

Для начала установим все необходимое. OpenAI рекомендует использовать библиотеку transformers, а для корректной работы с форматом Harmony — openai-harmony.

pip install transformers torch openai-harmony

Библиотека openai_harmony

Эта небольшая библиотека — спасение для любого, кто хочет работать с gpt-oss. Она берет на себя всю грязную работу по преобразованию стандартных диалоговых структур в сложный формат Harmony.

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

# Импортируем все необходимые классы
from openai_harmony import (
    Author,
    Conversation,
    DeveloperContent,
    HarmonyEncodingName,
    Message,
    Role,
    SystemContent,
    ToolDescription,
    load_harmony_encoding,
    ReasoningEffort
)

# 1. Загружаем специальный кодировщик для gpt-oss
encoding = load_harmony_encoding(HarmonyEncodingName.HARMONY_GPT_OSS)

# 2. Создаем системное сообщение (system message)
# Это мета-информация для модели
system_message = (
    SystemContent.new()
        .with_model_identity(
            "You are ChatGPT, a large language model trained by OpenAI."
        )
        .with_reasoning_effort(ReasoningEffort.HIGH) # Задаем высокий уровень детализации рассуждений
        .with_conversation_start_date("2025-08-06")
        .with_knowledge_cutoff("2024-06")
        .with_required_channels(["analysis", "commentary", "final"])
)

# 3. Создаем сообщение разработчика (developer message)
# Здесь живут наши инструкции и описание инструментов
developer_message = (
    DeveloperContent.new()
        .with_instructions("Always respond in a witty and slightly sarcastic tone.")
        .with_function_tools(
            [
                ToolDescription.new(
                    "get_current_weather",
                    "Gets the current weather in the provided location.",
                    parameters={
                        "type": "object",
                        "properties": {
                            "location": {
                                "type": "string",
                                "description": "The city and state, e.g. San Francisco, CA",
                            },
                            "format": {
                                "type": "string",
                                "enum": ["celsius", "fahrenheit"],
                                "default": "celsius",
                            },
                        },
                        "required": ["location"],
                    },
                ),
            ]
        )
)

# 4. Собираем всю беседу в один объект Conversation
convo = Conversation.from_messages(
    [
        Message.from_role_and_content(Role.SYSTEM, system_message),
        Message.from_role_and_content(Role.DEVELOPER, developer_message),
        Message.from_role_and_content(Role.USER, "What is the weather in Moscow?"),
    ]
)

# 5. Рендерим беседу в токены, готовые для подачи в модель
# Указываем, что мы ждем ответа от ассистента
tokens = encoding.render_conversation_for_completion(convo, Role.ASSISTANT)

print(f"Total tokens to be processed: {len(tokens)}")

[!TIP] Что здесь произошло? Мы не склеивали строки со спецтокенами вручную. Мы описали нашу задачу на высоком уровне (системные настройки, инструкции, функции, диалог), а openai_harmony сама сгенерировала корректную последовательность токенов, которую "поймет" gpt-oss.

Базовый инференс с transformers

Теперь, когда у нас есть правильно сформированные токены, мы можем запустить модель. Возьмем gpt-oss-20b как более доступный вариант.

from transformers import AutoModelForCausalLM, AutoTokenizer

# Замените на gpt-oss-120b, если у вас есть подходящее железо
model_id = "openai/gpt-oss-20b" 

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto", # Автоматически распределит модель по GPU
    torch_dtype="auto", # Использует bfloat16 или float16 если доступно
)

# Используем наши токены из предыдущего примера
# Обратите внимание, мы передаем `input_ids` напрямую
inputs = {"input_ids": torch.tensor([tokens]).to(model.device)}

# Генерируем ответ
generated_ids = model.generate(**inputs, max_new_tokens=200, do_sample=True)

# Чтобы распарсить ответ, снова используем openai_harmony
# Это нужно для правильной обработки каналов и спецтокенов
new_tokens = generated_ids[0][len(tokens):].tolist()
parsed_response = encoding.parse_messages_from_completion_tokens(new_tokens, Role.ASSISTANT)

# Выводим результат
for message in parsed_response:
    print(f"----- Channel: {message.channel} -----")
    if message.recipient:
        print(f"Recipient: {message.recipient}")
    print(message.content)

Этот код уже можно запускать. Но есть нюансы по оптимизации.

Оптимизации для разного железа

OpenAI и Hugging Face позаботились о том, чтобы инференс был максимально быстрым.

Для владельцев Hopper (H100/H200)

Если вам повезло иметь доступ к последнему поколению GPU от NVIDIA, вы можете включить кастомный кернел для Flash Attention 3, который поддерживает Attention Sinks. Это даст максимальную производительность.

Сначала установите его: pip install --upgrade kernels

Затем добавьте один параметр при загрузке модели:

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    torch_dtype="auto",
    # Включаем кастомный кернел
    attn_implementation="kernels-community/vllm-flash-attn3", 
)

Для всех остальных (Ampere, Ada Lovelace и т.д.)

Если у вас нет Hopper GPU, вы не сможете использовать mxfp4 квантизацию "из коробки". Но вы можете получить ускорение для MoE-слоев с помощью MegaBlocks.

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    torch_dtype="auto", # MegaBlocks требует bfloat16
    # Включаем оптимизированные кернелы MegaBlocks
    use_kernels=True,
)

[!WARNING] Использование use_kernels=True требует, чтобы модель работала в bfloat16, что увеличит потребление памяти по сравнению с mxfp4. Если у вас есть выбор, mxfp4 на Hopper всегда предпочтительнее.

Разбираем Function Calling и Chain-of-Thought

Давайте посмотрим, как модель использует свои главные фичи на практике. Представим, что мы запустили наш код с запросом про погоду в Москве.

Ответ модели (представленный через parsed_response) будет выглядеть примерно так:

Первое сообщение:

----- Channel: analysis -----
The user is asking for the weather in Moscow. I have a tool `get_current_weather` that can help with this. I should call it with the location "Moscow".

Второе сообщение:

----- Channel: commentary -----
Recipient: functions.get_current_weather
{"location": "Moscow", "format": "celsius"}

Это и есть Tool Call. Модель не просто ответила, а сформировала запрос к нашему инструменту. На этом этапе model.generate() остановится.

Наша задача — "поймать" этот вызов, исполнить нашу Python-функцию get_current_weather("Moscow"), получить результат (например, {"temperature": 18, "condition": "Cloudy"}) и скормить его обратно в модель для следующего шага.

Мы должны добавить в нашу историю диалога два сообщения: сам вызов от ассистента и наш ответ от имени инструмента.

# ... предыдущий код ...

# Добавляем вызов инструмента в историю
convo.add_message(
    Message.from_role_and_content(Role.ASSISTANT, '{"location": "Moscow", "format": "celsius"}')
    .with_channel("commentary")
    .with_recipient("functions.get_current_weather")
    .with_content_type("json")
)

# Имитируем выполнение функции и добавляем результат
tool_result = '{"temperature": 18, "condition": "Cloudy"}'
convo.add_message(
    Message.from_author_and_content(
        Author.new(Role.TOOL, "functions.get_current_weather"),
        tool_result,
    ).with_recipient("assistant").with_channel("commentary")
)

# Снова рендерим токены и запускаем generate...
# ... и так до тех пор, пока не получим ответ в канале 'final'

После второго запуска generate модель, получив данные о погоде, выдаст что-то вроде:

Первое сообщение (CoT):

----- Channel: analysis -----
I have received the weather data for Moscow. The temperature is 18 degrees Celsius and it's cloudy. Now I need to formulate a witty and sarcastic final response for the user.

Второе сообщение (финальный ответ):

----- Channel: final -----
Oh, you want to know the weather in Moscow? How original. Well, brace yourself for a thrilling 18 degrees and clouds. Try not to get too excited.

Вот так и работает полный цикл: User -> CoT -> Tool Call -> Tool Result -> CoT -> Final Answer.

Выводы: кому и зачем это нужно?

OpenAI сделала очень интересный ход. Они не просто выложили веса, а предложили целую экосистему для построения сложных, управляемых ИИ-агентов.

[!NOTE] Кому стоит обратить внимание на gpt-oss?

  1. Разработчикам ИИ-агентов и сложных систем. Возможность управлять CoT и надежный function calling — это золото для вас.
  2. Компаниям, которым важна кастомизация. Полный доступ к весам и permissive-лицензия позволяют дообучать модель под любые специфические задачи.
  3. Исследователям. Открытая архитектура с интересными решениями (MoE, Attention Sinks) — отличное поле для экспериментов.

[!DANGER] Кому стоит быть осторожнее?

  1. Новичкам. Если вы просто хотите "поиграться с нейронкой", сложность с форматом Harmony может стать серьезным барьером. Есть модели с более низким порогом входа.
  2. Тем, кто ищет "коробочное" решение. gpt-oss — это не готовый продукт, а мощный, но требовательный полуфабрикат. Чтобы получить от него максимум, придется повозиться.

Полезные ссылки: