--- title: LMAF emoji: ⚖️ colorFrom: blue colorTo: indigo sdk: gradio sdk_version: 5.31.0 app_file: app.py pinned: true license: apache-2.0 tags: - legal-nlp - multi-agent - ukraine - court-decisions - legal-consultation --- # LMAF -- Legal Multi-Agent Framework Nine specialised LLM agents analyse Ukrainian legal questions, search 100M+ court decisions in the [EDRSR](https://reyestr.court.gov.ua/) via [SecondLayer](https://legal.org.ua), and produce structured legal consultations with citations to legislation and case law. **[Live demo](https://agents.legal.org.ua)**  |  **[HuggingFace Space](https://huggingface.co/spaces/overthelex/lmaf)**  |  **[SecondLayer Platform](https://legal.org.ua)** ## How It Works A client question goes through four phases. Every agent starts from a fresh context (no conversation history) -- all state lives in a structured `ConsultationState` object, and every iteration is git-committed for reproducibility. ``` Phase 1 Phase 2 Phase 3 Phase 4 RESEARCH LOOP (up to 15 iterations) ┌─────────────────────────────────────┐ Question ─> Surveyor ─> Planner ─> Orchestrator ─────────────┐ │ ─> Formatter ─> Consultation ^ │ │ │ │ │ Researcher Analyst │ │ │ │ │ │ │ │ └──> Reviewer ────────────┘ │ │ │ │ │ Critic (every 3 iter.) │ │ │ │ │ └────────┘ Adjudicator ────────────┘ └─────────────────────────────────────┘ ``` An interactive D3.js version of this diagram is available on the [Architecture tab](https://agents.legal.org.ua) of the live demo. ## Agents | # | Agent | When | What it does | |---|-------|------|-------------| | 1 | **Surveyor** | Once, at start | Maps the legal landscape: jurisdiction, applicable legislation, Supreme Court positions, risks | | 2 | **Planner** | Once + on strategy critique | Produces and revises the research strategy and key legal questions | | 3 | **Orchestrator** | Every iteration | Reads state, formulates hypotheses, dispatches tasks to Researcher or Analyst | | 4 | **Researcher** | On dispatch | Searches case law, legislation, and doctrine via SecondLayer API (100M+ court decisions) | | 5 | **Analyst** | On dispatch | Computes deadlines, penalties (Art. 549-552 CC), 3% annual (Art. 625 CC), inflation losses | | 6 | **Reviewer** | After each research/analysis | Adversarial verification: checks citations exist, logic holds, evidence is current | | 7 | **Critic** | Every 3 iterations | Senior legal advisor audit: strategy gaps, coherence, missing counterarguments | | 8 | **Adjudicator** | On hypothesis conflict | Resolves disagreements between agents; can demote an established hypothesis back to working | | 9 | **Formatter** | Once, after loop | Produces the final structured consultation with legislation references and case law citations | ## ConsultationState All agents read and mutate a single state object: | Field | Type | Description | |-------|------|-------------| | `client_question` | str | Original question | | `jurisdiction` | str | civil, commercial, administrative, criminal | | `survey_summary` | str | Legal landscape from Surveyor | | `strategy` | LegalStrategy | Research plan from Planner | | `hypotheses` | LegalHypothesis[] | Working/established/refuted legal positions | | `evidence` | LegalEvidence[] | Case law, legislation, doctrine, computations | | `questions` | ResearchQuestion[] | Open/resolved research questions | | `critiques` | Critique[] | Active/resolved strategy and reasoning critiques | | `answer` | str | Final formatted consultation | ## Critique Routing When the Critic fires (every `critic_every_n` iterations), critiques are routed: - **strategy** critique --> Planner (revise research strategy) - **completeness** critique --> Orchestrator (generate new research questions) - **hypothesis** critique --> Adjudicator (resolve conflict, may demote hypothesis) ## Project Structure ``` secondlayer-agents/ ├── app.py # Gradio chat interface (prod + HF Space) ├── architecture.html # D3.js interactive architecture diagram ├── src/lmaf/ │ ├── engine.py # Main 4-phase pipeline loop (LMAF class) │ ├── agents/ # 9 agent implementations (BaseAgent subclasses) │ ├── state/ # ConsultationState, LoopState │ ├── core/ # Config, WorkspaceManager (git-versioned) │ ├── providers/ # LLM provider (AWS Bedrock) │ ├── tools/ # SecondLayer API bridge (HTTP client) │ ├── control/ # Loop control logic │ ├── verification/ # Evidence verification utilities │ └── rendering/ # State rendering for agent prompts ├── problems/ # Example legal problems (YAML) ├── tests/ # pytest suite (state, config, app) └── .github/workflows/ # CI/CD: test --> deploy prod + sync HF ``` ## Quick Start ```bash pip install -e . # AWS Bedrock (required) export AWS_REGION=eu-central-1 export AWS_ACCESS_KEY_ID=... export AWS_SECRET_ACCESS_KEY=... # SecondLayer API (for case law and legislation search) export SECONDLAYER_API_KEY=... # Run a consultation lmaf "Чи може продавець стягнути пеню за прострочення оплати товару?" # Run from a problem file lmaf problems/consumer_penalty.yaml ``` ## Example Problems | Problem | Domain | Question | |---------|--------|----------| | `consumer_penalty.yaml` | Civil | Penalty + 3% annual + inflation for late payment of 150K UAH goods | | `labor_dismissal.yaml` | Labor | Challenging dismissal under Art. 40(1) during martial law | | `property_dispute.yaml` | Family/Property | Property rights in an unregistered civil partnership (8 years) | ## CI/CD Every push to `main` triggers: 1. **Test** -- `pytest` on ubuntu-latest (36 tests: state, config, app) 2. **Deploy to prod** -- SSH to prod, rebuild Docker container, health check 3. **Sync to HuggingFace** -- force-push to `overthelex/lmaf` Space ## Data Sources | Source | What | Scale | |--------|------|-------| | [EDRSR](https://reyestr.court.gov.ua/) | Ukrainian court decisions | 100M+ documents | | [Verkhovna Rada](https://zakon.rada.gov.ua/) | Ukrainian legislation | Full corpus | | [ua-case-outcome-6m](https://huggingface.co/datasets/overthelex/ua-case-outcome-6m) | Court decisions dataset | 6.7M decisions | | [ukrainian-court-decisions](https://huggingface.co/datasets/overthelex/ukrainian-court-decisions) | Balanced benchmark | 428K decisions | | [edrsr-citation-graph-16m](https://huggingface.co/datasets/overthelex/edrsr-citation-graph-16m) | Citation graph | 16M edges | ## Related Papers - [Temporal Decay of Co-Citation Predictability in Legal Statute Retrieval](https://arxiv.org/abs/2605.17639) - [A Citation Graph from 100 Million Court Decisions](https://arxiv.org/abs/2605.15362) - [Tokenizer Fertility and Zero-Shot Performance on Ukrainian Legal Text](https://arxiv.org/abs/2605.14890) ## License Apache-2.0