Я тут недавно начал играться с расцензуриванием open source моделей типа gpt-oss-20b для разговоров о влажном и понял, что перед тем как писать пост про расцензурирование, надо вас хорошенечко прогреть. Поведаю о том, как появились чат модели и как мы жили без них.
Если вы когда-то интегрировали LLM, то скорее всего вы использовали
/v1/chat/completions
Этот эндпоинт появился в 2023 году после выхода ChatGPT. Но как же люди жили раньше?
К счастью, ваш покорный слуга реально шарит в этой теме 😎, так как дёргает API ручки с 2022 года и застал базовые LLM. Сейчас всё поймёте.
Что такое базовые LLM?
До 2023 года языковые модели были по сути продолжателями заданного текста. Это значит, что ваш запрос состоял из одной строки, которая называлась prompt.
Интересный факт: слово “prompt” существовало и раньше, но не было центральным понятием в ML. Чаще говорили просто “input text”. С приходом GPT-3 и API доступом к ней, слово “prompt” стало означать любой текст, подаваемый на вход модели.
Запрос выглядел так:
completion = client.completions.create(
model="davinci-002",
prompt="""
Q: Какая столица Франции?
A: Париж
Q: Кто развалил СССР?
A:
"""
)
Completion — это сгенерированное продолжение.
В этом случае в промпте мы симулировали диалог в формате вопрос-ответ. Если бы мы послали промпт типа:
“Как тебя зовут?”
то с большой вероятностью модель бы вернула:
“И сколько тебе лет?”
Так как это популярная связка вопросов. Базовая модель не имеет явного понимания ролей и не знает, что она “ассистент” - она тупо продолжает текст.
Модель дописывает следующие токены в последовательности. Никакого настоящего “чата” тогда не было, и написание промптов требовало сноровки.
Когда всё поменялось?
В какой-то момент стало очевидно, что люди используют модели как диалоговые системы.
В ответ на это появились:
-
instruction tuning и RLHF (чтобы модель вела себя как ассистент) – про проблемы RL писал 👉тут
-
chat template (чтобы диалог можно было стабильно кодировать в текст)
Chat template – это просто формат, который превращает список «сообщений» в строку для модели. (сериализация)
Сейчас, когда вы отправляете в модель запрос типа:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[
{"role": "user", "content": "Что случилось с подлодкой?"},
{"role": "assistant", "content": "Она утонула)))"},
{"role": "user", "content": "А чего смеётесь?"}
]
)
Примерно так выглядит строка, которая попадает в модель (формат зависит от модели):
<|user|> Что случилось с подлодкой?
<|assistant|> Она утонула)))
<|user|> А чего смеётесь?
<|assistant|>
И модель просто продолжает её.
Таким образом работает prefilling (префиллинг): если вы хотите направить модель в определённую сторону, вы можете начать отвечать за неё – и она продолжит.
Например:
<|user|> Что случилось с подлодкой?
<|assistant|> Она утонула)))
<|user|> А чего смеётесь? Отвечай в JSON формате!!!
<|assistant|>{"response": "
Модель продолжит это как:
Потому что"}
Модель не «решила» вернуть JSON. Вы просто начали ответ за неё - и она его дополнила.
Это и есть настоящий механизм управления LLM: не команды, не API, не магия — а правильное продолжение строки.
Все эти:
- JSON mode
- function calling
- structured output
Это просто более удобные обёртки над тем же самым приёмом. (если упростить)
🧠Самое важное
Чат модели – это не что-то принципиально новое. Это те же самые completion модели, просто:
- обученные на диалогах (instruction tuning + RLHF)
- с зашитым chat template
- и удобным API поверх этого
Но внутри всё по-прежнему работает так же: модель просто дописывает следующий токен
А если модель это просто продолжение текста, то значит:
- её можно направлять через формат
- её можно ломать через формат
- и да… её можно частично расцензурировать через формат, не меняя весов
С этим сейчас я и играюсь.
Вкусно вам? Мне тоже отсыпьте 🔥