3,583 papers
arXiv:2606.22586 74 21 июня 2026 г. FREE

Structured Context Injection: как устранить галлюцинации LLM при генерации в строгих форматах

КЛЮЧЕВАЯ СУТЬ
LLM почти никогда не угадывает правильные идентификаторы в незнакомых форматах: точность совпадения — 0.15 из 1.0. Метод Structured Context Injection позволяет генерировать строгие форматы — карточки товаров, конфиги, запросы к базам — без выдуманных полей и значений. Вставляешь три блока в промпт: правила структуры, что означает каждое поле, полный список допустимых значений. Фишка: словарь переключает модель с угадывания на выбор из списка — точность совпадения вырастает с 0.15 до 0.63, синтаксическая корректность — до 98.6–99.4%. Без дообучения.
Адаптировать под запрос

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_SELF vs AUTH_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


📋 Дайджест исследования

Ключевая суть

LLM почти никогда не угадывает правильные идентификаторы в незнакомых форматах: точность совпадения — 0.15 из 1.0. Метод Structured Context Injection позволяет генерировать строгие форматы — карточки товаров, конфиги, запросы к базам — без выдуманных полей и значений. Вставляешь три блока в промпт: правила структуры, что означает каждое поле, полный список допустимых значений. Фишка: словарь переключает модель с угадывания на выбор из списка — точность совпадения вырастает с 0.15 до 0.63, синтаксическая корректность — до 98.6–99.4%. Без дообучения.

Принцип работы

LLM не работает как база данных. Просишь поле 'country' — она не знает что в твоей системе принято: 'RU', 'Russia' или 'Россия'. Берёт то, что чаще встречалось при обучении. Попадает семантически близко — но формально мимо: filesystem-disk-mount вместо filesystem-mount. Карточка не проходит валидацию. Три блока решают три разные задачи: правила убирают синтаксические ошибки, спецификация объясняет семантику, словарь блокирует выдуманные значения. Плюс явная инструкция 'Используй ТОЛЬКО контекст, не свои знания' — без неё модель смешивает твой список со своим обучением и получается каша.

Почему работает

У модели нет проблем с рассуждением. Есть проблема с угадыванием закрытых словарей. Она понимает что пользователь хочет 'указать страну производства'. Но не знает как именно это называется в твоей системе. Как только даёшь список — перестаёт сочинять и начинает выбирать. Словарь даёт наибольший прирост из трёх блоков — больше, чем правила синтаксиса и спецификация полей вместе взятые. Остаток галлюцинаций (~22% генераций с хотя бы одной ошибкой) — не выдумка, а достройка суффиксов по аналогии. Для критических систем нужна валидация на выходе.

Когда применять

Генерация в строгих форматах → для карточек товаров, конфигурационных файлов, запросов к базам данных, внутренних языков разметки — особенно когда идентификаторы закрытые (атрибуты с конкретными числовыми ID, теги из справочника, коды из стандарта). НЕ подходит если словарь огромный — тысячи идентификаторов раздуют контекст, режь на подмножества по категориям. Для семантически близких значений вроде AUTH_SELF и AUTH_ADMIN добавляй пояснение в спецификацию — иначе модель путается.

Мини-рецепт

1. Открой ролью и запретом: 'Ты генератор [что генерируешь]. Используй ТОЛЬКО контекст ниже. НЕ используй свои знания о [область].'
2. Блок правил: обязательные поля, типы данных, порядок — структура без исключений.
3. Блок спецификации: что означает каждое поле — коротко, одной строкой на поле.
4. Блок словаря: полный список допустимых значений. Отдели меткой === ДОПУСТИМЫЕ ЗНАЧЕНИЯ ===. Это главный блок.
5. Один пример: заполненный образец в нужном формате — модель подхватывает паттерн.
6. Задача: описание на нормальном языке что нужно сгенерировать.

Примеры

[ПЛОХО] : Сгенерируй JSON-карточку для Wildberries: мужские кроссовки из текстиля, Китай, размеры 40-44, бренд Strobbs
[ХОРОШО] : Ты генератор карточек Wildberries. Используй ТОЛЬКО контекст ниже, НЕ свои знания. === ПРАВИЛА === Обязательные поля: brand, category, subject, attributes === СПЕЦИФИКАЦИЯ === Атрибут 85: Материал верха. Атрибут 111: Страна (ISO-код). Атрибут 14: Пол. Атрибут 7826: Размер EU. === ДОПУСТИМЫЕ ЗНАЧЕНИЯ === Категории: Обувь, Одежда. Материалы: Текстиль, Натуральная кожа, Замша. Страны: CN, RU, TR. Размеры: 40, 41, 42, 43, 44. === ПРИМЕР === {"brand":"Ralf","category":"Обувь","subject":"Ботинки","attributes":{"85":"Натуральная кожа","111":"RU","14":"Мужской","7826":["41"]}} Сгенерируй карточку: мужские кроссовки из текстиля, Китай, размеры 40-44, бренд Strobbs Без словаря модель напишет "материал": "хлопок" вместо "Текстиль" и "страна": "China" вместо "CN". Карточка не пройдёт валидацию. Со словарём — значения строго из списка.
Источник: Text2DSL: LLM-Based Code Generation for Domain-Specific Languages
ArXiv ID: 2606.22586 | Сгенерировано: 2026-06-28 20:52

Проблемы LLM

ПроблемаСутьКак обойти
Модель выдумывает идентификаторы в закрытых форматахПросишь сгенерировать JSON, конфиг или запрос. Твоя система принимает строго "RU" — модель пишет "Russia". Или твой API ждёт filesystem-mount — модель пишет filesystem-disk-mount. Семантически близко. Формально неверно. Валидация падает. Модель не злобствует — она просто не знает твой конкретный словарь и угадывает по похожестиВставь в промпт полный список допустимых значений. Добавь инструкцию: «Используй только значения из списка выше. Не додумывай». Модель переключается с угадывания на выбор из предложенного

Методы

МетодСуть
Три блока контекста — генерация в строгий формат без ошибокВставляй в начало промпта три секции. Блок 1 — правила структуры: какие поля обязательны, в каком порядке, какой тип данных. Блок 2 — спецификация: что означает каждое поле. Блок 3 — словарь: полный список всех допустимых значений без исключений. Плюс явная инструкция: «Используй только контекст выше. Не используй свои знания о {предметная область}». Затем — задача. Всё в одном запросе. Пример-образец внутри промпта даёт дополнительный прирост. Работает: JSON, конфиги, карточки товаров, внутренние форматы API. Не работает идеально: ~22% ответов всё равно содержат хотя бы одну ошибку — нужна валидация

Тезисы

ТезисКомментарий
Словарь допустимых значений важнее правил синтаксисаКогда вставляешь контекст в промпт, наибольший прирост точности даёт именно закрытый список значений — не правила структуры и не описание полей. Почему: у модели нет проблем с пониманием структуры. Проблема — она не знает как именно называется нужная вещь в твоей системе. Как только видит список — перестаёт угадывать. Применяй: если контекст не помещается целиком, сначала режь описания, но сохраняй список значений
📖 Простыми словами

Text2DSL:LLM-Based Code Generation for Domain-SpecificLanguages

arXiv: 2606.22586

Когда ты просишь нейронку написать код на редком языке или заполнить сложную базу данных, она ведет себя как самоуверенный стажер. Проблема в том, что LLM не знает твоих внутренних правил и специфических форматов, поэтому она начинает «галлюцинировать» — подставлять названия полей и значения, которые звучат логично, но в твоей системе просто не существуют. Исследование Text2DSL доказывает, что модель лажает не из-за глупости, а из-за нехватки жестких рамок, и лечится это внедрением трех конкретных ограничителей прямо в промпт.

Это как если бы ты отправил человека в огромный супермаркет купить «что-нибудь к чаю», не дав списка. Он принесет то, что любит сам, а не то, что нужно тебе. Формально поручение выполнено, но по факту — полный облом, потому что у тебя аллергия на сахар, а он купил торт. Чтобы метод Text2DSL сработал, нужно дать четкую инструкцию: карту отделов, состав продуктов и список брендов, которые есть в наличии.

В основе метода лежат три кита: правила формата, спецификация объектов и закрытый список значений. Сначала ты объясняешь нейронке синтаксис (как расставлять скобки), потом разжевываешь смысл каждого метода, и, самое главное, даешь список разрешенных слов. Если в системе принято писать RU, а модель выдает Russia — это ошибка, которая ломает всё. Text2DSL бьет по рукам за любую отсебятину, заставляя модель выбирать только из предложенного меню, что сводит галлюцинации к нулю.

Тестировали это на специфических языках программирования, но принцип универсален для любого бизнеса, где есть строгие стандарты. Будь то карточки товаров на маркетплейсах, медицинские протоколы или банковские транзакции — везде, где семантическая близость не заменяет формальную точность. Если менеджер Wildberries хочет, чтобы нейронка не выдумывала несуществующие материалы тканей, ему нужно внедрить этот метод, иначе модерация завернет 10 из 10 карточек.

Короче: хватит надеяться на «ум» модели, она всегда будет пытаться угадать, если ей не запретить. SEO для кода умирает, на смену приходит жесткая структура. Нужно перестать кормить нейронку общими фразами и начать скармливать ей словари и схемы. Либо ты даешь модели закрытый список, либо получаешь мусор на выходе, который придется переделывать руками.

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с