Как проявляется проблема: симптомы потери инструкций на длинных диалогах
Вы запускаете Qwen 3.6 27B локально через Opencode, ставите задачу на summarization, а модель начинает переводить текст. Вы просите «отвечай как senior-разработчик», а через 15 сообщений получаете ответ в стиле «я всего лишь ИИ-ассистент». Системный промпт с ролями агентов игнорируется, делегирование задач ломается, а модель «забывает», что должна сжимать ответ до трёх предложений.
Это классические симптомы потери контекста при локальном инференсе. Характерная особенность: на single-turn промптах модель работает корректно, на multi-turn начинаются сбои. Проблема воспроизводится даже на bfloat16 - квантизация не главный виновник. Точная причина до конца не установлена, но анализ конфигураций и issue #31720 позволяет выделить пять ключевых факторов: формат KV-кэша, стратегию управления контекстом в Opencode, несовместимость chat template с GGUF, артефакты speculative decoding и особенности гибридной архитектуры GDN.
Примеры сбоев: от неправильного делегирования до игнорирования ролей
Первый кейс: модель получает промпт с чёткими инструкциями по сжатию текста. На первых пяти сообщениях она выполняет задачу безупречно - выделяет ключевые мысли, укладывается в лимит токенов. К десятому сообщению начинает добавлять «от себя» развёрнутые комментарии, игнорируя ограничение длины. К пятнадцатому - полностью переключается в режим свободного диалога.
Второй кейс: агентная конфигурация с распределением ролей. Модель должна выступать в роли кодера, а запросы на ревью переадресовывать другому агенту. После двадцати сообщений она перестаёт делегировать и пытается выполнять все задачи самостоятельно, нарушая архитектуру пайплайна. Это задокументированное поведение, которое мы также разбирали в тесте Gemma3-31B vs Qwen3.6-27B, где Qwen при кодинге зацикливался на простых багах вместо следования ролевой модели.
Третий кейс - воспроизводимый баг из issue #31720: 6-shot multiple-choice промпт «What is 2+2? A. 3 B. 4 C. 5 D. 6» при temperature 0 на sglang 0.5.14 генерирует последовательность «A. 1, 2, 3, 4, 5, 6, 7, 8, 6, 9, 10, 1, 2, 3, 3, 1, 1, 1, 1, ...» вместо «B». На vLLM 0.21 те же промпты обрабатываются корректно - 1-2 токена. Это указывает на проблему в связке «фреймворк инференса + архитектура модели», а не в самой квантизации.
Корень проблемы: почему LLM теряют контекст при локальном инференсе
LLM не имеют внутреннего состояния между запросами. Каждый вызов - это передача полной истории диалога заново. Когда история разрастается до десятков тысяч токенов, в игру вступают механизмы сжатия, обрезки и кэширования. Ошибка на любом из этих этапов приводит к тому, что инструкции из начала диалога «вымываются» из эффективного контекста.
На локальных машинах проблема обостряется: разработчик управляет размером контекста вручную, выбирает формат квантизации, настраивает KV-кэш и параметры семплинга. Каждый параметр - точка отказа. В серверных API эти настройки скрыты за оптимизированными дефолтами, поэтому пользователи OpenAI или Anthropic редко сталкиваются с такой деградацией.
Роль KV-кэша: почему q8_0 и F16 ведут себя по-разному
KV-кэш хранит ключи и значения для каждого токена, обработанного моделью. При генерации нового токена модель обращается к этому кэшу вместо повторного вычисления внимания по всей истории. Формат хранения определяет точность этих обращений.
F16 (16-битный float) сохраняет полную точность вычислений. q8_0 (8-битное квантование кэша) теряет часть информации, но экономит видеопамять. На коротких диалогах разница незаметна. На длинных - ошибки квантования накапливаются: каждый новый токен вычисляется на основе уже неточных ключей и значений. К двадцатому сообщению накопленная ошибка может изменить распределение внимания так, что модель перестаёт «видеть» ранние инструкции.
Практическое наблюдение: переход с q8_0 на F16 KV-кэш часто решает проблему дрейфа инструкций ценой увеличения потребления VRAM на 30-50%. Для Qwen 3.6 27B с контекстом 32k токенов это означает дополнительные 2-4 ГБ видеопамяти.
Квантизация модели: как Q8_K_XL, Q8_0 и Q6 влияют на стабильность
Квантизация модели и квантизация KV-кэша - разные вещи. Первая сжимает веса, вторая - промежуточные вычисления. Q8_K_XL использует продвинутую схему с переменной точностью: важные слои получают больше бит, менее важные - меньше. Q8_0 квантует всё равномерно. Q6 - ещё более агрессивное сжатие.
Парадокс: Q8_K_XL может показывать лучшие бенчмарки качества, но быть менее стабильным на длинных диалогах. Причина - неравномерное распределение точности создаёт «узкие места» в слоях внимания, где накопление ошибки идёт быстрее. Q8_0, теряя в среднем качестве, ведёт себя предсказуемее на multi-turn сценариях.
Важное уточнение из issue #31720: проблема воспроизводится на bfloat16 и all-float16. Квантизация - не единственная причина. Не-GDN модель Seed-OSS-arch 36B на том же sglang работает чисто. Подозрение падает на реализацию GDN (fused GDN projection path) или её взаимодействие с ядром awq_marlin.
Фреймворк Opencode: как он управляет контекстом и где может ошибаться
Opencode использует фиксированную стратегию управления контекстом: выделяет определённый процент токенов под системный промпт, под историю и под ответ. Когда диалог превышает лимит, фреймворк обрезает историю, часто жертвуя ранними сообщениями, где как раз и находятся критически важные инструкции.
Проблема усугубляется при выставлении больших лимитов - 105k или 256k токенов. Модель технически способна обработать такой объём, но механизмы внимания на длинных последовательностях работают хуже: модель «фокусируется» на последних сообщениях и теряет связь с началом диалога. Это не баг, а архитектурное ограничение transformer-моделей.
Chat template и GGUF: несовместимость, которая ломает инструкции
GGUF-модели требуют строго определённого chat template - шаблона, по которому форматируются сообщения перед подачей в модель. Если Opencode применяет template от другой модели или модифицирует его, системные промпты могут «склеиваться» с пользовательскими сообщениями или терять маркеры ролей.
Пример: модель ожидает формат <|im_start|>system\n...<|im_end|>, а Opencode отправляет system: .... Модель не распознаёт это как системную инструкцию и обрабатывает как обычное пользовательское сообщение. Результат - полное игнорирование ролей и инструкций без каких-либо ошибок в логах.
Проверка: сравните формат сообщений в логах Opencode с ожидаемым форматом для Qwen 3.6 27B. Расхождение даже в одном токене-разделителе может объяснить все симптомы.
Speculative decoding и его артефакты: ngram-mod и draft-mtp под микроскопом
Speculative decoding ускоряет генерацию: draft-модель предлагает несколько вариантов следующего токена, основная модель проверяет их параллельно. В llama.cpp используются два драфтера: ngram-mod (копирует паттерны из контекста) и draft-mtp (маленькая модель, предсказывающая токены).
Проблема: draft-модель обучалась на других данных и может предлагать токены, статистически вероятные, но семантически неверные для текущей задачи. Основная модель, принимая такие предложения, постепенно уходит в сторону от инструкций. На multi-turn промптах эффект накапливается: каждый ход добавляет дрейф, и к десятому сообщению модель генерирует текст, не имеющий отношения к исходной задаче.
В тесте спекулятивного декодирования в llama.cpp мы показали, что ngram-драфтеры дают до 6x ускорения на задачах кодирования без потери accuracy. Но этот результат получен на итеративном редактировании кода, где паттерны повторяются. На задачах с жёсткими инструкциями и разнородными промптами поведение драфтеров менее предсказуемо.
Когда ускорение вредит: примеры вырождения на multi-turn промптах
6-shot multiple-choice промпт - идеальный тест на стабильность. Модель видит шесть примеров формата «вопрос → одна буква ответа» и должна экстраполировать паттерн. При temperature 0 ожидается детерминированный ответ из 1-2 токенов.
Что происходит на практике: draft-модель «видит» повторяющийся паттерн букв и предлагает продолжить последовательность. Основная модель, вместо того чтобы следовать инструкции «выбери один вариант», начинает генерировать все буквы подряд. Это не галлюцинация - это конфликт между задачей (multiple-choice) и паттерном, обнаруженным драфтером (перечисление).
Решение: отключать speculative decoding для задач, где критично точное следование инструкциям. Для Qwen 3.6 27B это особенно актуально из-за гибридной GDN-архитектуры, которая может иметь специфическое взаимодействие с драфтерами.
Практические решения: как настроить llama.cpp и Opencode для стабильной работы
Проблема потери контекста решается системно: нельзя исправить один параметр и забыть. Конфигурация должна учитывать характер задач, доступную видеопамять и требования к скорости. Ниже - выверенная на практике комбинация настроек для Qwen 3.6 27B.
Чек-лист конфигурации для Qwen 3.6 27B в Opencode
| Параметр | Рекомендуемое значение | Обоснование |
|---|---|---|
| context size | 32768 или 65536 | Не гнаться за 256k без необходимости. Меньший контекст снижает накопление ошибок внимания и ускоряет инференс. |
| kv-cache type | F16 | Полная точность кэша критична для сохранения инструкций на длинных диалогах. Если не хватает VRAM - q8_0 как компромисс, но тестировать стабильность. |
| speculative decoding | выключен | Отключить ngram-mod и draft-mtp для задач с жёсткими инструкциями. Включить только для итеративного кодирования, где паттерны повторяются. |
| temperature | 0.1–0.3 | Низкая температура снижает вероятность случайного дрейфа инструкций. 0 не рекомендуется - может вызывать зацикливание. |
| top_p | 0.9 | Стандартное значение, ограничивает выборку вероятных токенов без излишней жёсткости. |
| min_p | 0.05 | Отсекает маловероятные токены, снижая шанс генерации мусора при вырождении. |
| repeat_penalty | 1.05–1.1 | Лёгкий штраф за повторы предотвращает зацикливание, не ломая legitimate повторения терминов. |
| chat template | проверить соответствие | Сравнить шаблон в конфигурации Opencode с ожидаемым для Qwen 3.6 27B. Несовпадение - частая причина игнорирования ролей. |
Как тестировать стабильность инструкций: методика и промпты
Тестовый набор должен покрывать три сценария:
- Single-turn: одиночный промпт с чёткими инструкциями. Модель должна выполнить задачу без отклонений. Пример: «Сожми следующий текст до трёх предложений, сохранив ключевые факты».
- Multi-turn с инструкциями: 10-15 сообщений, где каждое требует соблюдения формата ответа. Пример: «Ответь одним предложением. Не используй слово 'нейросеть'». Проверять каждое сообщение.
- Few-shot с паттерном: 6-shot multiple-choice промпт из issue #31720. Модель должна выдать 1-2 токена ответа, а не генерировать последовательность.
Критерии оценки: single-turn должен выполняться всегда. Multi-turn - допускается не более одного отклонения на 20 сообщений. Few-shot - категорически не должен вырождаться в повторяющиеся последовательности.
Если single-turn работает, а multi-turn ломается - проблема в управлении контекстом или KV-кэше. Если few-shot вырождается - проблема в speculative decoding или несовместимости фреймворка с архитектурой модели.
Ограничения и открытые вопросы: что мы ещё не знаем о потере контекста
Точная причина сбоев на GDN-моделях не установлена. Подозрение падает на fused GDN projection path - специфическую реализацию слоёв внимания в гибридной архитектуре Qwen 3.6 27B. Не-GDN модель Seed-OSS-arch 36B на том же sglang работает без ошибок, что локализует проблему в архитектуре, а не в фреймворке или квантизации.
Рекомендации в этой статье основаны на наблюдениях и тестах по состоянию на июль 2026 года. С обновлениями llama.cpp, Opencode и sglang ситуация может измениться. Проблема активна в issue-трекерах - следите за репозиториями.
Отдельный пласт вопросов связан с prompt compression - сжатием истории диалога перед отправкой в модель. Opencode может применять эвристики, которые обрезают не по токенам, а по «важности» сообщений. Если эвристика ошибается и считает системный промпт менее важным, чем последнее сообщение пользователя, инструкции теряются не из-за модели, а из-за препроцессинга.
Практический вывод: при локальном запуске Qwen 3.6 27B начинайте с консервативных настроек (F16 KV-кэш, выключенный speculative decoding, контекст 32k) и проверяйте стабильность на тестовом наборе промптов. Увеличивайте контекст и включайте ускорения только после подтверждения, что модель держит инструкции на ваших задачах.