Problem
US zoning ordinances are dense, jurisdiction-specific legal documents. A compliance professional checking whether a proposed development satisfies local rules needs answers like "Does section 4.3 of the Riverside overlay district modify the setback requirements from the parent R-2 zone?" — a question that requires navigating overlapping, cross-referenced regulatory text.
Retrieval architecture
Two complementary retrieval layers:
RAG over document text
Standard dense retrieval over chunked PDF text. Docling handles layout-aware extraction, preserving section hierarchy, table structure, and footnotes. Chunks are embedded and stored for semantic search.
GraphRAG over zoning relationships
Zoning ordinances have explicit graph structure: overlay districts that modify parent zones, amendment chains, cross-references between sections. A small graph index captures:
- Overlay district → parent zone relationships
- Amendment chains (ordinance A amended section X of ordinance B)
- Cross-section references ("see also §7.2")
The GraphRAG retriever traverses this graph at query time, surfacing structurally related sections that semantic search alone would miss.
Citation verifier
The most operationally important component. After the Claude API generates an answer, a verifier:
- Extracts cited section numbers from the response
- Looks up each citation in the source PDF (by page and bbox from Docling extraction)
- Checks that the cited text supports the generated claim
- Flags hallucinated or drifted citations in the QA Dashboard
The ChatAEC dashboard surfaces these flags in < 2s p95.
Infrastructure
- Scrapers pull PDFs from 40+ municipal websites (Python + Selenium + plain HTTP)
- Raw PDFs land in MinIO; extraction events flow through Kafka
- Airflow orchestrates the scrape → extract → embed → load pipeline
- The graph index is backed by Postgres + a small in-process graph library
- Claude API (claude-sonnet) handles answer generation with a structured citation prompt