Автоматизировать юридическую экспертизу сложно. Здесь нужно не просто описать ситуацию, но и грамотно трактовать законы, учитывать контекст и судебную практику, понимать интересы клиента.

Поэтому Legal Tech — одна из самых быстрорастущих отраслей в мире, а теперь она набирает обороты и в России. Однако не все так просто.

В других отраслях, таких как финансы и техподдержка, искусственный интеллект (ИИ) давно помогает снижать издержки, избегать рисков и повышать эффективность, в то время как юридические задачи в России чаще всего по-прежнему выполняют люди.

Почему так? Причины две:

  1. В российском праве многое зависит от формулировок текста, конкретных обстоятельств дела, роли участников, а также от судебной практики, которая отличается в разных регионах. К тому же даже самые современные языковые модели с трудом понимают термины и сложные конструкции в юридических текстах.

  2. Современные ИИ чаще всего обучаются на англоязычных юридических данных. Из-за этого сложно их внедрять в российскую юридическую практику — нужна адаптация.

Как решить эти проблемы и как создать надежных ИИ-консультантов — обсудим сегодня.

1. Зачем нужен ИИ-консультант в сфере права

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

Предположим, сотрудник уволился с работы по собственному желанию и обратился к ИИ-консультанту с просьбой разъяснить ситуацию с работодателем:

«Уволился по собственному. Работал 8 месяцев, но отпуск не брал. Должны ли выплатить компенсацию?»

Обычный поиск по Трудовому кодексу даст только конкретный ответ и укажет на ст. 127 ТК РФ: «При увольнении работнику выплачивается денежная компенсация за неиспользованные отпуска». Но ИИ-консультант учтет, сколько времени работал сотрудник, и поймет, что тот не брал отпуск и имеет право на компенсацию. Более того, ИИ укажет, сколько точно дней оплачиваемого отпуска должны компенсировать, поэтому ответ будет выглядеть так: «Да, вам должны выплатить компенсацию за неиспользованные 18 дней отпуска. Это предусмотрено ст. 127 ТК РФ».

Другой пример запроса:

«Соседи шумят по ночам, невозможно спать. Куда жаловаться и есть ли смысл?»

Обычный поиск сошлется на санитарные нормы, КоАП и так далее. Возможно, предложит несколько статей. ИИ-консультант же распознает, что речь идет о нарушении тишины в ночное время в многоквартирном доме, и ответит примерно так:

«Вы можете обратиться с жалобой в управляющую компанию, Роспотребнадзор или полицию. Нарушение тишины с 23:00 до 7:00 может повлечь штраф по ст. 6.3 КоАП. Зафиксируйте шум (например, аудиозаписью)».

Теперь посмотрим, как это работает на примере закона РФ «О защите прав потребителей». Предположим, пользователь задает ассистенту вопрос:

«Купил смартфон. Стал глючить через 10 дней после покупки, хочу вернуть. Что делать?».

Обычный справочник сослался бы на раздел статьи 18 «Права потребителя при обнаружении в товаре недостатков». ИИ-ассистент же должен понять:

  • что речь идет о технически сложном товаре,

  • что после покупки прошло 10 дней,

  • с какой проблемой столкнулся пользователь,

  • что автор запроса планирует товар вернуть.

В итоге ответ должен выглядеть примерно так: «Если смартфон имеет существенный недостаток, вы вправе требовать возврат денег в течение 15 дней с момента покупки (ст. 18 ЗоЗПП). После 15 дней — только при наличии экспертизы, подтверждающей дефект». Это уже не просто ответ, а на мини-консультация!

Именно такого юридического помощника — собственного ИИ-консультанта — мы и попробуем сегодня создать. Он не только облегчит работу с юридической информацией, но и сможет давать короткие консультации.

2. Построение юридического ИИ-консультанта

Чтобы создать ИИ-ассистента, нужно пройти несколько этапов:

  1. Сначала мы определим, какие именно функции и задачи будет выполнять наш помощник.

  2. Затем подготовим данные, соберем и структурируем всю информацию.

  3. И наконец, выберем подходящую модель искусственного интеллекта, которая станет «мозгом» нашего помощника.

Работать будем на платформе Google Colab — это удобный и бесплатный инструмент. Вы также можете создать продвинутую версию бота, сделав интерфейс в Telegram, Gradio или Streamlit.

Шаг 1. Постановка задачи

Основная задача ассистента — это правильно понять юридический запрос пользователя, сформулированный на естественном языке, и предоставить точный, обоснованный ответ с ссылкой на соответствующий документ.

Чтобы решить эту задачу, в качестве основного источника берем Закон о защите прав потребителей, который предварительно обрабатываем и разбиваем на отдельные части — чанки, где каждый чанк соответствует отдельной статье. При обработке запросов модель ищет релевантные статьи и на их основе формирует точный и обоснованный ответ.

Будем использовать современные подходы:

  • Загрузку документа через PyPDFLoader.

  • Векторное представление текстов с помощью HuggingFaceEmbeddings.

  • Индексацию и быстрый поиск по текстам через FAISS.

  • Построение цепочки вопрос-ответ с помощью RetrievalQA.

  • GPT модель — для генерации и понимания текста .

Приступим к работе и сначала установим и импортируем библиотеки:

!pip install -U langchain-community
!pip install pypdf
!pip install faiss-gpu-cu12

LangChain нужен для создания приложений с языковыми моделями (LLM), такими как GPT. Langchain-community содержит open-source интеграции (вроде FAISS, RAG, OpenAI и др.).

Pypdf — это библиотека для работы с PDF-документами: чтение, разбор, извлечение текста, метаданных и так далее. Полезна, если мы хотим загружать и анализировать pdf-файлы.

Faiss-gpu — это библиотека для быстрого поиска по векторным представлениям слов (например, чтобы находить похожие документы или текстовые фрагменты). Особенно полезно в системах «вопрос-ответ», чат-ботах с базой знаний и RAG (Retrieval-Augmented Generation).

import os
import re
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.schema import Document
from langchain.vectorstores.faiss import FAISS

Теперь нужно получить API key GPT :

api_key = os.environ["OPENAI_API_KEY"] = "sk-..."

Можно переходить к работе с данными.

Шаг 2. Подготовка данных

На этом этапе мы собираем и обрабатываем данные (в нашем случае — Закон), извлекаем из него основное содержимое, структурируем и векторизуем текст для дальнейшей передачи его в модель.


Для работы над ассистентом нужно собрать базу нормативных текстов. Основу возьмем из законов и подзаконных актов, дополним — пояснительными материалами,  решениями судов, часто задаваемыми вопросами (FAQ) с официальных ресурсов (например, Роспотребнадзора, КонсультантПлюс или Гаранта). Собрать их можно вручную или парсить с сайтов вроде consultant.ru, garant.ru и pravo.gov.ru.

В нашем примере мы используем готовый текст Закона о защите прав потребителей, скачанный в формате PDF, подготовленный www.consultant.ru. Разберем подробнее, как его предобрабатывать: извлекать текст, разбивать на статьи и готовить к векторизации:

loader = PyPDFLoader("/content/sample_data/Zakon_consultant.pdf")
documents = loader.load()

Загружаем и извлекаем текст из всех страниц PDF. Возвращаем список объектов Document, где каждая страница — это отдельный элемент со своим текстом и метаданными. Всего должно получиться 45 страниц. Посмотрим, как выглядит первая страница:

documents[0]

Document(metadata={'producer': 'КонсультантПлюс', 'creator': 'Версия 4021.00.500 1992 - 2022 КонсультантПлюс Сборка 582435',
'creationdate': '20220912111458', 'title': 'Закон РФ от 07.02.1992 N 2300-1\n(ред. от 14.07.2022)\nО защите прав
потребителей', '/content/sample_data/consultantplus_consultant.pdf', 'total_pages': 45, 'page': 0, 'page_label': '1'},
page_content='Закон РФ от 07.02.1992 N 2300-1\n(ред. от 14.07.2022)\nО защите прав потребителей\nдокумент предоставлен
КонсультантПлюс www.consultant.ru\nДата сохранения: 12.09.2022')

Как видите, здесь много лишней информации, ее нужно удалить.

Почему удаляем:

  1. Важно избавиться от неинформативного текста — например, ссылок, бесполезных символов и повторов. Такие элементы не несут смысла, но искажают векторное представление документов. Очистка позволяет FAISS точнее находить релевантные фрагменты юридических текстов.

  2. Большие языковые модели (LLM), включая GPT, работают с ограниченным числом токенов на запрос. Лишний текст расходует эти токены без пользы. Это не только снижает эффективность генерации, но и увеличивает стоимость обработки — особенно при работе с платными API.

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

Пример того, как мы можем предобработать наш документ (к коду даны краткие комментарии к каждому пункту):

def clean_text(text):
# Удаляем все URL, включая www.consultant.ru
text = re.sub(r"https?://\S+|www\.\S+", "", text)

# Удаляем технические вставки от КонсультантПлюс, ГАРАНТ и т.д.
text = re.sub(r"КонсультантПлюс.*?(\n|$)", "", text, flags=re.IGNORECASE)
text = re.sub(r"Документ предоставлен КонсультантПлюс", "", text, flags=re.IGNORECASE)
text = re.sub(r"Система ГАРАНТ\s*\d+/\d+", "", text, flags=re.IGNORECASE)
text = re.sub(r"Дата сохранения:.*?\n?", "", text, flags=re.IGNORECASE)

# Удаляем дублирующиеся заголовки законов
text = re.sub(r"Закон РФ от.*?\n", "", text)
text = re.sub(r"\(ред\. от.*?\)", "", text, flags=re.IGNORECASE)

# Удаляем редакционные и служебные примечания
text = re.sub(r"\(в ред\..*?\)", "", text, flags=re.IGNORECASE)
text = re.sub(r"\(абзац .*?\)", "", text, flags=re.IGNORECASE)
text = re.sub(r"\(часть .*?\)", "", text, flags=re.IGNORECASE)
text = re.sub(r"абзац утратил силу.*?(\n|$)", "", text, flags=re.IGNORECASE)
text = re.sub(r"часть утратила силу.*?(\n|$)", "", text, flags=re.IGNORECASE)
text = re.sub(r"- Примечание.*?(\n|$)", "", text, flags=re.IGNORECASE)

# Удаляем лишние подчеркивания, табы и многократные пробелы
text = re.sub(r"_+", "", text)
text = re.sub(r"[ \t]{2,}", " ", text)
text = re.sub(r"\s*\n\s*", " ", text)
text = re.sub(r"\s{2,}", " ", text)

return text.strip()

Применяем функцию  clean_text ко всему документу:

cleaned_docs = [doc.page_content for doc in documents]
cleaned_docs = [clean_text(text) for text in cleaned_docs]

Теперь разобьем документ на чанки — небольшие фрагменты текста, чтобы дальше было удобнее его обрабатывать. Например, текст объемом 10 000 слов можно разделить на 20 чанков по 500 слов. Затем чанки векторизуем и добавим в FAISS для семантического поиска. Система будет искать не по всему документу, а по отдельным частям (в нашем случае — по отдельным статьям Закона).

Благодаря этому, RAG-система при запросе не анализирует весь закон целиком, а сразу находит подходящие статьи и передает их в модель для генерации ответа.

def split_by_articles(text):
# Паттерн для распознавания заголовков типа "Статья 23", "Статья 23.1", "Статья 7.3-1"
pattern = r'(Статья\s+\d+(?:[\.\-]\d+)*\.?)'

# Разбиваем текст по заголовкам статей, сохраняя заголовки
parts = re.split(pattern, text)

chunks = []
for i in range(1, len(parts), 2):
    header = parts[i].strip()
    content = parts[i + 1].strip() if (i + 1) < len(parts) else ""
    chunk = f"{header} {content}".strip()
    if chunk:
        chunks.append(Document(page_content=chunk))
return chunks

Применяем функцию split_by_articles к предобработанному тексту:

# Объединяем весь очищенный текст в один
full_text = " ".join(cleaned_docs)
documents_by_articles = split_by_articles(full_text)

Пример того, что получаем на выходе на примере одной статьи:

documents_by_articles

[Document(metadata={}, page_content='Статья 1. Правовое регулирование отношений в области защиты прав потребителей 1.
Отношения в области защиты прав потребителей регулируются Гражданским кодексом Российской Федерации, настоящим Законом,
другими федеральными законами (далее - законы) и принимаемыми в соответствии с ними иными нормативными правовыми актами
Российской Федерации. (п. 1 в ред. Федерального закона от 21.12.2004 N 171-ФЗ)
2. Правительство Российской Федерации не вправе поручать федеральным органам исполнительной власти принимать акты,
содержащие нормы о защите прав потребителей.
Правительство Российской Федерации вправе издавать для потребителя и продавца (изготовителя, исполнителя, уполномоченной
организации или уполномоченного индивидуального предпринимателя, импортера, владельца агрегатора) правила, обязательные при
заключении и исполнении публичных договоров (договоров розничной купли-продажи, энергоснабжения, договоров о выполнении
работ и оказании услуг). (абзац введен Федеральным законом от 21.12.2004 N 171-ФЗ; в ред. Федерального закона от
24.04.2020 N 144-ФЗ)'),

Document(metadata={}, page_content='Статья 2. Международные договоры Российской Федерации 1. Если международным договором
Российской Федерации установлены иные правила о защите прав потребителей, чем те, которые предусмотрены настоящим Законом,
применяются правила международного договора. 2. Решения межгосударственных органов, принятые на основании положений
международных договоров Российской Федерации в их истолковании, противоречащем Конституции Российской Федерации,
не подлежат исполнению в Российской Федерации. Такое противоречие может быть установлено в порядке, определенном федеральным
конституционным законом. (п. 2 введен Федеральным законом от 08.12.2020 N 429-ФЗ)')
]

Теперь перейдем к индексации документов и познакомимся с моделями.

Шаг 3. Выбор модели

В нашем проекте мы будем использовать модель rubert-tiny2, созданную на основе архитектуры BERT и адаптированную для русского языка.

Плюсы этой модели:

  • ее просто использовать, потому что у нее небольшой вес,

  • для ее получения достаточно обратиться к Hugging Face,

  • она подходит для быстрого выполнения задач и имеет максимальную длину контекста 2048 токенов.

Вы можете выбрать и другую модель — например ruBERT, ruGPT или GigaChat.

Для получения эмбеддингов (числовых представлений текста) загружаем модель. Ее задача — точно передавать смысл каждого текстового фрагмента (чанка) в виде вектора.

embedding_model = HuggingFaceEmbeddings(model_name="cointegrated/rubert-tiny2")
db = FAISS.from_documents(documents_by_articles, embedding_model)

Затем инициализируем GPT, для примера мы будем использовать версию gpt-3.5-turbo, но вы можете взять любую. Указываем значение temperature=0.2, чтобы снизить уровень вариативности в ответах модели, так как нам нужны более надежные и однозначные ответы:

llm = ChatOpenAI(
    model="gpt-3.5-turbo",  # или "gpt-4"
    temperature=0.2,
    openai_api_key=api_key
)

Построим цепочку QA. Создаем связку retriever и qa_chain, чтобы реализовать подход Retrieval-Augmented Generation (RAG). Ретривер извлекает 3 наиболее релевантных фрагмента из базы (параметр k=3), а затем модель формирует ответ на основе найденного контекста.

retriever = db.as_retriever(search_kwargs={"k": 3})
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)

Шаг 4. Оценка качества

Теперь рассмотрим результат работы на наших запросах.

Вернемся к вопросу пользователя:

query = "Купил смартфон. Стал глючить через 10 дней после покупки, хочу вернуть. Что делать?"
response = qa_chain.invoke({"query": query})

Что получилось:

{'query': 'Купил смартфон. Стал глючить через 10 дней после покупки, хочу вернуть. Что делать?',
'result': 'Согласно статье 26.1 закона "О защите прав потребителей", вы можете отказаться от товара ненадлежащего качества
в течение семи дней после его передачи. В вашем случае, если смартфон начал глючить через 10 дней после покупки,
вы можете обратиться к продавцу с требованием о возврате товара и возврате денежной суммы, уплаченной по договору.
Продавец обязан вернуть вам деньги, за исключением расходов на доставку, не позднее чем через десять дней с дня предъявления вами требования.'}

Попробуем другие запросы:

query = "Какие документы нужно предоставить для возврата товара?"
response = qa_chain.invoke({"query": query})

Результат:

{'query': 'Какие документы нужно предоставить для возврата товара?',
'result': 'Для возврата товара надлежащего качества потребителю необходимо сохранить товарный вид, потребительские свойства товара,
а также иметь документ, подтверждающий факт и условия покупки указанного товара. Если у потребителя нет товарного или кассового чека,
он может использовать другие доказательства приобретения товара у данного продавца.'}

Еще один:

query = "Как вернуть товар, если он был куплен онлайн?"
response = qa_chain.invoke({"query": query})

Вывод:

{'query': 'Как вернуть товар, если он был куплен онлайн?',
'result': 'В случае покупки товара онлайн, потребитель вправе отказаться от товара в любое время до его передачи,
а после передачи товара - в течение семи дней. Возврат товара надлежащего качества возможен при сохранении его товарного вида,
потребительских свойств и наличии документа, подтверждающего факт и условия покупки товара.
Потребитель должен обратиться к продавцу с требованием о возврате уплаченной за товар денежной суммы.'}

Попробуем оценить, какие еще варианты ответов может предложить система. Для этого выведем топ-3 наиболее релевантных фрагмента из базы знаний и проанализируем их с точки зрения близости к исходному запросу. FAISS-индекс работает с метрикой L2 (евклидово расстояние), что позволяет измерить, насколько близко по смыслу каждый чанк находится к заданному вопросу.

from langchain.vectorstores.faiss import FAISS

similar_docs_and_scores = db.similarity_search_with_score(query, k=3)

for i, (doc, score) in enumerate(similar_docs_and_scores, 1):
    print(f"\n--- Документ {i} ---")
    print(f"Схожесть: {score:.4f}")
    print(doc.page_content[:500])

Важно понимать, что retriever сам по себе не выбирает «правильный» ответ, его задача — извлечь k наиболее подходящих по смыслу фрагментов (документов или статей).

Затем уже LLM анализирует все переданные фрагменты и самостоятельно формирует финальный ответ. Она не выбирает один конкретный чанк, а синтезирует информацию из всех источников.

Чтобы объективно оценить качество ответов на юридические вопросы, важно привлекать экспертов, практикующих юристов. Они проверят, соответствуют ли ответы законодательству, насколько полно раскрыта тема и нет ли искажений.

Вывод

Сегодня мы разобрали, как с помощью больших языковых моделей (LLM) и инструментов RAG и FAISS можно собрать работающий прототип LegalTech-ассистента. Он умеет искать и структурировать информацию по Закону о защите прав потребителей.

На практике такой ИИ-ассистент поможет разгрузить специалистов, а людям без юридического образования — легко находить нужную информацию и ответы на вопросы.

Что дальше? Можно подключить новые нормативные акты, научить ИИ обрабатывать более сложные запросы и внедрить другие полезные возможности. В следующих статьях расскажем, как развить прототип в полноценного LegalTech-ассистента.