Sözleşme Analizi için NLP: OCR'den Anlamaya
Dünyanın dört bir yanındaki şirketler her yıl milyarlarca sözleşmeyi yönetiyor. Tedarik anlaşmaları, maddeleri gizlilik, hizmet şartları, iş sözleşmeleri: geleneksel olarak hukuk metinlerinden oluşan bir okyanus avukatlar ve avukat yardımcıları tarafından yüzlerce saatlik manuel inceleme gerektirir. 2026 yılında pazar küresel Hukuk Teknolojisi Talep nedeniyle 35 milyar doları aştı Yasal belge yönetiminde artan otomasyon.
Gerçek devrim yalnızca belgelerin dijitalleştirilmesinde değil, aynı zamanda onları anla. 80 sayfalık bir sözleşmenin taranmış PDF'sini yapılandırılmış verilere dönüştürün, otomatik olarak çıkartın sözleşme tarafları, yükümlülükler, son tarihler ve risk hükümleri: burası Doğal Dil İşleme (NLP) hukuki alana uygulanır.
Bu yazımızda serinin açılışını yapıyoruz. LegalTech ve yapay zeka boru hattının tamamını keşfetmek kağıt belgeyi eyleme geçirilebilir bilgiye dönüştüren şey:OCR (Optik Karakter Tanıma) al NER (Adlandırılmış Varlık Tanıma), sınıflandırması hükümler en anlamsal anlayış. Gerçek Python kodunu göreceğiz, karşılaştırın ana OCR motorları ve NLP modellerini inceleyeceğiz ve bunların yeniden tanımladıkları LegalTech platformlarını analiz edeceğiz sektör.
Bu Makalede Neler Öğreneceksiniz?
- Tam sözleşme analizi hattı: fiziksel belge → OCR → NLP → yapılandırılmış içgörüler
- OCR motorlarının karşılaştırılması: Tesseract, AWS Textract, Azure Document Intelligence, Google Document AI
- Belge ön işleme: düzen analizi, tablo çıkarma, sayfa bölümlendirme
- Sözleşmeler için Adlandırılmış Kuruluş Tanıma (NER): taraflar, tarihler, tutarlar, maddeler
- Trafo modelleri ile klozların sınıflandırılması (LegalBERT, DeBERTa)
- spaCy, HuggingFace Transformers ve Tesseract ile Python uygulamasını tamamlayın
- Real LegalTech platformları: Kira Systems, Luminance, Ironclad
- Sözleşme Yapay Zekası projeleri için değerlendirme ölçümleri ve en iyi uygulamalar
LegalTech ve AI Serisine Genel Bakış
| # | Öğe | Odak |
|---|---|---|
| 1 | Buradasınız — Sözleşme Analizi için NLP | OCR'den anlayışa |
| 2 | Yapay Zeka ile Hukuki Araştırma | Anlamsal arama ve bilgi grafiği |
| 3 | Akıllı Sözleşmeler ve Blockchain | Blockchain'de sözleşme otomasyonu |
| 4 | Yasal Belgelerin Özetlenmesi | LLM ile otomatik özetler |
| 5 | Yapay Zekalı Uyumluluk Motoru | Otomatik mevzuat uyumluluğu |
| 6 | e-Keşif ve Adli Tıp | Anlaşmazlıklar için belge analizi |
| 7 | Elektronik İmza ve Dijital Kimlik | eIDAS 2.0 ve SPID |
| 8 | GDPR ve Tasarıma Göre Gizlilik | Yapay zeka ile gizlilik uyumu |
| 9 | Yasal Yardımcı Pilot | Hukuk firmaları için yapay zeka asistanı |
| 10 | Yasal Veri Entegrasyonu | Birlikte çalışabilirlik ve standartlar |
Sözleşme Analizi Boru Hattı
Bir sözleşmenin otomatik analizi tek bir algoritma değil, tek bir algoritmadır. çok aşamalı boru hattı her bileşenin bir sonrakine güç verdiği yer. Önce genel ve temel mimariyi anlayın Kendinizi her aşamanın teknik ayrıntılarına kaptırmak için.
Boru Hattının 6 Aşaması
- Kazanma: Belgenin sisteme girişi (tarama, yükleme, e-posta, DMS API)
- Ön işleme ve OCR: Düzen analizi, çarpıklık giderme, ikilileştirme, metin çıkarma
- Yapılanma: Bölümlere, paragraflara, maddelere, tablolara ayırma
- Varlık Çıkarma (NER): Parçaların, tarihlerin, tutarların ve mevzuat referanslarının tanımlanması
- Sınıflandırma ve Analiz: Madde türü, risk düzeyi, yükümlülükler, koşullar
- Çıktı ve Entegrasyon: Yapılandırılmış JSON, kontrol paneli, uyarı, CLM/DMS ile entegrasyon
Her aşama belirli zorlukları beraberinde getirir. OCR basamaklarındaki bir hata NER'i işe yaramaz hale getiriyor daha sofistike. Yanlış segmentasyon, bir sorumluluk reddi beyanının sınıflandırılmasına neden olabilir basit bir tanım olarak. Bu nedenle boru hattının kalitesi ölçülür. uçtan uca, bileşen bileşen değil.
| Faz | Giriş | Çıkışlar | Anahtar Teknolojiler |
|---|---|---|---|
| Kazanma | PDF, TIFF, DOCX, resimler | Normalleştirilmiş dosya | Apache Tika, python-docx, PyPDF2 |
| OCR | Taranan görüntü/PDF | Ham metin + koordinatlar | Tesseract, Metin, Belge AI |
| Yapılanma | Ham metin | Bölümler, maddeler, tablolar | Düzen ayrıştırıcı, regex, kural motoru |
| NER | Yapılandırılmış metin | Açıklamalı varlıklar | spaCy, Yasal-NER, John Snow Labs |
| sınıflandırma | Yalıtılmış hükümler | Etiket + güven puanı | YasalBERT, DeBERTa, GPT-4 |
| Çıkışlar | Yapılandırılmış veriler | JSON, kontrol paneli, uyarı | REST API, web kancaları, CLM SDK |
Yasal Belgeler için OCR: Teknolojilerin Karşılaştırılması
OCR, üretim hattındaki ilk darboğazdır. Bir sözleşme yerel PDF (metin içeren) olarak gelebilir seçilebilir) veya kağıt belgenin taranması olarak. İkinci durumda OCR'nin yeniden inşa edilmesi gerekir piksellerden metin, değişken tarama kalitesini yönetme, yoğun yasal yazı tipleri, çift sütunlu düzen, tablolar ve el yazısı açıklamalar.
2025-2026'da OCR ortamına dört kurumsal platform ve bir açık kaynaklı proje hakim olacak bu önemli bir referans olmaya devam ediyor. Farklılıkları görelim.
Tesseract OCR (Açık Kaynak)
Tesseract, Google tarafından sürdürülen ve artık 5.x sürümünde ve açık kaynaklı OCR motoruyla dünyada en yaygın olanıdır. Karakter tanıma için bir LSTM ağı kullanır ve ötesinde destekler 100 dil. Gücü ve esnekliği: Herhangi bir Python hattına entegre edilebilir. lisanslama maliyetleri ve ön işleme üzerinde tam kontrol.
Ancak Tesseract'ın karmaşık yasal belgeler konusunda önemli sınırlamaları vardır. Yerel olarak işlemez tablo çıkarma düzen yapısını (üstbilgiler, altbilgi, sütunlar) tanımıyor elde etmek için önemli ön işleme (ikilileştirme, çarpıklık giderme, gürültü giderme) gerektirir. Orta kalitede taramalarda kabul edilebilir sonuçlar.
AWS Texttract
Amazon Texttract çıkarma olanağı sunarak geleneksel OCR'nin ötesine geçer. tablolar, form (anahtar/değer çiftleri) e imzalar yerel özellikler olarak. Entegrasyon AWS ekosistemi (S3, Lambda, Step Functions) ile yüksek hacimli sunucusuz işlem hatları için idealdir. Eşzamansız işleme, yüzlerce sayfalık belgeleri zaman aşımı olmadan işlemenize olanak tanır.
Azure AI Belge Zekası
Azure AI Belge Zekası (eski adıyla Form Recognizer), aşağıdakiler için önceden eğitilmiş modeller sunar: faturalar, makbuzlar ve kimlik belgelerinin yanı sıra güçlü bir düzen şablonu bu paragrafları, tabloları, seçim işaretlerini ve barkodları çıkarır. Güç ve olasılık eğitmek özel modeller alanınıza özel belgelerde temel özel düzenlere sahip sözleşmeler için.
Google Doküman Yapay Zekası
Google Doküman Yapay Zekası son derece yüksek hassasiyetli OCR'yi özel işlemcilerle birleştirir belirli belge türleri için. Belge OCR işlemcisi kesinliğe ulaşır Metin üzerinde %98, özel işlemciler belirli alanları çıkarmak üzere eğitilebilir standart sözleşmelerden Vertex AI ile entegrasyon, uçtan uca makine öğrenimi hatları oluşturmanıza olanak tanır.
Yasal Belgeler için OCR Motorlarının Karşılaştırılması
| karakteristik | Tesseract 5 | AWS Texttract | Azure Belge Zekası | Google Doküman Yapay Zekası |
|---|---|---|---|---|
| Metin doğruluğu | %92-95 | %96-98 | %97-99 | %98+ |
| Tablo çıkarma | Yerli yok | Evet (yerli) | Evet (yerli) | Evet (yerli) |
| Düzen analizi | Temel | İyi | Harika | Harika |
| Özel modeller | OCR eğitimi | Özel Sorgular | Özel Modeller | Özel İşlemciler |
| Maliyet | Ücretsiz (OSS) | 1,50$/1000 sayfa | 1,50$/1000 sayfa | 1,50$/1000 sayfa |
| Şirket içi | Si | No | Evet (konteyner) | No |
| Desteklenen diller | 100+ | ~20 | ~300 | ~200 |
| El yazısı | Sınırlı | İyi | İyi | İyi |
| Şunun için idealdir: | Prototipleme, düşük bütçe | AWS sunucusuz işlem hattı | KurumsalMicrosoft | Yüksek hassasiyet, GCP |
OCR'a ihtiyacınız OLMADIĞINDA
Birçok modern sözleşme dijital olarak oluşturulur (Word, yerel PDF). Bu durumlarda OCR e gereksiz ve potansiyel olarak zararlı: gibi kütüphanelerle yerel PDF'lerden doğrudan metin çıkarma PyMuPDF (fitz) veya pdftesisatçı ve daha hızlı, daha hassas ve hiçbir ücret ödemeden. Boru hattındaki ilk işlem her zaman olmalıdır. triyaj: olup olmadığını belirleyin belge OCR gerektiriyorsa veya metin zaten mevcutsa.
Uygulama: Python'da OCR Pipeline
Python'da hem yerel PDF'leri hem de taramaları işleyen sağlam bir OCR hattının nasıl oluşturulacağını görelim. otomatik ön işleme ve farklı motorlar arasında geri dönüş ile.
Belge Triyajı ve Ön İşleme
İlk adım, PDF'nin seçilebilir metin içerip içermediğini veya taranmış bir görüntü olup olmadığını belirlemektir. Bu karar, sonraki boru hattının tamamını yönlendirir.
import fitz # PyMuPDF
import pytesseract
from PIL import Image, ImageFilter, ImageEnhance
from pathlib import Path
from dataclasses import dataclass
from typing import Optional
import io
@dataclass(frozen=True)
class OcrResult:
"""Risultato immutabile dell'estrazione testo."""
text: str
source: str # 'native' | 'tesseract' | 'textract'
confidence: float # 0.0 - 1.0
page_count: int
tables: list # tabelle estratte
def is_native_pdf(pdf_path: str, threshold: float = 0.1) -> bool:
"""Determina se un PDF contiene testo selezionabile.
Args:
pdf_path: Percorso al file PDF
threshold: Rapporto minimo caratteri/pagina per considerarlo nativo
Returns:
True se il PDF ha testo estraibile direttamente
"""
doc = fitz.open(pdf_path)
total_chars = sum(len(page.get_text()) for page in doc)
avg_chars_per_page = total_chars / len(doc) if len(doc) > 0 else 0
doc.close()
# Un contratto tipico ha 2000-5000 caratteri per pagina
return avg_chars_per_page > 100
def extract_native_text(pdf_path: str) -> OcrResult:
"""Estrae testo da PDF nativo senza OCR."""
doc = fitz.open(pdf_path)
pages_text = []
for page in doc:
pages_text.append(page.get_text("text"))
full_text = "\n\n".join(pages_text)
page_count = len(doc)
doc.close()
return OcrResult(
text=full_text,
source="native",
confidence=0.99,
page_count=page_count,
tables=[]
)
def preprocess_image(image: Image.Image) -> Image.Image:
"""Preprocessing per migliorare la qualità OCR.
Applica: conversione grayscale, contrasto, nitidezza,
binarizzazione adattiva.
"""
# Conversione in scala di grigi
gray = image.convert("L")
# Aumento contrasto
enhancer = ImageEnhance.Contrast(gray)
enhanced = enhancer.enhance(2.0)
# Aumento nitidezza
sharpened = enhanced.filter(ImageFilter.SHARPEN)
# Binarizzazione con soglia adattiva
threshold_value = 128
binary = sharpened.point(
lambda x: 255 if x > threshold_value else 0, "1"
)
return binary
def ocr_with_tesseract(
pdf_path: str,
lang: str = "ita+eng"
) -> OcrResult:
"""OCR con Tesseract e preprocessing avanzato."""
doc = fitz.open(pdf_path)
pages_text = []
confidences = []
for page_num in range(len(doc)):
page = doc[page_num]
# Renderizza pagina come immagine ad alta risoluzione
mat = fitz.Matrix(300 / 72, 300 / 72) # 300 DPI
pix = page.get_pixmap(matrix=mat)
img_bytes = pix.tobytes("png")
image = Image.open(io.BytesIO(img_bytes))
# Preprocessing
processed = preprocess_image(image)
# OCR con dati di confidenza
ocr_data = pytesseract.image_to_data(
processed,
lang=lang,
output_type=pytesseract.Output.DICT,
config="--oem 3 --psm 6"
)
# Estrai testo e calcola confidenza media
page_text = pytesseract.image_to_string(
processed, lang=lang,
config="--oem 3 --psm 6"
)
pages_text.append(page_text)
# Confidenza media (escludi valori -1)
valid_confs = [
int(c) for c in ocr_data["conf"] if int(c) > 0
]
if valid_confs:
confidences.append(sum(valid_confs) / len(valid_confs))
doc.close()
avg_confidence = (
sum(confidences) / len(confidences) / 100
if confidences else 0.0
)
return OcrResult(
text="\n\n".join(pages_text),
source="tesseract",
confidence=avg_confidence,
page_count=len(pages_text),
tables=[]
)
def process_contract(pdf_path: str) -> OcrResult:
"""Pipeline principale: triage + estrazione."""
if is_native_pdf(pdf_path):
return extract_native_text(pdf_path)
return ocr_with_tesseract(pdf_path)
En İyi Uygulama: DPI ve Ön İşleme
Küçük yazı tiplerine ve yoğun düzenlere sahip yasal belgeler için her zaman en az DPI kullanın. 300 rasterleştirme için. Ön işleme (ikilileştirme, eğriliği düzeltme, kenar giderme) ortalama kalitede taramalarda OCR doğruluğunu %10-15 oranında artırabilir. Ancak taramalarda yüksek kaliteli agresif ön işleme kötüleşmek sonuçlar: her zaman bir cihazda test edin temsili örnek.
Yasal Metin için NLP: Özel Zorluklar
Hukuk dili sıradan bir doğal dil değildir. Bunu sağlayan özelliklere sahiptir otomatik işleme, en gelişmiş modeller için bile özellikle zordur.
Hukuk Dilinin Karmaşıklığı
- Uzun ve karmaşık cümleler: Tek bir sözleşme maddesi aşağıdakiler için uzatılabilir: Birden fazla alt öğe, gravür ve çapraz referans içeren 200-500 kelime. Trafo modelleri sınırlı bağlam penceresiyle (BERT için 512 jeton) küresel anlamını kaybedebilirler.
- Uzmanlaşmış terminoloji: "Açık fesih şartı", "cezai hüküm" gibi terimler sözleşmeye bağlı", "istisnai inadimpleti sözleşme" kullanımdan farklı kesin anlamlara sahiptir aynı kelimelerin ortak noktası.
- Kasıtlı belirsizlik: Bazı maddeler izin vermek için kasıtlı olarak belirsizdir esnek yorumlar. NLP bu belirsizliği fark etmeli ve raporlamalı, çözmemeli keyfi olarak.
- Çapraz referanslar: "5. maddenin 3. fıkrasının b) bendi uyarınca" belgeye yapılan iç ve dış referansların çözümlenmesi.
- Çoklu olumsuzluklar ve koşullar: "Bir önceki paragrafta belirtilenler dışında, partinin bunu yapması gerekmeyecek..." cümlesi tüm metin bloklarının anlamını tersine çevirir.
- Çok dillilik: Uluslararası sözleşmeler birden fazla dilde hükümler içerebilir, karmaşıklığı daha da artıran dilsel yaygınlık maddeleri ile.
Yasal Alan İçin NLP Modelleri
Genel dil modelleri (BERT, RoBERTa) hukuki metinlerde optimumun altında performansa sahiptir çünkü ön eğitimleri Wikipedia'ya, kitaplara ve genel web sayfalarına dayanıyor. Bu yüzden doğdular modeller alana özgü hukuki külliyat konusunda eğitim aldı.
| Modeli | Temel | Eğitim Derlemi | Diller | Ana Kullanım |
|---|---|---|---|---|
| Yasal-BERT | BERT-temel | 12GB yasal metinler (AB, İngiltere, ABD) | İngilizce | NER, madde sınıflandırması |
| CaseLaw-BERT | BERT-temel | Amerikan içtihat hukuku (Harvard) | İngilizce | Hukuk araştırması |
| İtalyan-Yasal-BERT | BERT-temel | BT mevzuatı ve içtihatları | İtalyan | NER İtalyan tüzel kişileri |
| YasalPro-BERT | BERT-temel | Özel yasal hükümler | İngilizce | Hükümlerin sınıflandırılması |
| DeBERTa-v3-yasal | DeBERTa-v3 | Sözleşmeler + mevzuat | İngilizce | Hukuki Soru Cevaplama |
| John Snow Laboratuvarları Yasal NLP | NLP'yi Kıvılcım | 600'den fazla hukuka özel şablon | Çok dilli | Kurumsal boru hattını tamamlayın |
CUAD (Sözleşmeyi Anlamak Atticus Veri Kümesi) gibi belirli veri kümelerinde LegalBERT ince ayarı 41 tür sözleşme maddesinin sınıflandırılmasında %83-88'lik bir F1 puanına ulaşır; Aynı görevde genel BERT'e göre %12-15 iyileşme. Temel modelin seçimi ve ince ayar verilerinin kalitesi kadar önemlidir.
Sözleşmeler için Adlandırılmış Kuruluşun Tanınması
Il Adlandırılmış Varlık Tanıma (NER) ve sistemin tanımladığı ve sınıflandırdığı aşama sözleşme metnindeki önemli varlıklar. İnsanları, yerleri tanıyan genel NER'den farklı olarak ve kuruluşlar için yasal NER'in alana özgü varlıkları çıkarması gerekir.
Önemli Tüzel Kişiler
| Varlık | Tanım | Örnek |
|---|---|---|
| PARTİ | Sözleşme tarafları | "Acme S.p.A." (Tedarikçi), "Beta S.r.l." (Müşteri) |
| TARİHLER | İlgili tarihler | İmza tarihi, yürürlük tarihi, sona erme, yenileme |
| MİKTAR | Parasal tutarlar | "Yıllık 150.000,00 Avro", "50.000 ABD Doları" |
| SÜRE | Zaman dilimleri | "36 ay", "imza tarihinden itibaren 3 yıl" |
| CLAUSE_REF | Cümlelere yapılan atıflar | "Mad. 5, paragraf 3", "Bölüm 12.1" |
| LAW_REF | Düzenleyici referanslar | "50/2016 sayılı Kanun Hükmünde Kararname", "Mad. 1341 c.c." |
| YÜKÜMLÜLÜK | Sözleşme yükümlülükleri | "Tedarikçi teslim etmeyi taahhüt eder..." |
| YARGI YETKİSİ | Yetkili mahkeme | "Milano Mahkemesi" |
| GOVERNING_LAW | Geçerli yasa | "İtalyan hukuku", "İngiltere Kanunları" |
spaCy ile NER uygulaması
spaCy, özel NER boru hatları oluşturmak için esnek bir çerçeve sunar. Nasıl oluşturulacağını görelim Belirleyici kuralları makine öğrenimiyle birleştiren, İtalyan sözleşmeleri için özel bir NER modeli.
import spacy
from spacy.tokens import Span
from spacy.language import Language
from spacy.matcher import Matcher, PhraseMatcher
from dataclasses import dataclass
from typing import Tuple
@dataclass(frozen=True)
class LegalEntity:
"""Entità legale estratta dal contratto."""
text: str
label: str
start_char: int
end_char: int
confidence: float
@Language.component("legal_entity_ruler")
def legal_entity_ruler(doc):
"""Componente spaCy per entità legali con regole."""
new_ents = list(doc.ents)
# Pattern per riferimenti normativi italiani
law_patterns = [
# D.Lgs. 50/2016, D.L. 18/2020
r"D\.(?:Lgs|L|P\.R|M)\.\s*\d+/\d{4}",
# Art. 1341 c.c., Art. 2043 c.c.
r"[Aa]rt(?:icolo|\.)\s*\d+(?:\s*(?:comma|co\.)\s*\d+)?(?:\s*c\.c\.|"
r"\s*c\.p\.c\.|c\.p\.)?",
# Legge n. 241/1990
r"[Ll]egge\s*(?:n\.\s*)?\d+/\d{4}",
]
# Pattern per importi monetari
amount_patterns = [
# EUR 150.000,00 / euro 150.000
r"(?:EUR|euro|Euro|€)\s*[\d.,]+",
# 150.000,00 euro
r"[\d.]+,\d{2}\s*(?:EUR|euro|Euro|€)",
# USD 50,000.00
r"(?:USD|GBP|CHF|\$|£)\s*[\d,]+(?:\.\d{2})?",
]
# Pattern per date italiane
date_patterns = [
# 15 marzo 2026, 1 gennaio 2025
r"\d{1,2}\s+(?:gennaio|febbraio|marzo|aprile|maggio|giugno|"
r"luglio|agosto|settembre|ottobre|novembre|dicembre)\s+\d{4}",
# 15/03/2026, 01.01.2025
r"\d{2}[/.\-]\d{2}[/.\-]\d{4}",
]
import re
for pattern in law_patterns:
for match in re.finditer(pattern, doc.text):
span = doc.char_span(
match.start(), match.end(), label="LAW_REF"
)
if span and not any(
ent.start <= span.start < ent.end
for ent in new_ents
):
new_ents.append(span)
for pattern in amount_patterns:
for match in re.finditer(pattern, doc.text):
span = doc.char_span(
match.start(), match.end(), label="AMOUNT"
)
if span and not any(
ent.start <= span.start < ent.end
for ent in new_ents
):
new_ents.append(span)
for pattern in date_patterns:
for match in re.finditer(pattern, doc.text):
span = doc.char_span(
match.start(), match.end(), label="DATE"
)
if span and not any(
ent.start <= span.start < ent.end
for ent in new_ents
):
new_ents.append(span)
doc.ents = sorted(new_ents, key=lambda e: e.start)
return doc
def create_legal_nlp() -> spacy.Language:
"""Crea pipeline spaCy per NER legale."""
# Carica modello italiano base
nlp = spacy.load("it_core_news_lg")
# Aggiungi componente custom dopo il NER standard
nlp.add_pipe("legal_entity_ruler", after="ner")
return nlp
def extract_entities(
text: str,
nlp: spacy.Language
) -> list:
"""Estrai entità legali dal testo contrattuale."""
doc = nlp(text)
return [
LegalEntity(
text=ent.text,
label=ent.label_,
start_char=ent.start_char,
end_char=ent.end_char,
confidence=0.85 # spaCy rule-based = high confidence
)
for ent in doc.ents
if ent.label_ in (
"PER", "ORG", "LOC", "DATE",
"AMOUNT", "LAW_REF", "PARTY"
)
]
# Esempio di utilizzo
nlp = create_legal_nlp()
sample = """
Il presente contratto e stipulato tra Acme S.p.A., con sede
in Via Roma 15, Milano (di seguito "Fornitore") e Beta S.r.l.,
con sede in Via Napoli 42, Roma (di seguito "Cliente").
Il corrispettivo annuo e pari a EUR 150.000,00 ai sensi
dell'Art. 1655 c.c. La durata e di 36 mesi a decorrere
dal 1 marzo 2026.
"""
entities = extract_entities(sample, nlp)
for entity in entities:
print(f"{entity.label:<12} {entity.text}")
Beklenen Çıktı
ORG Acme S.p.A.
LOC Via Roma 15, Milano
ORG Beta S.r.l.
LOC Via Napoli 42, Roma
AMOUNT EUR 150.000,00
LAW_REF Art. 1655 c.c.
DATE 1 marzo 2026
Transformatörlü Klozların Sınıflandırılması
Maddelerin sınıflandırılması otomatik sözleşme analizinin kalbidir. Her madde bir kategoriye atanmıştır (sorumluluk, gizlilik, fesih, cezalar vb.) e isteğe bağlı olarak risk düzeyi açısından değerlendirilir. Bu işlem geleneksel olarak saatler sürer yasal iş: eğitimli bir Transformer modeli bunu saniyeler içinde yapar.
CUAD Veri Kümesi
Il Sözleşme Anlayışı Atticus Veri Kümesi (CUAD) ve referans kriteri sözleşme sınıflandırması. Onlarca avukatın katkılarıyla The Atticus Project tarafından oluşturuldu. daha fazlasını içerir 13.000 ek açıklama 510 gerçek iş sözleşmesine ilişkin Birleşme ve satın alma işlemleri ve durum tespiti ile ilgili 41 tür madde.
41 CUAD Kategorisi (Seçim)
- Anlaşma Tarihi
- Partiler
- Geçerli Hukuk
- Kolaylık Nedeniyle Fesih
- Atama Karşıtı
- Rekabet Yasağı
- Talep Dışı
- Ayrıcalıklılık
- Tazminat
- Sorumluluğun Sınırlandırılması
- IP Sahipliği Ataması
- Lisans Verilmesi
- Gizlilik Anlaşması
- Gelir/Kar Paylaşımı
- Fiyat Kısıtlamaları
- Asgari Taahhüt
- Hacim Kısıtlaması
- Sigorta
- Denetim Hakları
- Kontrol Değişikliği
Madde Sınıflandırması için LegalBERT'te İnce Ayarlama
LegalBERT ve CUAD veri kümesini kullanarak bir cümle sınıflandırıcısının nasıl eğitileceğini görelim. Süreç, önceden eğitilmiş modelin açıklamalı cümle örnekleri üzerinde ince ayarını yapmayı içerir sözleşmeye bağlı.
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
TrainingArguments,
Trainer,
)
from datasets import load_dataset, Dataset
from sklearn.metrics import f1_score, precision_score, recall_score
import numpy as np
from dataclasses import dataclass
from typing import Dict
@dataclass(frozen=True)
class ClauseLabel:
"""Label per la classificazione delle clausole."""
id: int
name: str
risk_level: str # 'low' | 'medium' | 'high' | 'critical'
# Definizione categorie di clausole
CLAUSE_LABELS = {
0: ClauseLabel(0, "termination", "high"),
1: ClauseLabel(1, "indemnification", "critical"),
2: ClauseLabel(2, "limitation_of_liability", "critical"),
3: ClauseLabel(3, "confidentiality", "medium"),
4: ClauseLabel(4, "non_compete", "high"),
5: ClauseLabel(5, "governing_law", "medium"),
6: ClauseLabel(6, "intellectual_property", "high"),
7: ClauseLabel(7, "payment_terms", "medium"),
8: ClauseLabel(8, "warranty", "high"),
9: ClauseLabel(9, "force_majeure", "medium"),
10: ClauseLabel(10, "assignment", "medium"),
11: ClauseLabel(11, "dispute_resolution", "medium"),
12: ClauseLabel(12, "general_provision", "low"),
}
MODEL_NAME = "nlpaueb/legal-bert-base-uncased"
def load_and_prepare_data(
dataset_name: str = "theatticusproject/cuad-qa"
) -> tuple:
"""Carica e prepara il dataset CUAD per classificazione."""
dataset = load_dataset(dataset_name)
# Trasforma da QA a classificazione
texts = []
labels = []
for example in dataset["train"]:
context = example["context"]
# Usa la categoria della domanda come label
category = example.get("category", "general_provision")
label_id = next(
(k for k, v in CLAUSE_LABELS.items()
if v.name == category),
12 # default: general_provision
)
texts.append(context[:512]) # Tronca a 512 token
labels.append(label_id)
return texts, labels
def compute_metrics(eval_pred) -> Dict[str, float]:
"""Calcola metriche di valutazione."""
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1)
return {
"f1_macro": f1_score(
labels, predictions, average="macro"
),
"f1_weighted": f1_score(
labels, predictions, average="weighted"
),
"precision": precision_score(
labels, predictions, average="weighted"
),
"recall": recall_score(
labels, predictions, average="weighted"
),
}
def train_clause_classifier():
"""Addestra il classificatore di clausole."""
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_NAME,
num_labels=len(CLAUSE_LABELS),
problem_type="single_label_classification",
)
texts, labels = load_and_prepare_data()
# Tokenizzazione
encodings = tokenizer(
texts,
truncation=True,
padding="max_length",
max_length=512,
return_tensors="pt",
)
# Crea dataset HuggingFace
dataset = Dataset.from_dict({
"input_ids": encodings["input_ids"],
"attention_mask": encodings["attention_mask"],
"labels": labels,
})
# Split train/eval
split = dataset.train_test_split(test_size=0.2, seed=42)
training_args = TrainingArguments(
output_dir="./legal-bert-clauses",
num_train_epochs=5,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
warmup_steps=500,
weight_decay=0.01,
logging_dir="./logs",
logging_steps=100,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1_macro",
learning_rate=2e-5,
fp16=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=split["train"],
eval_dataset=split["test"],
compute_metrics=compute_metrics,
)
trainer.train()
return trainer
# Inferenza su nuove clausole
def classify_clause(
text: str,
model,
tokenizer
) -> tuple:
"""Classifica una singola clausola contrattuale.
Returns:
Tuple di (label, confidence, risk_level)
"""
inputs = tokenizer(
text,
truncation=True,
padding="max_length",
max_length=512,
return_tensors="pt",
)
outputs = model(**inputs)
probs = outputs.logits.softmax(dim=-1)
predicted_id = probs.argmax().item()
confidence = probs.max().item()
clause_label = CLAUSE_LABELS[predicted_id]
return clause_label.name, confidence, clause_label.risk_level
CUAD'da İnce Ayarın Sınırları
CUAD veri seti ticari sözleşmelere odaklanmıştır. ingilizce dili ve bağlamda Amerikan Birleşme ve Satın Almaları. İtalyan, Avrupa veya diğer yargı yetkisine sahip sözleşmeler için bu gereklidir belirli veri kümelerini oluşturun veya uyarlayın. Etkili bir yaklaşım, iki aşamalı transfer öğrenimi: Genel sözleşme yapısını öğrenmek için CUAD'da ince ayar yapın, ardından bir sözleşmede daha fazla ince ayar yapın. özel alan adınıza ait küçük veri kümesi (200-500 örnek).
Yükümlülük Tespiti ve Anlamsal Analiz
Maddeleri sınıflandırmanın yanı sıra, bir Sözleşme Yapay Zeka sistemi, maddeleri tanımlamalıdır. yükümlülükler sözleşmeye bağlı: Kimin neyi, ne zaman yapması gerektiği ve sonuçlarının ne olacağı uyumsuzluktan. Bu görev olarak bilinir Deontic Modalite Tespiti içinde Yasal NLP literatürü.
Üç Deontik Modalite
- Yükümlülük (ZORUNLU/OLACAKTIR): "Tedarikçi mutlak Malları 30 gün içinde teslim edin"
- İzin (MAY/CAN): "Müşteri olabilmek projede değişiklik talep et"
- Yasak (OLMAMALI/OLMAMALIDIR): "Taraflar yapamazlar sözleşmeyi üçüncü kişilere devretmek"
Sıfır Atış Sınıflandırması ile Uygulama
Yükümlülük takibi için etkili bir yaklaşım sıfır atış sınıflandırması özel açıklamalı eğitim verileri gerektirmeyen DeBERTa gibi modellerle.
from transformers import pipeline
from dataclasses import dataclass
from typing import List
@dataclass(frozen=True)
class Obligation:
"""Obbligo contrattuale rilevato."""
text: str
modality: str # 'obligation' | 'permission' | 'prohibition'
confidence: float
subject: str # chi ha l'obbligo
action: str # cosa deve fare
deadline: str # entro quando (se specificato)
def create_obligation_detector():
"""Crea il classificatore zero-shot per obblighi."""
return pipeline(
"zero-shot-classification",
model="MoritzLaurer/DeBERTa-v3-large-mnli-fever-"
"anli-ling-wanli",
device=0, # GPU, usa -1 per CPU
)
def detect_obligations(
clauses: List[str],
classifier
) -> List[Obligation]:
"""Rileva obblighi in una lista di clausole."""
candidate_labels = [
"obligation or duty",
"permission or right",
"prohibition or restriction",
"definition or description",
"condition or prerequisite",
]
results = []
for clause in clauses:
output = classifier(
clause,
candidate_labels,
multi_label=False,
)
top_label = output["labels"][0]
top_score = output["scores"][0]
# Filtra solo obblighi, permessi e divieti
modality_map = {
"obligation or duty": "obligation",
"permission or right": "permission",
"prohibition or restriction": "prohibition",
}
if top_label in modality_map and top_score > 0.6:
results.append(Obligation(
text=clause,
modality=modality_map[top_label],
confidence=top_score,
subject="", # Da estrarre con NER
action="", # Da estrarre con SRL
deadline="", # Da estrarre con NER
))
return results
# Esempio
classifier = create_obligation_detector()
clauses = [
"Il Fornitore deve consegnare i beni entro 30 giorni "
"dalla data dell'ordine.",
"Il Cliente può richiedere modifiche al progetto entro "
"la fase di design.",
"Le parti non possono cedere il presente contratto a "
"terzi senza previo consenso scritto.",
"Per 'Servizi' si intendono le attivita descritte "
"nell'Allegato A.",
]
obligations = detect_obligations(clauses, classifier)
for obl in obligations:
print(f"[{obl.modality.upper()}] "
f"({obl.confidence:.2f}) {obl.text[:60]}...")
Cümleler Arasındaki Anlamsal Benzerlik
Bir diğer önemli uygulama ise cümleler arasındaki anlamsal karşılaştırmadır. Bir şirket yeni bir belge aldığında sözleşme şunu bilmek istiyor: "Bu sorumluluk reddi beyanı bizimkine benzer veya bizimkilerden farklı standart madde?" Orada anlamsal benzerlik yerleştirmelere dayalı olarak bu karşılaştırmaya olanak sağlar.
from sentence_transformers import SentenceTransformer, util
from dataclasses import dataclass
from typing import List, Tuple
@dataclass(frozen=True)
class ClauseComparison:
"""Risultato del confronto tra clausole."""
clause_a: str
clause_b: str
similarity: float
is_substantially_similar: bool
deviation_areas: List[str]
def compare_clauses(
new_clause: str,
standard_clauses: List[str],
threshold: float = 0.85,
) -> List[ClauseComparison]:
"""Confronta una clausola con le clausole standard.
Args:
new_clause: Clausola dal contratto in revisione
standard_clauses: Clausole standard dell'azienda
threshold: Soglia di similarità (0-1)
Returns:
Lista di confronti ordinati per similarità
"""
model = SentenceTransformer(
"sentence-transformers/all-mpnet-base-v2"
)
new_embedding = model.encode(
new_clause, convert_to_tensor=True
)
std_embeddings = model.encode(
standard_clauses, convert_to_tensor=True
)
similarities = util.cos_sim(new_embedding, std_embeddings)
comparisons = []
for idx, sim_score in enumerate(similarities[0]):
score = sim_score.item()
comparisons.append(ClauseComparison(
clause_a=new_clause[:100],
clause_b=standard_clauses[idx][:100],
similarity=score,
is_substantially_similar=score >= threshold,
deviation_areas=(
[] if score >= threshold
else ["Possibile deviazione rilevata"]
),
))
# Ordina per similarità decrescente
return sorted(
comparisons, key=lambda c: c.similarity, reverse=True
)
# Esempio: confronto clausola di riservatezza
new_clause = (
"Le informazioni riservate non potranno essere divulgate "
"a terzi per un periodo di 5 anni dalla data di "
"risoluzione del contratto."
)
standard_clauses = [
"Le informazioni confidenziali non potranno essere "
"comunicate a terzi per 3 anni dalla cessazione del "
"rapporto contrattuale.",
"Il Fornitore si impegna a consegnare i prodotti entro "
"30 giorni lavorativi dall'ordine.",
"Le informazioni riservate saranno protette per un "
"periodo di 10 anni dalla firma del presente accordo.",
]
results = compare_clauses(new_clause, standard_clauses)
for r in results:
status = "SIMILE" if r.is_substantially_similar else "DIVERSA"
print(f"[{status}] Similarità: {r.similarity:.3f}")
print(f" Standard: {r.clause_b}...")
print()
Uçtan Uca İşlem Hattı: OCR'den İçgörüye
Artık tüm bileşenleri bir sözleşme PDF'si alan ve çıktı veren eksiksiz bir işlem hattına entegre ediyoruz Varlıkları, sınıflandırılmış maddeleri ve tanımlanmış yükümlülükleri içeren yapılandırılmış bir rapor.
from dataclasses import dataclass, field
from typing import List, Optional
from datetime import datetime
import json
@dataclass(frozen=True)
class ContractAnalysis:
"""Risultato completo dell'analisi contrattuale."""
file_name: str
analyzed_at: str
page_count: int
ocr_source: str
ocr_confidence: float
parties: List[str]
dates: List[dict]
amounts: List[dict]
law_references: List[str]
clauses: List[dict]
obligations: List[dict]
risk_summary: dict
def analyze_contract(pdf_path: str) -> ContractAnalysis:
"""Pipeline completa di analisi contrattuale.
Fasi:
1. Triage e OCR
2. Segmentazione in clausole
3. NER per entità legali
4. Classificazione clausole
5. Rilevamento obblighi
6. Calcolo risk summary
"""
# Fase 1: OCR
ocr_result = process_contract(pdf_path)
# Fase 2: Segmentazione
clauses_text = segment_into_clauses(ocr_result.text)
# Fase 3: NER
nlp = create_legal_nlp()
all_entities = extract_entities(ocr_result.text, nlp)
parties = [
e.text for e in all_entities
if e.label in ("ORG", "PER", "PARTY")
]
dates = [
{"text": e.text, "position": e.start_char}
for e in all_entities if e.label == "DATE"
]
amounts = [
{"text": e.text, "position": e.start_char}
for e in all_entities if e.label == "AMOUNT"
]
law_refs = [
e.text for e in all_entities
if e.label == "LAW_REF"
]
# Fase 4: Classificazione clausole
classified = []
for clause in clauses_text:
label, conf, risk = classify_clause(
clause, model, tokenizer
)
classified.append({
"text": clause[:200],
"type": label,
"confidence": round(conf, 3),
"risk_level": risk,
})
# Fase 5: Rilevamento obblighi
obligation_detector = create_obligation_detector()
detected_obligations = detect_obligations(
clauses_text, obligation_detector
)
obligations_data = [
{
"text": o.text[:200],
"modality": o.modality,
"confidence": round(o.confidence, 3),
}
for o in detected_obligations
]
# Fase 6: Risk summary
risk_counts = {"low": 0, "medium": 0, "high": 0, "critical": 0}
for c in classified:
risk_counts[c["risk_level"]] = (
risk_counts.get(c["risk_level"], 0) + 1
)
return ContractAnalysis(
file_name=pdf_path,
analyzed_at=datetime.now().isoformat(),
page_count=ocr_result.page_count,
ocr_source=ocr_result.source,
ocr_confidence=round(ocr_result.confidence, 3),
parties=list(set(parties)),
dates=dates,
amounts=amounts,
law_references=list(set(law_refs)),
clauses=classified,
obligations=obligations_data,
risk_summary=risk_counts,
)
def segment_into_clauses(text: str) -> List[str]:
"""Segmenta il testo in clausole individuali.
Usa pattern tipici dei contratti italiani:
- Numerazione (1., 1.1, Art. 1, Articolo 1)
- Titoli in maiuscolo
- Separatori di sezione
"""
import re
# Pattern per inizio clausola
clause_pattern = re.compile(
r"(?:^|\n)"
r"(?:"
r"(?:Art(?:icolo)?\.?\s*\d+)" # Art. 1, Articolo 1
r"|(?:\d+\.\d*\s+[A-Z])" # 1. Titolo, 1.1 Sotto
r"|(?:[A-Z][A-Z\s]{10,})" # TITOLO IN MAIUSCOLO
r")"
)
splits = clause_pattern.split(text)
# Filtra clausole troppo corte (< 50 caratteri)
return [
clause.strip()
for clause in splits
if len(clause.strip()) > 50
]
# Esecuzione
result = analyze_contract("contratto_fornitura.pdf")
print(json.dumps(
{
"parties": result.parties,
"risk_summary": result.risk_summary,
"clause_count": len(result.clauses),
"obligation_count": len(result.obligations),
},
indent=2, ensure_ascii=False
))
Sözleşme Yapay Zekası için LegalTech platformları
2026 LegalTech pazarında çeşitli platformlar yapay zeka tabanlı sözleşme analizi çözümleri sunuyor. Sektörde finansman sağlandı 2025'te 4,3 milyar dolar, bir artış 2024 yılına göre %54 oranında artış gösterdi. Ana platformlara ve teknolojik yaklaşımlarına bakalım.
| platformu | Uzmanlık | Yapay zeka teknolojisi | Tipik Kullanıcılar | Gösterge fiyatı |
|---|---|---|---|---|
| Kira Sistemleri (Edebi) | Birleşme ve Satın Alma Durum Tespiti | Hibrit ML + Üretken Yapay Zeka | En iyi 100 hukuk firmasının 70+'i | Kurumsal (özel) |
| parlaklık | Anormallik tespiti, uyumluluk | Tescilli Yasal Düzeyde Yapay Zeka | Hukuk firmaları, kurumsal | Aylık 500 |







