TL;DR
Когда LLM не знает конкретный язык, формат или внутреннюю структуру — она выдумывает: пишет похожие, но несуществующие идентификаторы, поля, значения. Исследование Text2DSL доказывает: если добавить в промпт три компонента одновременно — правила формата (что синтаксически допустимо), спецификацию объектов и методов (что означает каждый элемент), закрытый список допустимых значений (конкретные идентификаторы, которые можно использовать) — галлюцинации практически исчезают.
Главное открытие: LLM без контекста почти никогда не угадывает правильные идентификаторы (индекс совпадения — 0.146 из 1.0). С контекстом — совпадение вырастает до 0.633. Модель переходит из режима «угадывать» в режим «выбирать из списка». Именно словарь допустимых значений даёт наибольший прирост качества — больше, чем правила синтаксиса.
Работает в одном промпте: в начало вставляешь спецификацию формата, добавляешь явную инструкцию «не используй свои знания, только то, что в контексте» — и просишь генерировать. Метод не требует дообучения модели. Синтаксическая корректность вырастает до 98.6–99.4%.
Схема метода
Один промпт, три блока контекста + задача:
БЛОК 1: Правила формата → что синтаксически допустимо
(структура, обязательные элементы, порядок)
БЛОК 2: Спецификация → что означает каждый объект/поле/метод
(не оставляй LLM угадывать семантику)
БЛОК 3: Закрытый словарь → полный список допустимых значений
(все идентификаторы, все теги, все варианты — без исключений)
ИНСТРУКЦИЯ: "Используй ТОЛЬКО контекст выше. Не используй свои знания."
ЗАДАЧА: [что нужно сгенерировать]
Всё — в одном запросе. Отдельных шагов нет.
Пример применения
Задача: Менеджер маркетплейса Wildberries хочет автоматизировать заполнение карточек товаров. Есть 50 SKU. У каждого — строгая структура атрибутов: категория, тип товара, допустимые значения материала, страны производства, размерной сетки. Если указать несуществующий атрибут — карточка не пройдёт модерацию.
Промпт:
Ты генератор карточек товаров для Wildberries.
Используй ТОЛЬКО информацию из контекста ниже.
НЕ используй свои знания о Wildberries.
=== ПРАВИЛА СТРУКТУРЫ ===
Каждая карточка содержит обязательные поля:
- brand: строка (название бренда)
- category: одно значение из списка категорий
- subject: подкатегория из списка subjects
- attributes: объект, где ключи — ID атрибутов, значения — из словаря
=== СПЕЦИФИКАЦИЯ АТРИБУТОВ ===
Атрибут 85: Материал верха → принимает значения из списка материалов
Атрибут 111: Страна производства → принимает ISO-коды стран
Атрибут 14: Пол → принимает: "Мужской", "Женский", "Унисекс"
Атрибут 7826: Размер → принимает значения из размерной сетки EU
=== ДОПУСТИМЫЕ ЗНАЧЕНИЯ ===
Категории: "Обувь", "Одежда", "Аксессуары", "Спорт", "Дом"
Subjects (обувь): "Кроссовки", "Ботинки", "Сандалии", "Туфли", "Сапоги"
Материалы: "Натуральная кожа", "Искусственная кожа", "Текстиль", "Нубук", "Замша"
Страны: "RU", "CN", "TR", "IT", "DE"
Размеры EU: "36", "37", "38", "39", "40", "41", "42", "43", "44", "45"
Пример готовой карточки:
{
"brand": "Ralf Ringer",
"category": "Обувь",
"subject": "Ботинки",
"attributes": {
"85": "Натуральная кожа",
"111": "RU",
"14": "Мужской",
"7826": ["41", "42", "43"]
}
}
Сгенерируй карточку для товара:
Мужские кроссовки из текстиля, производство Китай,
размеры 40-44, бренд "Strobbs"
Результат: Модель выдаст JSON-карточку, где каждый атрибут — строго из словаря. Никаких "материал": "хлопок" вместо "Текстиль", никаких "Страна": "China" вместо "CN". Инструкция «не используй свои знания» блокирует попытку модели подставить то, что кажется правильным по смыслу, но не совпадает с допустимым значением.
Почему это работает
LLM — это не база данных. Когда говоришь «сгенерируй JSON с полем country», модель не знает что в твоей конкретной системе принято — "RU" или "Russia" или "Россия". Она выбирает то, что чаще встречалось при обучении. Получается семантически близко, но формально неверно: filesystem-disk-mount вместо filesystem-mount. Это ломает валидацию.
У LLM нет проблем с рассуждением — есть проблема с угадыванием закрытых словарей. Она понимает «пользователь хочет установить пакет», но не знает как именно это называется в твоей системе. Как только ты даёшь список — она мгновенно переключается с угадывания на выбор из заданного. Именно поэтому Jaccard (точность совпадения идентификаторов) даёт самый большой прирост при добавлении словаря.
Инструкция «не используй свои знания» работает как явный запрет на авто-дополнение. Без неё модель одновременно читает твой контекст и своё обучение — и смешивает. С ней — приоритет однозначен. Это не блокирует интеллект модели, а убирает источник интерференции.
Рычаги управления:
- Добавь примеры — один-два заполненных образца в контексте дают +20% к корректности сложных случаев
- Явно перечисли запрещённые ошибки — если знаешь типичные, добавь: "НЕ используй auth_admin, только AUTH_ADMIN"
- Разбей на секции с метками (=== СЛОВАРЬ ===, === ПРАВИЛА ===) — модель лучше находит нужный блок при генерации
Шаблон промпта
Ты генератор {что_генерируешь}.
Используй ТОЛЬКО информацию из контекста ниже.
НЕ используй свои знания о {предметная_область}.
=== ПРАВИЛА СТРУКТУРЫ ===
{обязательные_элементы_и_порядок}
=== СПЕЦИФИКАЦИЯ ===
{что_означает_каждое_поле_или_объект}
=== ДОПУСТИМЫЕ ЗНАЧЕНИЯ ===
{полный_список_идентификаторов_и_значений}
=== ПРИМЕР ===
{один_заполненный_образец}
Сгенерируй {что_нужно} для:
{описание_задачи_на_естественном_языке}
Что подставлять:
- {что_генерируешь} — карточка товара / SQL-запрос / конфиг / документ
- {предметная_область} — Wildberries / наша БД / внутренний формат
- {обязательные_элементы} — поля, которые обязаны присутствовать
- {спецификация} — что означает каждое поле, какой тип данных
- {полный_список} — все допустимые значения без исключений
- {один_образец} — заполненный пример в нужном формате
🚀 Быстрый старт — вставь в чат:
Вот шаблон Structured Context Injection. Адаптируй под мою задачу:
[твоя задача — например "генерировать карточки товаров для CRM"].
Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит какие поля обязательны, какие значения допустимы, есть ли пример — потому что без этого она не может заполнить разделы СПЕЦИФИКАЦИЯ и ДОПУСТИМЫЕ ЗНАЧЕНИЯ. Она возьмёт паттерн из шаблона и адаптирует под твою задачу.
Ограничения
⚠️ Остаточные галлюцинации: Даже с полным контекстом ~22% генераций содержат хотя бы один неверный идентификатор. Модель «достраивает» суффиксы по аналогии вместо точного копирования из словаря. Для критически важных систем нужна валидация.
⚠️ Размер словаря: Если список допустимых значений огромный (тысячи идентификаторов), контекст раздувается. Сокращай до релевантного подмножества для конкретной задачи — или делай несколько промптов по категориям.
⚠️ Семантически похожие значения:
AUTH_SELFvsAUTH_ADMIN— модель плохо различает близкие по смыслу варианты. Если различие принципиально — добавь в спецификацию краткое объяснение когда что использовать.
⚠️ Только MoE-архитектуры в тесте: Исследование проверяло смешанные (MoE) модели, поэтому неизвестно, одинаково ли работает с обычными трансформерами вроде GPT-4. Скорее всего работает — принцип универсальный, но проверяй на своей задаче.
Как исследовали
Команда из RTU MIREA (Москва) взяла конкретный DSL — Polkit, система правил авторизации Linux — и построила датасет из 4 204 пар «описание на естественном языке → код правила». Сначала сгенерировали 5 000 пар через Grok-4.1, потом прогнали через трёхуровневый валидатор на основе AST-парсера (синтаксис → структура → семантика) и отсеяли 16% кривых. Дополнительно 200 правил проверили эксперты вручную — согласие между ними κ = 0.91, почти идеальное.
Дальше — чистый A/B: два разных промпта (с контекстом и без), две модели разных размеров и разных производителей (GigaChat от Сбера, Nemotron от NVIDIA), 4 204 запроса на каждую. Одна переменная — только наличие или отсутствие контекста. Результаты оказались неожиданно сильными для меньшей модели: GigaChat без контекста угадывала правильные идентификаторы в 14.6% случаев, с контекстом — в 63.3%. Исследователи сами отметили, что словарь идентификаторов дал наибольший прирост — больше, чем грамматика или спецификация. Это противоречит интуиции: обычно думаешь что правила синтаксиса важнее набора слов. Оказывается нет — LLM справляется со структурой лучше, чем с точными строками.
Оригинал из исследования
You are a polkit rule generator.
Use ONLY the information from the context below.
DO NOT use your own knowledge about polkit.
[Full context: BNF grammar, API specification,
vocabulary V of 65+ action.id values,
8 reference examples, generation rules]
Контекст: Baseline-промпт без контекста содержал только "You are a polkit rule generator for Linux. FORMAT: Return ONLY the polkit rule code in a javascript ... block." Добавление second-prompt с полным контекстом дало +18.9 pp синтаксической корректности у меньшей модели.
Адаптации и экстраполяции
💡 Адаптация для SQL с конкретной схемой
Классический кейс: просишь ChatGPT написать SQL, а она выдумывает имена таблиц которых нет. Применяй тот же принцип:
Ты генератор SQL-запросов для нашей БД.
Используй ТОЛЬКО таблицы и поля из контекста.
НЕ используй свои предположения о структуре.
=== СХЕМА БАЗЫ ДАННЫХ ===
Таблица orders: id, user_id, status, created_at, amount
Таблица users: id, email, name, city, registered_at
Таблица products: id, name, category, price, stock_qty
=== ДОПУСТИМЫЕ ЗНАЧЕНИЯ ===
status: "new", "paid", "shipped", "delivered", "cancelled"
city: "Москва", "СПб", "Казань", "Екатеринбург"
=== ПРИМЕР ЗАПРОСА ===
-- Найти все заказы пользователя
SELECT o.id, o.amount, o.status
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.email = 'user@example.com'
Напиши запрос: {задача на русском}
🔧 Техника: иерархия приоритетов → устранение конфликта между знаниями модели и контекстом
По умолчанию модель смешивает контекст с тренировочными данными. Явная инструкция разрывает это:
Источники информации в порядке приоритета:
1. Документ SPEC ниже — АБСОЛЮТНЫЙ ПРИОРИТЕТ
2. Пример EXAMPLE ниже — второй приоритет
3. Твои собственные знания — НЕ использовать
Если значение не найдено в SPEC — напиши "UNKNOWN",
не придумывай.
Работает для любого закрытого словаря: внутренние коды статусов, названия продуктов, теги систем.
🔧 Техника: явный список запрещённых галлюцинаций
Если знаешь типичные ошибки модели — добавь их явно:
=== ТИПИЧНЫЕ ОШИБКИ — НЕ ПОВТОРЯЙ ===
❌ status: "completed" → правильно: "delivered"
❌ status: "processing" → правильно: "paid"
❌ city: "Питер" → правильно: "СПб"
Исследование показало, что модель генерирует "семантически близкие, но формально неверные" идентификаторы. Явный разбор прошлых ошибок работает как дообучение в одном промпте.
Ресурсы
Text2DSL: LLM-Based Code Generation for Domain-Specific Languages
Procedia Computer Science, 30th KES International Conference, 2026
Авторы: Kozachok Alexander, Nazimov Alexander, Magomedov Shamil
Организации: RTU MIREA (Москва), Академия ФСО РФ (Орёл)
Датасет PolkitBench: 4 204 валидированных пары NL→Polkit-rule
Связанные работы: DIN-SQL (schema linking), Synchromesh (grammar-constrained decoding), CodeBLEU metric
