Тот случай, когда больше - значит хуже
Вы скачали новую крутую модель для генерации кода. Установили Claude Code, настроили, радуетесь: теперь можно работать без интернета и ограничений по токенам. Берёте проверенный промпт из облачной версии - тот самый, который отлично работал с GPT-4. 16.5 тысяч токенов подробных инструкций, примеров, ограничений. Запускаете. И получаете... бред.
Модель qwen3-coder-30b с 32K контекстом начинает галлюцинировать уже на втором ответе. Игнорирует системные инструкции, придумывает несуществующие функции, выдаёт синтаксически правильный, но семантически бессмысленный код.
Парадокс: контекста достаточно (32K против 16.5K), модель специализированная (кодовая), но результат - катастрофа. Почему? Потому что длина системного промпта убивает внимание модели. И вот как это работает.
Механизм поломки: когда инструкция становится шумом
Представьте, что вы даёте человеку инструкцию на 50 страниц, а потом просите решить простую задачу. Скорее всего, он либо проигнорирует половину инструкции, либо запутается. Примерно то же происходит с локальными LLM.
Вот что происходит пошагово:
1 Аттеншн-механизм перегружается
Self-attention вычисляет взаимосвязи между всеми токенами в контексте. Формально сложность O(n²), но на практике используют оптимизации. Однако даже оптимизированные алгоритмы страдают на длинных последовательностях: модель пытается связать 500-й токен инструкции с 15000-м токеном пользовательского запроса. И не справляется.
2 Квантование усугубляет проблему
Когда модель квантуют (скажем, с FP16 до INT4), теряется точность вычислений. Мелкие веса становятся нулями. На коротких промптах это незаметно, но на длинных - накапливается ошибка. Особенно страдают квантованные версии больших моделей, которые и так работают на пределе возможностей видеопамяти.
3 Позиционные эмбеддинги "сползают"
RoPE, ALiBi и другие позиционные кодирования работают идеально в тренировочном диапазоне (обычно до 8K-16K). За пределами этого диапазона модель буквально не понимает, где находится токен в последовательности. 16500-й токен? Модель обрабатывает его как 500-й, потому что эмбеддинги повторяются.
Разбор конкретного кейса: qwen3-coder-30b vs 16.5K промпт
Возьмём реальный пример. Системный промпт для кодогенерации включает:
- Общие правила (200 токенов)
- Спецификацию формата ответов (500 токенов)
- Примеры хороших ответов (8000 токенов)
- Примеры плохих ответов (4000 токенов)
- Ограничения безопасности (1000 токенов)
- Стилевые гайдлайны (2000 токенов)
Итого: 16.5K токенов. Пользовательский запрос: "Напиши функцию сложения двух чисел на Python".
| Что ожидали | Что получили | Почему |
|---|---|---|
| Простую функцию с типизацией | Класс с 5 методами и декораторами | Модель "вспомнила" пример из середины промпта |
| Прямой ответ | Рассуждения на 3 абзаца перед кодом | Спутала стилевые гайдлайны с обязательными требованиями |
| Код на Python | Смесь Python и псевдокода | Потеряла контекст языка из-за перегрузки |
Худшее в этой ситуации: модель уверена, что делает всё правильно. Нет никаких "я не уверен" или "возможно, я ошибаюсь". Только уверенный бред. Это признак полного сбоя механизмов внимания.
Как исправить: не инструкциями, а архитектурой
Первое желание - добавить ещё инструкций. "Обращай больше внимания на начало промпта", "Не забывай про ограничения". Это не работает. Проблема не в содержании, а в механике обработки.
1 Режьте промпты безжалостно
16.5K токенов - это перебор даже для облачных моделей. Для локальных - смерть. Цель: уложиться в 2-4K токенов системного промпта. Как?
- Удаляйте примеры. Да, они полезны. Нет, они не стоят 12K токенов. Оставьте 1-2 самых ярких.
- Объединяйте правила. Вместо 10 пунктов по 100 токенов - 3 пункта по 150.
- Выносите в RAG. Если нужны многочисленные примеры, используйте векторную базу. Модель запросит примеры, когда они понадобятся.
2 Используйте иерархические промпты
Вместо одного монолитного промпта создайте структуру:
# Уровень 1: Основная инструкция (500 токенов)
system_core = "Ты — ассистент для генерации кода. Формат ответа: код без объяснений."
# Уровень 2: Контекстно-зависимые правила
# Эти правила добавляются только при определённых условиях
security_rules = "Если запрос касается аутентификации, добавь проверки..."
# Уровень 3: Примеры по требованию
# Хранятся отдельно, подгружаются по ключевым словам
Такой подход используют в Owlex MCP-сервере, где разные модели получают разные инструкции в зависимости от задачи.
3 Настройте динамический контекст
Не загружайте весь промпт сразу. Используйте схему:
- Базовый промпт (1K токенов)
- Пользовательский запрос
- Если модель просит уточнений - добавляем соответствующие части инструкций
- Только тогда, когда точно нужно
Это требует более сложной логики, но полностью решает проблему перегрузки. Кстати, именно так работают динамические промпты для кодогенерации.
Технические детали: что происходит внутри модели
Если вы любите копать глубже (а я знаю, что любите), вот что показывают внутренние метрики при перегрузке промптами:
Attention entropy резко падает после первых 4K токенов. Это значит, что модель перестаёт различать важные и неважные части контекста. Все токены становятся "одинаково важными", что равносильно "одинаково бесполезными".
В квантованных моделях добавляется проблема активационного сдвига. Значения активаций в глубоких слоях выходят за диапазон, который может представить INT4. Результат - случайные числа вместо осмысленных векторов.
И самая неприятная часть: эффект накапливается. Первый ответ может быть почти нормальным. Второй - уже странным. К пятому ответу модель полностью "забывает" системный промпт и работает как базовая версия без инструкций.
Проверка на практике: простой тест
Хотите проверить свою настройку? Сделайте так:
# Тестовый запрос
prompt = """
[Ваш длинный системный промпт здесь]
Задача: напиши "Hello, World!" на Python.
"""
# Ожидаемый ответ: print("Hello, World!")
# Реальный ответ модели с перегруженным промптом:
# "Создадим класс HelloWorld с методом print_message..."
Если модель усложняет простейшую задачу - промпт слишком длинный. Точка.
Что делать с Claude Code и подобными инструментами
Claude Code локально - отличная идея, но требует адаптации. Не копируйте промпты из облака один в один. Вместо этого:
- Проанализируйте, какие части промпта действительно нужны
- Создайте "легкую" версию для локальных моделей
- Используйте практические техники из гайда по локальному запуску
- Тестируйте на простых задачах перед сложными
И помните: локальная модель - это не точная копия облачной. Это автомобиль с меньшим двигателем. Можно ехать по тому же маршруту, но не стоит загружать полный багажник.
Будущее: модели, которые справляются с длинным контекстом
Новые архитектуры вроде LoopCoder с повторяющимися слоями обещают лучшее handling длинного контекста. Но пока это будущее. Сегодняшний день диктует простые правила:
И последний совет: если ваша модель начинает галлюцинировать, не добавляйте больше инструкций. Убирайте. Удалите половину промпта. Скорее всего, качество вырастет. Потому что иногда меньше - действительно значит больше. Особенно когда работаешь с мозгами размером в несколько гигабайт.
P.S. Если интересно, как диагностировать дрейф контекста и галлюцинации - там есть полезные протоколы. Но сначала порежьте свои промпты. Скорее всего, это поможет сразу.