Нарушение инварианта токенов ломает обучение агентов: как исправить ошибку в Qwen3
Повторная токенизация диалога в агентных режимах искажает градиентный спуск, заставляя модели оптимизироваться по несуществующим токенам. Разработчики теряют контроль над обучением, пока не заменят пересборку текста на работу с буфером токенов и расчет дельт.
Исследование, опубликованное в сообществе Hugging Face, выявляет критическую ошибку в процессе обучения языковых моделей с использованием подкрепления (RL), когда модели наделяются способностью вызывать внешние инструменты. Основная проблема кроется в нарушении инварианта «Токен-вход, Токен-выход» (Token-In, Token-Out, TITO): при попытке обучить модель в многошаговом режиме разработчики часто декодируют ответ модели, обрабатывают его и повторно кодируют (токенизируют) обновленный диалог. Поскольку токенизация не является обратимым процессом, повторное кодирование той же текстовой строки может дать другую последовательность ID-токенов. В результате градиентный спуск происходит по последовательности, которую модель никогда не генерировала, что делает сигнал обучения некорректным и ведет к сбою обучения.
Важный нюанс: Ошибка не вызывает явного падения кода, но математическая основа обучения разрушается, так как модель оптимизируется по «призрачным» токенам, отличным от сгенерированных.
Механизм ошибки и метод исправления
В стандартном цикле обучения (single-turn) модель генерирует ответ, и градиент вычисляется точно по этим токенам. В агентном режиме (multi-turn) ситуация усложняется: модель генерирует вызов инструмента, система выполняет его, результат добавляется в диалог, и модель продолжает генерацию. Если на этом этапе весь диалог пересобирается в текст и заново токенизируется, возникают два вида сбоев:
- Потеря границ: Тренер перестает различать, какие токены сгенерировала модель, а какие пришли от инструмента, что усложняет расчет функции потерь.
- Дрейф токенов: Из-за особенностей алгоритмов слияния байтов (BPE) и вариативности форматирования (пробелы, порядок аргументов JSON) повторная токенизация выдает иные ID, чем исходная генерация.
Решение заключается в строгом соблюдении правила: никогда не перекодировать токены, которые уже были декодированы. Вместо пересборки всего диалога используется буфер, в который последовательно добавляются:
- Исходные токены промпта.
- Токены, сгенерированные моделью (без изменений).
- Токены ответа инструмента, полученные через разницу (дельта) между рендерингом диалога с инструментом и без него.
Этот подход гарантирует, что градиент всегда применяется к тем самым токенам, которые выбрала политика модели.
Стоит учесть: Для корректной работы метода дельты шаблон чата (chat template) должен обладать свойством «сохранения префикса» при добавлении сообщений от инструментов, то есть добавление нового сообщения не должно менять токенизацию предыдущих частей диалога.
Проверка шаблонов и поддержка моделей
Автор статьи проверил свойство сохранения префикса на широком наборе популярных моделей с открытыми весами. Тестирование показало, что большинство современных шаблонов чатов удовлетворяют этому требованию по умолчанию, так как оно является узкоспециализированным и не затрагивает логику отображения сообщений пользователя или системы.
Результаты проверки по семействам моделей:
| Семейство моделей | Статус сохранения префикса | Примечание |
|---|---|---|
| Qwen2.5 | ✅ | Работает корректно |
| Qwen2.5-Coder | ✅ | Работает корректно |
| Qwen3 | ❌ | Требует однострочного исправления в шаблоне |
| Qwen3 Instruct (2507) | ✅ | Работает корректно |
| Qwen3-VL | ✅ | Работает корректно |
| Qwen3.5 / Qwen3.6 | ✅ | Работает корректно |
| DeepSeek-V3.1 / R1 | ✅ | Работает корректно |
| Llama 3.1 / 3.2 / 4 | ✅ | Работает корректно |
| Gemma 4 / Function Gemma | ✅ | Работает корректно |
| GLM-4.5 / GLM-5 | ✅ | Работает корректно |
| MiniMax-M2.1 | ✅ | Работает корректно |
Исключение составил базовый вариант Qwen3, где логика шаблона Jinja удаляла блок размышлений (<think>) при добавлении ответа инструмента, нарушая целостность префикса. Исправление заняло одну строку кода в шаблоне, после чего модель стала совместимой с методом TITO.
Ограничения метода и альтернативы
Существуют сценарии, где метод TITO требует адаптации или уступает альтернативным подходам.
- Переписывание истории: Если агент в процессе работы сжимает историю диалога, удаляет блоки размышлений или подменяет прошлые ходы сводками (как это делают некоторые модели Z.ai или инструменты типа Claude Code), инвариант TITO нарушается. В таких случаях необходимо «замораживать» часть диалога до момента редактирования, используя её как промпт без вычисления градиента, и обучать только на новых токенах.
- Трункация (обрезка): Если генерация обрывается на лимите длины последовательности, метод TITO справляется с этим без проблем, так как буфер просто содержит обрезанную последовательность. Альтернативные методы с использованием рендереров требуют дополнительной логики для синтеза закрывающих токенов.
Альтернативой является использование библиотеки рендереров, где для каждого семейства моделей пишется отдельный код, управляющий переходом между ходами. Это дает более строгий контроль и удобство отладки, но требует поддержки каждого нового шаблона вручную. Метод TITO же универсален и требует лишь проверки одного свойства шаблона.
Важный нюанс: Метод TITO не требует переписывания логики шаблонов чата, если они уже поддерживают сохранение префикса, что делает его более масштабируемым решением для новых моделей по сравнению с написанием кастомных рендереров.
Практические аспекты внедрения
Для реализации корректного обучения агентов необходимо изменить архитектуру цикла обучения, отказавшись от пересборки диалога в текстовом виде.
- Использование буфера токенов: Все токены, сгенерированные моделью, должны храниться в буфере и никогда не подвергаться повторной токенизации.
- Расчет дельты: Для добавления ответа инструмента используется разница между токенизацией диалога с ответом и без него, что позволяет вставить только необходимые токены.
- Валидация шаблонов: Перед началом обучения необходимо запустить тест на сохранение префикса для используемого токенизатора. Если тест не проходит, шаблон требует правки (как в случае с Qwen3).
- Обработка сжатия истории: При использовании агентов, меняющих историю диалога, необходимо явно разграничивать промпт (без градиента) и сгенерированную часть (с градиентом) в точке изменения истории.
На фоне этого: Переход на метод TITO позволяет избежать скрытых ошибок обучения, которые ранее могли проявляться как нестабильность сходимости или неочевидные сбои в работе сложных агентов.
Источник: huggingface.co