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

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

В качестве «мозга» системы была выбрана локальная языковая модель 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 следующего содержания…”.

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

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).

enes