Что такое Guided Decoding и как оно связано с JSON schema?
Краткий тезис
Guided Decoding — это техника ограничения генерации токенов во время декодирования LLM, чтобы гарантировать, что выходной текст соответствует заданной формальной спецификации, например JSON Schema. В отличие от пост-обработки (попытки исправить JSON после генерации), decoding|guided decoding работает на уровне вероятностного распределения токенов, маскируя недопустимые варианты. Это критически важно для Agentic RAG, где агенты должны возвращать строго структурированные вызовы функций или JSON-объекты для дальнейшей обработки.
1. Проблема: неструктурированный вывод LLM
LLM по умолчанию генерирует свободный текст. Даже если в промпте указано «верни JSON», модель может:
- пропустить закрывающую скобку;
- использовать неверный тип данных (строка вместо числа);
- добавить лишние поля, не предусмотренные схемой;
- сгенерировать валидный JSON, но не соответствующий ожидаемой структуре.
Пост-обработка (например, json.loads() с try-except) ненадёжна: она либо падает, либо требует дорогих повторных запросов к LLM. Guided Decoding решает эту проблему на этапе генерации.
2. Guided Decoding vs пост-обработка
| Характеристика | Guided Decoding | Пост-обработка |
|---|---|---|
| Гарантия валидности | Да (100% соответствие схеме) | Нет (зависит от качества LLM) |
| Дополнительные запросы к LLM | Нет | Часто требуется повторная генерация |
| Скорость | Немного медленнее обычной генерации (из-за маскирования) | Быстро, но с риском ошибок |
| Гибкость | Поддерживает любые контекстно-свободные грамматики | Ограничена возможностями парсинга |
| Интеграция | Требует специальных библиотек | Встроена в любой код |
3. Как работает Guided Decoding
Основная идея — на каждом шаге декодирования (при генерации очередного токена) вычисляется маска допустимых токенов, которая обнуляет вероятности всех токенов, не соответствующих текущему состоянию грамматики/схемы.
Процесс
- Задаётся формальная спецификация (JSON Schema, грамматика, Pydantic-модель).
- Спецификация преобразуется в конечный автомат (DFA) или контекстно-свободную грамматику.
- Во время генерации LLM поддерживается текущее состояние автомата.
- Для каждого состояния вычисляется множество разрешённых следующих токенов (с учётом токенизации BPE).
- Вероятности всех остальных токенов принудительно зануляются.
- Выбор следующего токена происходит только из разрешённого множества.
Пример для JSON Schema
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"]
}
Автомат будет разрешать:
- сначала
{(начало объекта); - затем
"name"(ключ); - затем
:; - затем строку в кавычках;
- затем
,или}; - затем
"age"и т.д.
4. JSON Schema как грамматика
JSON Schema — это декларативный язык для описания структуры JSON-документов. Guided Decoding использует её как грамматику: каждое правило схемы (type, properties, items, enum и т.д.) транслируется в ограничения на последовательность токенов.
Пример трансляции
"type": "string"→ разрешает только токены, составляющие строку в кавычках (включая экранирование).- "enum": ["red", "green"] → разрешает только токены, образующие одну из строк "red" или
"green". - "minimum": 0 → разрешает только числовые токены, которые при парсинге дают число >= 0.
Библиотеки (outlines, guidance) автоматически строят конечный автомат по схеме.
5. Реализации: outlines, lmql, guidance
5.1 Outlines (рекомендуемая)
from outlines import generate, models
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
model = models.transformers("mistralai/Mistral-7B-v0.1")
generator = generate.json(model, Person)
result = generator("Extract person from: John is 30 years old.")
# result = Person(name="John", age=30)
Outlines поддерживает Pydantic, JSON Schema, регулярные выражения.
5.2 LMQL
from lmql import LMQL
@lmql.query
def extract_person(text):
'''lmql
"Extract person from: {text}"
return {"name": name, "age": age} :: {
"name": str,
"age": int
}
'''
LMQL встраивает ограничения прямо в язык запросов.
5.3 Guidance
from guidance import models, gen
model = models.LlamaCpp("model.gguf")
result = model + f'Extract person: John is 30 years old. JSON: {gen("json", pattern=r"{.*}")}'
Guidance позволяет задавать грамматику через регулярные выражения или встроенные типы.
6. Связь с Agentic RAG
В Agentic RAG агент (LLM) должен не только отвечать на вопрос, но и выполнять действия: вызывать функции, обращаться к внешним API, обновлять состояние. Все эти действия требуют строго структурированного вывода — обычно JSON с полями action, parameters и т.д.
Пример:
{
"action": "search_documents",
"parameters": {
"query": "guided decoding",
"top_k": 5
}
}
Без Guided Decoding агент может сгенерировать "action": "search_documents" без кавычек или с опечаткой, что приведёт к ошибке выполнения. Guided Decoding гарантирует, что вывод всегда будет соответствовать заданной схеме вызова функции.
7. Производительность и ограничения
Плюсы
- Гарантированная валидность вывода.
- Снижение числа повторных запросов.
- Возможность генерировать сложные вложенные структуры.
Минусы
- Немного увеличивает время генерации (на 5–20% в зависимости от сложности схемы).
- Требует поддержки со стороны библиотеки (не все фреймворки умеют).
- Сложно комбинировать с другими техниками (например, beam search).
Когда использовать
- Агенты, вызывающие функции.
- Извлечение структурированных данных из текста.
- Генерация конфигурационных файлов.
- Любой сценарий, где валидность вывода критична.
8. Пет-проект для закрепления
Задача Создать агента, который по тексту вопроса определяет, какой инструмент вызвать (поиск по документам, калькулятор, погода), и возвращает JSON с параметрами вызова. Использовать Guided Decoding для гарантии корректного JSON.
Инструменты
- Python 3.10+
- Hugging Face Transformers (или llama.cpp)
- Библиотека outlines
- FastAPI для демонстрации
Шаги:
- Определить Pydantic-модели для каждого инструмента (SearchTool, CalculatorTool, WeatherTool).
- Загрузить небольшую LLM (например, Qwen2.5-1.5B-Instruct).
- Написать функцию, которая принимает текст и возвращает JSON, используя outlines.generate.json с объединённой схемой (discriminated union).
- Обернуть в FastAPI-эндпоинт.
- Протестировать на примерах: "Какая погода в Москве?" →
{"tool": "weather", "params": {"city": "Москва"}}.
Ожидаемый результат Агент всегда возвращает валидный JSON, соответствующий одной из схем. Без Guided Decoding модель иногда ошибается (пропускает кавычки, путает типы).
9. Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 212 | Что такое Agentic RAG и как он отличается от обычного RAG? |
| 214 | Как реализовать вызов функций (function calling) в LLM? |
| 215 | Какие существуют паттерны multi-agent систем? |
| 210 | Как обеспечить детерминированность ответов LLM? |
| 205 | Какие методы структурированного вывода вы знаете? |
10. Навигация
- Предыдущий: 212
- Следующий: 214
- Индекс: 00. Индекс разборов
Навигация
- Предыдущий: 212
- Следующий: 214
- Индекс: 00. Индекс разборов