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 = {
"contract_supply": [
"предмет договору", "ціна товару", "порядок оплати",
"час поставки", "якість товару", "відповідальність сторін",
"порядок вирішення спорів", "час дії договору"
],
"employment_contract": [
"місце роботи", "трудова функція", "дата початку роботи",
"умови оплати праці", "режим робочого часу",
"гарантії та компенсації", "умови праці на робочому місці"
],
"lease": [
"об'єкт оренди", "орендна плата", "час оренди",
"права та обов'язки орендатора", "права та обов'язки орендодавця",
"порядок повернення майна"
]
}
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 тижнів.







