AI-агент для анализа юридических документов
Юрист тратит 60–70% времени на анализ документов: чтение договоров, выявление рисковых условий, проверку соответствия шаблонам, сравнение версий. AI-агент не заменяет юридическую экспертизу, но делает черновую аналитическую работу за минуты вместо часов: находит отклонения от стандарта, выявляет отсутствующие обязательные условия и формирует структурированный отчёт с конкретными ссылками на пункты.
Архитектура юридического агента
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import PyPDFLoader, Docx2txtLoader
from langchain_core.tools import tool
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
import json
class LegalAnalysisState(TypedDict):
document_text: str
document_type: str
analysis_results: Annotated[list, operator.add]
risk_flags: Annotated[list, operator.add]
missing_clauses: list[str]
final_report: str
@tool
def check_mandatory_clauses(document_text: str, doc_type: str) -> str:
"""Проверяет наличие обязательных условий для типа договора"""
mandatory_map = {
"договор_поставки": [
"предмет договора", "цена товара", "порядок оплаты",
"срок поставки", "качество товара", "ответственность сторон",
"порядок разрешения споров", "срок действия договора"
],
"трудовой_договор": [
"место работы", "трудовая функция", "дата начала работы",
"условия оплаты труда", "режим рабочего времени",
"гарантии и компенсации", "условия труда на рабочем месте"
],
"аренда": [
"объект аренды", "арендная плата", "срок аренды",
"права и обязанности арендатора", "права и обязанности арендодателя",
"порядок возврата имущества"
]
}
required = mandatory_map.get(doc_type, [])
text_lower = document_text.lower()
missing = []
present = []
for clause in required:
# Fuzzy matching — не точное совпадение слов
if any(word in text_lower for word in clause.split()):
present.append(clause)
else:
missing.append(clause)
return json.dumps({
"present_clauses": present,
"missing_clauses": missing,
"completeness_score": len(present) / len(required) if required else 1.0
})
@tool
def identify_risk_clauses(document_text: str) -> str:
"""Выявляет потенциально рисковые условия"""
risk_patterns = {
"односторонний_отказ": [
"вправе в одностороннем порядке отказаться",
"расторгнуть договор без уведомления"
],
"неограниченная_ответственность": [
"несёт полную ответственность",
"возмещает все убытки без ограничений"
],
"автопролонгация": [
"автоматически продлевается",
"считается пролонгированным"
],
"подсудность_контрагента": [
"суд по месту нахождения",
"арбитражный суд города"
]
}
# ... анализ паттернов
return json.dumps({"risks_found": []})
Сравнение с шаблонным договором
class ContractComparator:
COMPARISON_PROMPT = """Сравни договор с эталонным шаблоном компании.
Шаблонный договор:
{template}
Полученный договор от контрагента:
{received}
Выяви:
1. **Отклонения в пользу контрагента** (они получили лучшие условия)
2. **Отклонения против нашей компании** (мы несём повышенные риски)
3. **Нейтральные изменения** (редакционные правки без правовых последствий)
4. **Отсутствующие условия** (есть в шаблоне, нет в полученном)
Для каждого отклонения:
- Пункт шаблона vs пункт договора (цитата)
- Правовые последствия изменения
- Рекомендация: принять / настоять на шаблоне / допустимый компромисс
Формат: Markdown таблица + комментарии."""
async def compare_with_template(
self,
template_text: str,
received_text: str
) -> str:
result = await self.llm.ainvoke(
self.COMPARISON_PROMPT.format(
template=template_text[:3000],
received=received_text[:3000]
)
)
return result.content
Граф анализа (LangGraph)
def build_legal_agent_graph():
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [
check_mandatory_clauses,
identify_risk_clauses,
]
def analyze_node(state: LegalAnalysisState) -> LegalAnalysisState:
# Шаг 1: определение типа документа
doc_type_result = llm.invoke(
f"Определи тип документа (1-2 слова): {state['document_text'][:500]}"
)
state["document_type"] = doc_type_result.content.strip()
# Шаг 2: проверка обязательных условий
mandatory_check = check_mandatory_clauses.invoke({
"document_text": state["document_text"],
"doc_type": state["document_type"]
})
state["analysis_results"].append(json.loads(mandatory_check))
# Шаг 3: выявление рисков
risk_check = identify_risk_clauses.invoke({
"document_text": state["document_text"]
})
risks = json.loads(risk_check)
state["risk_flags"].extend(risks.get("risks_found", []))
return state
def generate_report_node(state: LegalAnalysisState) -> LegalAnalysisState:
prompt = f"""Создай структурированный отчёт по анализу документа для юриста.
Тип документа: {state['document_type']}
Результаты проверки условий: {json.dumps(state['analysis_results'], ensure_ascii=False)}
Выявленные риски: {json.dumps(state['risk_flags'], ensure_ascii=False)}
Структура отчёта:
## Общая оценка
## Критические риски (требуют немедленного внимания)
## Отсутствующие обязательные условия
## Рекомендации по доработке
## Итог: рекомендовать к подписанию / требует доработки / отказать"""
state["final_report"] = llm.invoke(prompt).content
return state
graph = StateGraph(LegalAnalysisState)
graph.add_node("analyze", analyze_node)
graph.add_node("report", generate_report_node)
graph.add_edge("analyze", "report")
graph.add_edge("report", END)
graph.set_entry_point("analyze")
return graph.compile()
Интеграция с правовыми базами
class LegalDatabaseIntegration:
async def check_counterparty(self, inn: str) -> dict:
"""Проверяет контрагента в ЕГРЮЛ и базах рисков"""
egrul_data = await self.egrul_client.get_company(inn)
risk_score = await self.risk_service.evaluate(inn)
return {
"company_name": egrul_data.get("name"),
"status": egrul_data.get("status"), # действующее / ликвидировано
"registration_date": egrul_data.get("ogrn_date"),
"risk_score": risk_score, # 0-100, выше = рискованнее
"bankruptcy_flag": egrul_data.get("bankruptcy", False),
"tax_debt_flag": risk_score > 60
}
Кейс: юридический департамент холдинга, 200 договоров в месяц от контрагентов. До внедрения: каждый договор прочитывался юристом полностью (~45 мин на договор). После: AI-агент за 90 секунд создаёт отчёт с выявленными отклонениями, юрист читает отчёт и проверяет только флаги (~10 мин). Продуктивность: 200 договоров в месяц → 380 договоров при той же команде. Выявляемость критических рисков: +23% (AI видит паттерны, которые человек пропускает при усталости).
Сроки: базовый агент с проверкой условий: 3–4 недели; сравнение с шаблоном и интеграция с ЕГРЮЛ: 6–8 недель.







