lmaf / README.md
Lexai
docs: rewrite README to match actual architecture and codebase (#9)
c63f734 unverified
---
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