Создание ДС с локальной LLM. Часть 2: Строгая структура данных (JSON Schema)
В первой части мы рассмотрели общую архитектуру решения для автоматической генерации Дополнительных Соглашений. Мы выяснили, что ключ к успеху — это не просто "поболтать" с моделью, а заставить её работать как часть жесткого алгоритма.
Сегодня мы углубимся в техническую реализацию этого "принуждения". Как заставить творческую языковую модель (LLM) возвращать данные, которые можно безопасно вставить в базу данных или Word-документ, не опасаясь галлюцинаций или лишнего текста?
Ответ: **JSON Schema** и режим **Structured Outputs**.
Это вторая часть большой серии, где я опишу подробно каждый раздел из общей части. Подписывайся на меня в телеграм, если тоже любишь автоматизировать юридические процессы.
Проблема: LLM любят поговорить
Обычный промпт: "Извлеки из договора номер и дату" часто приводит к ответу: "Конечно! Я проанализировал текст. Номер договора — 123, а дата заключения — 1 января 2025 года."
Для человека это понятно. Для кода — это катастрофа. Нам нужно писать регулярные выражения, чтобы вытащить данные из этого ответа. А если модель решит изменить формат ответа завтра? Весь пайплайн сломается.
Решение: Structured Outputs
Современные движки для запуска LLM (включая `vLLM`, `llama.cpp` и серверы, совместимые с OpenAI API) поддерживают параметр `response_format`. Мы можем передать схему данных, и движок будет гарантировать, что выход модели валиден относительно этой схемы.
В моем проекте я использую локальную модель Qwen, и для неё я определил строгую схему `ADDENDUM_SCHEMA`.
Реализация в коде
Вот как выглядит определение схемы на Python (фрагмент из `generate_addendums.py`):
Разбор архитектурных решений в схеме
Почему схема именно такая? Обратите внимание на несколько неочевидных моментов.
1. Борьба с падежами
Русский язык сложен для автоматической генерации шаблонов. В преамбуле ДС мы пишем: "...в лице Генерального директора Иванова И.И., действующего на основании..." (Родительный падеж).
В блоке подписей: > "Генеральный директор Иванов И.И.(Именительный падеж).
Если просить модель вернуть просто "ФИО подписанта", нам придется склонять его отдельной библиотекой (типа `pymorphy2`), которая часто ошибается с фамилиями.
Решение: Я запрашиваю у LLM сразу готовые формы: `подписант_заказчика` (для реквизитов) `подписант_заказчика_в_родительном падеже` (для преамбулы)
Это перекладывает задачу склонения на языковую модель, которая "чувствует" контекст лучше, чем алгоритмические морфолизаторы.
2. Конструктор фраз изменений
Для внесения изменений в договор формулировки могут быть разными: "Дополнить Статью 5.." или "Дополнить Раздел 2...". Чтобы шаблон Word был универсальным, я прошу модель вернуть готовые грамматические формы: `фраза_единицы_предмет_вин`: "статью 5" (Винительный падеж — дополнить кого/что?) `фраза_пункт_предмет_твор`: "пунктом 5.1" (Творительный падеж — дополнить кем/чем?)
Это позволяет в шаблоне DOCX написать просто: `{фраза_единицы_предмет_вин}` дополнить `{фраза_пункт_предмет_твор}` следующего содержания:
И это будет работать корректно и для "статью 5", и для "раздел 2".
3. Атомарность данных
Я разделил логические части изменений на отдельные поля: `последний_пункт` `добавляемый_пункт`
Это позволяет на этапе пост-обработки (уже в Python) проверить логику модели. Если `добавляемый_пункт` не следует за `последним` (например, после 3.4 идет 3.6), я могу залогировать это как предупреждение или даже перезапустить генерацию.
Как это работает в API
При вызове модели мы передаем эту схему в параметре `response_format`. Вот фрагмент функции `call_llm`:
Благодаря `temperature: 0.0` и `response_format`, мы получаем скучный, предсказуемый, но идеально валидный JSON, который можно сразу отправлять в генератор документов.
Что дальше?
Теперь, когда у нас есть надежный способ получения структурированных данных, нам нужно помочь модели не ошибиться в цифрах и фактах. В следующей части мы рассмотрим Structural Hints — как мы "подсказываем" модели правильные ответы, предварительно вычисляя их алгоритмически.
Кому, как и мне, интересно автоматизировать юридические процессы, присоединяйтесь ко мне в телеграме, там я пишу "человеческим языком", а не вот это вот всё)