Menu ☰
rag · · 3 min read

RAG for Romanian Legal Corpora: PDF to Cited Query

Romanian legal PDFs break every assumption a stock RAG stack brings from English wiki data. Scanned ordinances from 2003. Diacritics stripped by OCR.

CAI Technology · Last reviewed: 10/12/2026
Clean editorial photo of two diverse professionals reviewing a document in a bright office; no visible text, no third-party logos, anatomy appears natural.

RAG for Romanian Legal Corpora: PDF to Cited Query

Romanian legal PDFs break every assumption a stock RAG stack brings from English wiki data. Scanned ordinances from 2003. Diacritics stripped by OCR. Articles numbered 7¹ and 7² (“articolul 7 indice 1”) that your tokenizer collapses to one token. A query that must cite Article 11 of Law 544/2001 returns Article 1 — close enough for a demo, wrong enough for a lawyer.

The pipeline below is what we run in production for the legal workflows inside Lexnomia and the GDPR evidence tracker in AEGIS compliance.

From PDF to chunk: the ingestion layer

Three failures dominate Romanian ingestion. First, OCR on pre-2010 Monitorul Oficial scans drops diacritics on scanned lines — “statutara” and “statutară” become different retrieval neighbors. Second, PDF column order flips mid-page when the layout changes. Third, Annex tables (common in OPANAF rulings — see OPANAF 1.581/2025 on anaf.ro) carry the actual obligation and get thrown away by naive text extraction.

We use layout-aware extraction (Docling or an LLM-vision fallback), then normalize diacritics against a reference dictionary. Every chunk keeps a source_span with page number and bounding box — the only way a citation can be audited later.

chunk_id: lege_544_2001_art_11_al_1
source_doc: monitorul-oficial-663-23-10-2001.pdf
page: 3
bbox: [142, 418, 471, 502]
article_ref: "Art. 11 alin. (1)"
norm_text: "Persoanele care efectuează studii și cercetări..."
diacritics_fixed: true

Retrieval and the citation contract

Dense embeddings alone miss article numbers. The retrieval layer runs hybrid: BM25 over raw Romanian text plus a multilingual embedding (bge-m3 or an in-house finetune), reranked by a cross-encoder on top-50 candidates. Article identifiers go into a structured filter — not the vector — so a question about “art. 6 lit. f) GDPR” never retrieves “art. 6 lit. b)” (GDPR consolidated text on EUR-Lex).

Generation runs under a strict contract: every claim in the answer must point to a chunk_id present in the retrieved set. If the model emits a sentence without a span, the sentence is dropped before the user sees it. This aligns with ENISA guidance on verifiable AI outputs for the public sector (ENISA framework for AI cybersecurity) and the integrity requirements that apply once the EU AI Act high-risk obligations enter force (Regulation (EU) 2024/1689 on EUR-Lex).

flowchart LR A[PDF: Monitorul Oficial scan] --> B[Layout + OCR + diacritics fix] B --> C[Chunk with page + bbox + article_ref] C --> D{Query arrives} D --> E[BM25 + dense + cross-encoder rerank] E --> F[Answer draft with span citations] F --> G[Drop any sentence without chunk_id] classDef io fill:#f1f5f9,stroke:#94a3b8 classDef gate fill:#dcfce7,stroke:#10b981 class A,F io class G,B gate

What we do differently

The team at CAI Technology treats the citation as the primary artifact and the generated prose as a byproduct. If a lawyer cannot click a sentence and land on the exact bounding box in the source PDF within one second, the pipeline is broken — regardless of BLEU score. That inverts the usual RAG product debate about “answer quality” and simplifies everything downstream, including the eval harness.

See how the same discipline shapes our RAG pillar work on retrieval evaluation and adversarial robustness.

Read further

We start with a 30-minute conversation.

Free AI-readiness audit for companies with 50+ employees. We reply within 24 hours.