Автоматизация создания Дополнительных Соглашений (ДС) с помощью локальной модели Qwen (Часть 1: Общая)

В этой статье я расскажу о разработке решения для автоматической генерации Дополнительных Соглашений (ДС) к договорам. Основная задача — избавить юристов и менеджеров от рутины, переложив анализ текста договора и формирование «рыбы» документа на искусственный интеллект.

Это первая часть большой серии, где я опишу процесс в общих чертах, а дальше каждую часть раскрою отдельно. Подписывайся на меня в телеграм, если тоже любишь автоматизировать юридические процессы.

В качестве «мозга» системы была выбрана локальная языковая модель Qwen (в частности версия `qwen3-vl-30b-a3b-thinking`), работающая через локальный API-сервер. Это обеспечивает конфиденциальность данных (тексты договоров не покидают контур компании) и отсутствие затрат на облачные токены.

Архитектура решения

Система написана на Python и состоит из трех основных этапов:

1. Сбор данных: Загрузка исходных данных о договорах из базы SQLite.

2. Интеллектуальный анализ (LLM): Извлечение ключевых параметров (стороны, номера, даты) и логический вывод новых данных (следующий номер пункта, склонение ФИО).

3. Генерация документа: Заполнение шаблона `.docx` полученными данными.

1. Строгая структура данных (JSON Schema)

Одной из главных проблем при работе с LLM является нестабильность вывода. Чтобы модель возвращала данные в четко заданном формате, я использовал Structured Outputs (JSON Schema).

В коде определена схема `ADDENDUM_SCHEMA`, которая жестко диктует модели, какие поля она должна вернуть: `номер_ДС`, `дата_ДС` * `подписант_заказчика_в_родительном падеже` (критично для преамбулы ДС) Блоки для разделов «Предмет», «Оплата», «Сроки» (тип единицы, номер пункта, текст цитаты).

Это позволяет избежать парсинга свободного текста и сразу получать готовый JSON для вставки в шаблон.

Подробнее здесь

2. Техника «Подсказок» (Structural Hints)

Локальные модели, даже мощные, иногда ошибаются в простой арифметике или навигации по большим текстам (например, могут неправильно определить последний пункт в разделе).

Чтобы повысить точность, я реализовал гибридный подход. Вместо того чтобы просить модель саму считать пункты, я делаю это алгоритмически на Python с помощью функции `structural_hints_for_llm`:

1. Скрипт парсит структуру договора (главы, статьи).

2. Находит разделы, содержащие ключевые слова («ПРЕДМЕТ», «ОПЛАТА», «СРОК»).

3. Вычисляет последний номер пункта (например, `2.4`) и генерирует номер для нового пункта (`2.5`).

Эти вычисленные данные передаются модели в поле `hints`. Модели остается лишь «собрать» всё в красивую фразу, например: "дополнить раздел 2 пунктом 2.5 следующего содержания...".

Пример кода подсказок:

python def structural_hints_for_llm(contract_json: dict) -> dict: # ... логика поиска разделов ... subj = find(lambda tt: re.search(r"ПРЕДМЕТ", tt, re.IGNORECASE)) if subj: out["тип_единицы_предмет"] = subj["type"] out["последний_пункт_предмет"] = subj["last"] out["добавляемый_пункт_предмет"] = subj["next"] # Python сам посчитал +1 return out

Подробнее здесь

3. Работа с русской грамматикой

Для корректного формирования ДС необходимо склонять имена и должности (например, "в лице Генерального директора Иванова..."). В промпте для LLM я использую специальную инструкцию: "Верни грамматически корректные фразы... а также должность и ФИО подписантов в родительном падеже... ВНИМАНИЕ: поля родительного падежа возвращай БЕЗ предлога ‘в лице’".

Дополнительно на стороне Python реализована функция очистки `sanitize_signatory_gen`, которая убирает лишние скобки и мусор, если модель всё-таки добавила их.

Подробнее здесь

4. Взаимодействие с API

Для общения с моделью используется стандартный REST API (совместимый с OpenAI), поднятый локально (например, через LM Studio на порту 1234). Функция `call_llm` отправляет контекст договора, системный промпт и подсказки. Реализован механизм повторных попыток (retries) на случай, если модель не ответит или вернет битый JSON.

python payload = { "model": "qwen3-vl-30b-a3b-thinking", "messages": [...], "response_format": ADDENDUM_SCHEMA # Принуждение к схеме }

Подробнее здесь

5. Генерация DOCX

Финальный этап — подстановка данных в XML-структуру Word-документа. Вместо сложных библиотек шаблонизации используется прямой поиск и замена плейсхолдеров в XML или построение документа с нуля через `python-docx` на основе полученных данных.

Подробнее здесь

Итоги

Использование локальной модели Qwen-30B в связке с алгоритмическим пре-процессингом позволило создать надежный инструмент.

Плюсы: Полная приватность, отсутствие затрат на API, высокая точность благодаря гибридному подходу (Python считает, LLM формулирует).

Сложности: Требуется мощное железо для быстрого инференса модели 30B, но можно обойтись и игровой видеокартой или мощным процессором.

Это решение демонстрирует, что для юридических задач не обязательно использовать ChatGPT — правильно настроенная локальная модель с грамотной обвязкой кода справляется не хуже.

Кому, как и мне, интересно автоматизировать юридические процессы, присоединяйтесь ко мне в телеграме, там я пишу "человеческим языком", а не вот это вот всё)

Начать дискуссию