CARDIO4Cities / AI engineer case study

City research workspace

  • For: City Leads preparing government and healthcare meetings
  • In: a city name. Out: a cited brief, open questions, a knowledge graph, Q&A
  • Rule: every finding traces to a source; every unknown stays visible
8agents, 3 of them gates
3datastores: ledger, vectors, graph
4live search sources: Tavily web search + 3 scholarly APIs
$0models, search, storage, hosting on free tiers
Live research · open-weights models · no pre-seeded city data 01 / 08

The problem

Today
  • Days of reading portals, papers and policy
  • Ends as one person’s unverifiable document
The real risk: confidently wrong
  • A national figure quoted as a city one
  • A statistic nobody can source
“Understanding a city” = 5 areas
AreaQuestion
BurdenHow common are CVD, hypertension, diabetes?
ProgrammesWhat screening already runs?
PolicyWhich NCD plans are in force?
AccessFacilities, workforce, pathways to care?
ActorsWhich institutions matter?
02 / 08

AI solution: a team of agents

PlannerDiscoveryCrawl gateReader Claim agentFact checkerSufficiencyBrief
↺ Sufficiency sends the Planner back for missing areas · bounded by depth
AgentJobHands on
PlannerTurns the city into searches per areaSearch queries
DiscoveryTavily web search for government and programme pages; OpenAlex, Europe PMC, Wikipedia for studies. Ranks by authorityCandidate sources
gate Crawl gateReads robots.txt before any fetchPermitted sources
ReaderFetches HTML, XML, PDFClean text
Claim agentProposes findings, each with an exact quoteCandidate claims
gate Fact checkerA different model judges each claimPublished or withheld
gate SufficiencyAre 3 of 5 areas covered?Publish, or search again
Answer agentAnswers questions from stored evidence onlyCited answer, or “not enough evidence”

Stack: LangGraph · open-weights models on Groq · Tavily + scholarly APIs · SQLite, Qdrant, Graphiti + Neo4j Sandbox · FastAPI · Docker on Render. No agent both writes a claim and approves it.

03 / 08

Knowledge management and retrieval

StoreHoldsAnswers
SQLite ledgerRuns, sources, crawl decisions, facts, gaps, metrics“What did the system decide, and why?”
QdrantVerified evidence passages, filtered by city“What evidence is near my question?”
Graphiti + Neo4j SandboxOrganisations, programmes, policies, indicators, places“Who is connected to what?”
QuestionVectors + graphRerankAnswer agentCited answer or decline
  • Vectors and graph are queried together at question time; citations resolve to stored records, never to model memory
  • Graphiti is bi-temporal, so re-researching a city keeps what was previously true
  • If vectors or graph are down, the ledger still answers
04 / 08

Trustworthiness and evidence

GuardRuleIf it fails
Permissionrobots.txt is read before any fetchNot fetched, listed with reason
GroundingThe quote must be found in the source textClaim discarded
NumbersEvery number in a claim must be in its quoteUnsupported
IndependenceThe checker never wrote the claimWithheld → gap
ScopeNational evidence is not a city figurePublished with a warning
Hyderabad · passed“55% had hypertension”22/40 and 55% both appear in the quote; marked partially supported because the sample is one hospital.
Hyderabad · withheld“Meetings held in Hyderabad”The checker read the quote: five different cities. Recorded as a gap.
05 / 08

Worked example and evaluation: Hyderabad

Recorded run · 13 Sep 2026 · Balanced depth · 1 round · 51 s · docs/examples/hyderabad-research-run.json

80%of claims survived checking
100%of findings are city-level
3 / 5areas covered; policy and access became gaps
4 / 4checked by a model, not rules
From 46 sources to 4 findings
Discovered46
Permitted45
Read6
Claims5
Published4
Withheld1
Finding · burden · partially supported“Common comorbidities were hypertension (22/40, 55%), dyslipidemia (19/40, 47.5%), and diabetes mellitus (9/40, 22.5%).”Nizam’s Institute of Medical Sciences (Cureus, 2026). Confidence 0.70: a hospital sample, not city prevalence.
Honest readingGrounded is not representative, and the brief says so. This run predates Tavily: all 46 sources were scholarly, which is why policy and access came back empty. Tavily now adds government and programme pages to every run.
06 / 08

User experience

A City Lead, not an engineer
1Type“Hyderabad, India”
2Pick depthQuick, Balanced, Thorough
3Watch10 steps in 4 plain phases
4CheckEach finding opens to its quote
5Ask & take awayCited Q&A, downloadable brief
DepthSources readRoundsWeb searchesTime
Quick51342 s measured
Balancedup to 8up to 2up to 1051 s measured (Hyderabad, 1 round)
Thoroughup to 12up to 2up to 12~4–8 min est.

Degraded modes are shown, not hidden: a banner appears when a model, store or search provider is unavailable.

07 / 08

Trade-offs and limitations

Decisions: trust is never traded; time and cost are
DecisionEffect
Rules before modelsrobots.txt, quote and number checks cost no tokens
Search APIs, not scrapingTavily + scholarly APIs: sanctioned, no captchas
Rate limit ≠ outageFail over to a free model; extraction 383 s → seconds
Brief first, graph laterThe user never waits for the graph
Limitations and next steps
LimitationNext
Grounded ≠ relevantReranker, labelled city evaluation set
Web search returns news, commerceAuthority ranking and fact checker filter; tune domains
Free tiers: rate limits, sleep, Sandbox expiryPaid tiers
SQLite, no auth, no human reviewPostgreSQL, authentication, review queue
Demo path
Unseen cityWatch the agentsFinding → quoteOpen questionsGraphAskDownload
08 / 08
← Workspace Architecture ← → to navigate