#технический_четверг
ч.1 тут
ч.3 тут
В прошлой серии узнали – можно смотреть на веса, которые модель назначает интересным нам токенам. А на другие не смотреть и на результат генерации не смотреть тоже 🙈
Так забить на результат генерации можно, но только если нас интересует всего один токен.
Иначе нужно прям контролировать генерацию – не давать модели выбирать токены, которые нам не нужны. А то первый "некорректный" токен потянет за собой кривое распределение весов для второго, а тот для третьего и т.д.
Так что нужно вмешиваться в процесс генерации и "занулять" веса у всех токенов, которые не подходят под нужный формат. И уже потом выбирать только из оставшихся.
Например, если ответ должен быть целым числом – все токены, которые содержат в себе что-то кроме цифр – под запретом. (А для первого под запретом еще и "0")
Именно так работал json-режим в OpenAI – под запрет шли все токены, которые не давали ответу быть валидным json-ом (главный формат интернета, между прочим).
Вот как в этом формате может выглядеть разобранное LLMкой резюме:
{
"Имя": "Вася",
"Фамилия": "Иванов",
"Специализация": "Тестировщик",
"Стаж (лет)": 5,
"Образование": ["НГУ", "МГУ"],
"Опыт работы": [
{
"Компания": "Рога и копыта",
"Должность": "старший тестировщик",
"Период": [2023, 2025]
},
{
"Компания": "Просто копыта",
"Должность": "тестировщик",
"Период": [2020, 2023]
}
]
}Важно: генерация идет последовательно, поэтому такую штуку делают при генерации каждого следующего токена. А это не очевидная инженерная задача.
И так же теперь работает structured output, только он идет еще дальше – позволяет описывать конкретный формат – какие поля должны быть в ответе, какие у них типы и т.д.
Например, что стаж – всегда целое число, а опыт работы – массив значений, каждое из которых включает компанию, должность и период.
Этот формат прописывается в виде json-schema (или pydantic классов на python). В комментах пара примеров
Почему это очень круто:
1. Сильно упрощается связка с остальным кодом, где все определено. Теперь мы точно знаем, что получим ответ в нужном формате в 100% случаев, и его бесшовно можно использовать в не-ии коде.
2. Это контринтуитивно, но ограничения позволяют получать более качественные ответы. Прописывая грамотную структуру ответа, мы как-бы направляем модель думать в нужном нам направлении (см. пост про custom CoT)
3. И еще страннее то, что это может ускорять генерацию, (даже если генерирует точно такой же текст как без ограничений 🤯). Тут объяснений – на отдельный пост, как-нибудь напишу.
———
Теперь совсем улетим в космос:
Для локальных моделей, есть полный контроль над выбором следующего токена – можно делать любые ограничения, а не только те, которые разрешает OpenAI со своей json-схемой.
А любой кастомный формат можно описать формальными грамматиками – будь то Python, sql, markdown или ваш собственный формат отчетов на работе.
И передать грамматику в outlines, чтобы модель всегда следовала формату 🫨
———
Фух, так много еще хочется рассказать, но кажется, даже это уже ту мач для поста в тг, так что хватит на сегодня.
В 3 части будут практические примеры и не так душно
