Spaces:
Running
Running
File size: 7,854 Bytes
a992ecb 3bd9d04 a992ecb 3bd9d04 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb 3bd9d04 a992ecb 3bd9d04 a992ecb c63f734 a992ecb c63f734 a992ecb c63f734 a992ecb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | ---
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
|