This project is an end-to-end agentic NLP system for legal precedent research. Given a case fact pattern or query, the system retrieves relevant US Supreme Court precedents, ranks them by similarity, and explains why each case is relevant using paragraph-level citations.
The system focuses on retrieval, explainability, and verification—not legal advice or outcome prediction. It demonstrates modern approaches to building production-grade AI systems with safety mechanisms against hallucinations.
🎯 Built as a portfolio project showcasing agentic workflows, hybrid retrieval, LLM orchestration, and full-stack development.
Legal professionals spend significant time searching for relevant precedents:
- Keyword-based search often misses cases with similar fact patterns but different wording
- LLM-only approaches are unreliable due to hallucinations and missing citations
- No explainability in why certain cases are relevant
This project explores how LLMs, semantic retrieval, and agentic workflows can be combined safely for professional legal research.
✅ Semantic Vector Search
- Domain-specific embeddings via self-hosted Inception microservice (
freelawproject/modernbert-embed-base_finetune_512, 768-dim, fine-tuned on legal text) - HNSW approximate nearest-neighbor index (pgvector) for sub-10ms ANN queries
- Two retrieval modes: raw paragraph similarity or distinct-case results
✅ RRF Case Aggregation
- Reciprocal Rank Fusion scores cases by their aggregate paragraph relevance
- Cases with many relevant paragraphs outrank cases with one coincidentally similar paragraph
- Solves the core problem of paragraph-level search for case-level queries
🔜 Hybrid BM25 + Vector Search (planned — see Roadmap)
- Combines exact legal term matching (BM25 via PostgreSQL
tsvector) with semantic search - Merged via RRF:
1/(60+bm25_rank) + 1/(60+vector_rank) - Critical for statute citations, doctrine names, and case name lookups
✅ FastAPI Backend with Full CRUD
- Async psycopg3 connection pool; complete CRUD for cases, opinions, paragraphs
POST /api/v1/search— semantic search with configurabletop_k,distinct_cases,scan_multiplier
✅ 5-Agent Workflow (architecture designed, implementation planned)
- Ingestion Agent: Fetches and stores court opinions
- Retriever Agent: Hybrid search across 5,000 SCOTUS cases
- Reranker Agent: LLM-powered relevance scoring
- Explanation Agent: Generates detailed relevance explanations
- Verifier Agent: Validates all citations to prevent hallucinations
✅ Paragraph-Level Citations
- Every claim is backed by specific paragraph references with
text_with_citationsmarkers - Verification status displayed for transparency
┌─────────────────────────────────────────────────────────────┐
│ React/Next.js UI (TBD) │
└────────────────────────┬────────────────────────────────────┘
│ HTTP/REST
┌────────────────────────▼────────────────────────────────────┐
│ FastAPI Backend :8000 (done) │
│ POST /api/v1/search GET|POST|PUT|DELETE /api/v1/cases │
│ GET|POST|PUT|DELETE /api/v1/opinions │
│ GET|POST|PUT|DELETE /api/v1/paragraphs│
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Agent Orchestrator (TBD) │ │
│ └─────┬───────┬───────┬───────┬────────┬─────────────┘ │
│ Ingest│ Retrie│ Rerank│ Explai│ Verify │ (all TBD) │
└────────┼───────┼───────┼───────┼────────┼───────────────────┘
│ │ │ │ │
┌────▼───────▼──┐ ┌─▼──────▼──┐ ┌──▼────────────────┐
│ PostgreSQL │ │ pgvector │ │ Inception :8005 │
│ pg16-trixie │ │ HNSW ANN │ │ modernbert-embed │
│ 5,000 cases │ │ 768-dim │ │ 768-dim, legal │
│ 5,043 opinions│ │ cosine │ │ GPU-capable │
└───────────────┘ └───────────┘ └───────────────────┘
LLM APIs (planned)
OpenAI GPT-4o-mini (reranker)
Anthropic Claude (explanation)
- User Query →
POST /api/v1/searchwith optionaldistinct_cases,top_k - Embed query → Inception
/api/v1/embed/text; mean-pool if query > 512 tokens - ANN scan → pgvector HNSW cosine search, top
top_k × scan_multipliercandidates - RRF aggregation (distinct_cases mode) → Score each case by
SUM(1/(60+rank))across all its matching paragraphs; return top-k distinct cases - Results → Paragraph text + case/opinion metadata + similarity scores
- User Query → System receives query + optional fact pattern
- Retriever Agent → Hybrid search (BM25 + Vector + RRF) retrieves top cases
- Reranker Agent → GPT-4o-mini scores and selects top 10 cases
- Explanation Agent → Claude generates detailed explanations with paragraph citations (parallel)
- Verifier Agent → Validates all quoted text against source paragraphs
- Results → Verified precedents with confidence scores returned to user
- Python 3.12 with
uvfor fast dependency management - FastAPI — high-performance async REST API (CRUD + semantic search)
- PostgreSQL 16 with pgvector extension — vector storage, HNSW ANN index
- psycopg3 (
psycopg[binary,pool]) — async connection pool, direct SQL (no ORM) - Pydantic v2 — request/response schema validation
- structlog — JSON structured logging (planned)
- Inception microservice (self-hosted, port 8005) — wraps
freelawproject/modernbert-embed-base_finetune_512- 768-dimensional embeddings fine-tuned on legal text from the Free Law Project
- GPU-capable via NVIDIA CUDA; CPU fallback for development
- Mean-pools multi-chunk responses for queries > 512 tokens
- pgvector HNSW index — approximate nearest-neighbor search (cosine, m=16, ef_construction=64)
- Reciprocal Rank Fusion — case-level score aggregation over paragraph rankings
- OpenAI GPT-4o-mini — fast reranking agent
- Anthropic Claude 3.5 Sonnet — high-quality explanations and verification
- PostgreSQL tsvector + GIN index — BM25 full-text search for hybrid retrieval (next milestone)
- Next.js 14 — React framework with App Router
- TypeScript — type-safe frontend code
- Tailwind CSS — utility-first styling
- Docker + Docker Compose — containerized deployment
- PostgreSQL container with pgvector extension
- Inception embedding container — separate compose, CUDA-capable
host.docker.internalbridges backend → Inception across separate Docker composes
- US Supreme Court opinions via CourtListener API (Free Law Project)
- Public case text and metadata only
- No private or proprietary data
- Current scope: 5,000 SCOTUS cases (v1); expanding to full corpus
- Docker & Docker Compose
- OpenAI API key
- Anthropic API key (optional, for explanations)
- CourtListener API key (for data ingestion)
- Clone the repository
git clone https://github.com/your-username/litigation-precedent-assistant.git
cd litigation-precedent-assistant- Set up environment variables
cp .env.example .env
# Edit .env with your API keys- Start the services
docker-compose up --build- Access the application
- Web UI: http://localhost:3000
- API Documentation: http://localhost:8000/docs
- Health Check: http://localhost:8000/api/health
- Install dependencies
# Install uv (fast Python package installer)
pip install uv
# Install project dependencies
uv pip install -e .- Set up PostgreSQL with pgvector
# Using Docker
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=precedent_finder \
-p 5432:5432 \
pgvector/pgvector:pg16
# Initialize schema
psql -h localhost -U postgres -d precedent_finder -f scripts/db/init_schema.sql- Ingest data
# Fetch Supreme Court cases
python scripts/ingest/fetch_scotus_cases.py
# Generate embeddings
python scripts/embeddings/generate_embeddings.py
# Load to database
python scripts/embeddings/load_to_db.py- Run the backend
uvicorn src.backend.api.main:app --reload --port 8000- Run the frontend
cd src/frontend
npm install
npm run dev- Navigate to http://localhost:3000
- Enter your legal query in the search box
- Optionally add context (your fact pattern)
- Click "Search" to retrieve relevant precedents
- View detailed explanations with paragraph-level citations
- Check verification badges (✓ = verified, ⚠ = unverified)
Search for precedents:
curl -X POST http://localhost:8000/api/v1/search \
-H "Content-Type: application/json" \
-d '{
"query": "What are the precedents for right to privacy in medical decisions?",
"context": "Plaintiff is a patient seeking abortion access in Texas.",
"top_k": 5
}'Get case details:
curl http://localhost:8000/api/v1/cases/123API Documentation:
- Interactive docs: http://localhost:8000/docs
- OpenAPI spec: http://localhost:8000/openapi.json
The system is evaluated as a retrieval and explanation tool, not a legal decision system.
| Metric | Target | Description |
|---|---|---|
| Recall@10 | >75% | Fraction of relevant cases in top 10 |
| Precision@10 | >80% | Fraction of top 10 that are relevant |
| nDCG@10 | >0.85 | Normalized discounted cumulative gain |
| MRR | >0.80 | Mean reciprocal rank of first relevant result |
| Metric | Target | Measured |
|---|---|---|
| p50 latency | <3s | TBD |
| p95 latency | <5s | TBD |
| Verification accuracy | >90% | TBD |
| Throughput | 10 RPS | TBD |
- Golden dataset: 50 test queries with human relevance judgments
- Verifier pass rate: Citation correctness > 95%
- Human evaluation: 20 sample explanations reviewed for relevance and completeness
- Weak supervision: Citation graph validation
end-to-end/
├── docker/ # Docker configurations
├── scripts/ # Data ingestion and utilities
│ ├── ingest/ # Data fetching and parsing
│ ├── embeddings/ # Embedding generation
│ └── db/ # Database setup
├── src/
│ ├── backend/ # Python backend
│ │ ├── agents/ # 5 specialized agents
│ │ ├── api/ # FastAPI routes
│ │ ├── core/ # Config, logging, orchestrator
│ │ ├── db/ # Database models and repositories
│ │ ├── services/ # LLM, embeddings, search services
│ │ └── utils/ # Text processing, citations
│ └── frontend/ # Next.js frontend
│ ├── app/ # Pages and layouts
│ ├── components/ # React components
│ └── lib/ # API client
├── tests/ # Unit, integration, E2E tests
├── .env.example # Environment variables template
├── pyproject.toml # Python dependencies
└── README.md # This file
- US Supreme Court only (v1 scope)
- 500 landmark cases in initial release (expanding to full corpus)
- Limited domain coverage (employment and contract disputes prioritized)
- No legal advice - Tool is for research purposes only
- No outcome prediction - Does not predict case outcomes
- OCR not implemented - Scanned documents flagged but not processed
- English language only - No multilingual support
- Rate limiting: 10 requests per minute per IP
- Concurrent users: Optimized for 10 concurrent users
- Context length: Limited by LLM context windows
# Unit tests
pytest tests/unit/
# Integration tests
pytest tests/integration/
# All tests with coverage
pytest --cov=src --cov-report=html# Format code
black src/ tests/
# Lint
ruff check src/ tests/
# Type checking
mypy src/# Create migration
alembic revision --autogenerate -m "Description"
# Apply migrations
alembic upgrade headdocker-compose -f docker/docker-compose.prod.yml up -dThe application can be deployed to:
- AWS: ECS + RDS + CloudFront
- Google Cloud: Cloud Run + Cloud SQL
- Render: Web Services + PostgreSQL
- Railway: All-in-one deployment
See DEPLOYMENT.md for detailed instructions.
- 5,000 SCOTUS cases ingested and normalized
- Chunking v2: tokenizer-based boundaries,
[[CIT:id|display]]inline citation markers - Inception embedding microservice (768-dim, legal domain fine-tuned)
- pgvector HNSW index for approximate nearest-neighbor search
- FastAPI backend — full CRUD + semantic search
- RRF case aggregation — cases scored by aggregate paragraph relevance
- Embeddings backfill (generate + load pipeline ready, awaiting Inception validation)
- Hybrid BM25 + Vector Search (next milestone — see below)
BM25 (Best Match 25) ranks documents by exact term frequency weighted by how rare the term is across the corpus. It excels at what vector search misses: statute citations ("42 U.S.C. § 1983"), doctrine names ("res judicata"), and case names ("Miranda v. Arizona").
Implementation plan:
- Add PostgreSQL full-text index (migration
005_bm25_index.sql):
ALTER TABLE paragraphs
ADD COLUMN text_tsv tsvector
GENERATED ALWAYS AS (to_tsvector('english', text)) STORED;
CREATE INDEX idx_paragraphs_text_tsv ON paragraphs USING gin(text_tsv);-
Run parallel scans — BM25 via
tsvector @@ websearch_to_tsqueryand vector via HNSW, each returning top-N candidates -
Merge via RRF — assign ranks to each result list, combine:
score = 1/(60 + bm25_rank) + 1/(60 + vector_rank)
Documents appearing in both lists (exact match AND semantically similar) rise to the top.
- Apply existing RRF case aggregation on top of the hybrid paragraph scores.
When it helps most: queries with specific legal terminology, statute numbers, and case names where vector search may over-generalize to conceptually similar but doctrinally distinct results.
- Retriever Agent wrapper around hybrid search
- LLM integration (OpenAI GPT-4o-mini + Anthropic Claude)
- Reranker Agent — LLM-based final relevance scoring
- Explanation Agent — paragraph-level citation generation
- Verifier Agent — citation hallucination detection
- Agent Orchestrator — parallel workflow coordination
- Next.js 14 web interface with search UI and verification badges
- Full SCOTUS corpus (10,000+ cases)
- Circuit Court opinions
- Citation graph visualization
- Shepardizing (track overturned cases)
- Document upload (analyze user's brief)
- ColBERT late-interaction retrieval
- Active learning from user feedback
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- It does NOT provide legal advice
- It should NOT be used as a substitute for professional legal judgment
- Users should independently verify all citations and precedents
- No warranty is provided for accuracy or completeness
- Consult qualified legal professionals for legal matters
🚧 Under Active Development - Portfolio & Learning Project
This is a learning project focused on:
- Agentic workflow design and implementation
- Hybrid retrieval system architecture
- LLM safety and verification mechanisms
- Production-grade NLP system design
Not intended for production legal use without significant additional development and validation.
- Free Law Project for CourtListener API
- OpenAI for GPT and embedding models
- Anthropic for Claude models
- pgvector team for PostgreSQL vector extension
- Legal professionals who provided feedback on requirements
- GitHub Issues: Report bugs or request features
- Documentation: Full docs
- Project Board: Development progress
If you use this project in your research or reference it in your work, please cite:
@software{litigation_precedent_assistant,
title = {Litigation Precedent Research Assistant},
author = {Your Name},
year = {2026},
url = {https://github.com/your-username/litigation-precedent-assistant}
}Built with ❤️ for the legal tech community
Demonstrating the intersection of AI, NLP, and legal research