Demo Walkthrough: Defra AI Agent¶
This walkthrough demonstrates the complete functionality of the Defra AI Agent for environmental incident reporting. Follow these steps to see the system in action.
Prerequisites¶
- Docker and Docker Compose installed
- OpenAI API key configured in
.env - All services running (
docker compose up -d)
Scenario 1: Critical Water Pollution Incident¶
Context¶
A toxic chemical spill has been reported near a drinking water treatment facility, posing immediate danger to public health.
Step 1: Submit the Incident¶
curl -X POST http://localhost:8000/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "water_pollution",
"description": "Toxic chemical spill near drinking water treatment plant, immediate danger to public health",
"location": "Thames Water Treatment Plant, London",
"latitude": 51.4875,
"longitude": -0.1687,
"reporter_email": "emergency@example.com",
"urgency": "critical"
}'
Expected Response¶
{
"success": true,
"incident_id": "INC-20251206-143022",
"message": "Incident INC-20251206-143022 received and classified as critical severity. P1 - Immediate Response (within 1 hour)",
"severity": "critical",
"priority": "P1 - Immediate Response (within 1 hour)",
"classification": {
"category": "water_pollution",
"severity": "critical",
"priority": "P1 - Immediate Response (within 1 hour)",
"required_actions": [
"Log incident in database",
"Assign incident ID",
"Alert Environment Agency duty officer immediately",
"Dispatch field team for urgent assessment",
"Notify emergency services if required",
"Issue public warning if necessary",
"Activate major incident protocol",
"Check water quality monitoring data",
"Identify potential sources",
"Alert water companies if applicable",
"Send acknowledgment to reporter"
],
"reasoning": "Incident classified as critical severity water_pollution. Critical classification due to immediate public health or environmental risk. Water pollution incidents require urgent response to prevent downstream contamination."
},
"spatial_context": {
"protected_sites": "No protected sites found within 5.0km",
"water_bodies": "Found 1 water body within 10.0km: River Thames (0.84km away)",
"historical_incidents": "No similar incidents in last 90 days"
},
"guidance": "Relevant guidance on critical incident response...",
"notifications": {
"sent": ["email to emergency@example.com"],
"failed": [],
"test_mode": true
}
}
Key Observations¶
✅ Severity Detection: System correctly identified "toxic" and "drinking water" keywords → Critical severity
✅ Priority Assignment: P1 response (within 1 hour)
✅ Action Generation: 11 specific actions including emergency protocols
✅ Spatial Awareness: Found River Thames 0.84km away
✅ Notifications: Email acknowledgment sent to reporter
Scenario 2: Oil Spill Near Protected Site¶
Context¶
An oil spill has been observed in the River Thames near protected marshes (SSSI designation).
Step 2: Submit the Incident¶
curl -X POST http://localhost:8000/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "water_pollution",
"description": "Large oil slick observed on the River Thames near Westminster Bridge affecting protected marshes",
"location": "Westminster Bridge, London",
"latitude": 51.5007,
"longitude": -0.1246,
"reporter_email": "witness@example.com",
"urgency": "high"
}'
Expected Response Highlights¶
{
"severity": "high",
"priority": "P2 - Urgent Response (within 4 hours)",
"classification": {
"required_actions": [
"Alert Environment Agency team",
"Schedule site visit within 4 hours",
"Check for nearby protected sites",
"Alert water companies if applicable"
]
},
"spatial_context": {
"protected_sites": "Found 1 protected site: Thames Estuary Marshes (SSSI) 2.3km away, vulnerable to oil spills",
"water_bodies": "River Thames (0.84km away, moderate quality)"
}
}
Key Observations¶
✅ Keyword Matching: "oil spill" triggered high severity
✅ Spatial Intelligence: Found protected SSSI site 2.3km away
✅ Vulnerability Matching: System noted site is vulnerable to oil spills
✅ 4-Hour Response: P2 priority for urgent action
Scenario 3: Illegal Dumping Near SSSI¶
Context¶
Construction waste has been illegally dumped in Peak District National Park near a protected site.
Step 3: Submit the Incident¶
curl -X POST http://localhost:8000/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "illegal_dumping",
"description": "Large pile of construction waste dumped in Peak District National Park",
"location": "Peak District, Derbyshire",
"latitude": 53.2958,
"longitude": -1.7978,
"reporter_email": "ranger@example.com",
"urgency": "high"
}'
Expected Response Highlights¶
{
"severity": "high",
"priority": "P2 - Urgent Response (within 4 hours)",
"classification": {
"required_actions": [
"Alert Environment Agency team",
"Schedule site visit within 4 hours",
"Document evidence for prosecution",
"Arrange waste removal",
"Check for hazardous materials"
]
},
"spatial_context": {
"protected_sites": "Found 1 protected site: Peak District Moors (SSSI) 0.45km away, vulnerable to illegal dumping",
"historical_incidents": "No similar incidents in last 90 days"
},
"guidance": "Relevant waste management regulations..."
}
Key Observations¶
✅ Incident-Specific Actions: Waste-specific actions (evidence, removal, hazmat check)
✅ Close Proximity Alert: SSSI found 0.45km away
✅ Pattern Detection: Historical incident check (none found)
✅ Legal Framework: Guidance includes prosecution procedures
Scenario 4: Low-Priority Noise Complaint¶
Context¶
A resident reports minor construction noise during permitted hours.
Step 4: Submit the Incident¶
curl -X POST http://localhost:8000/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "noise_pollution",
"description": "Minor noise from construction site during daytime",
"location": "Commercial area, Manchester",
"latitude": 53.4808,
"longitude": -2.2426,
"reporter_email": "resident@example.com",
"urgency": "low"
}'
Expected Response Highlights¶
{
"severity": "low",
"priority": "P4 - Routine Response (within 5 days)",
"classification": {
"required_actions": [
"Log incident in database",
"Add to routine inspection schedule",
"Monitor for pattern development",
"Send acknowledgment to reporter"
]
},
"spatial_context": {
"protected_sites": "No protected sites within 5.0km",
"water_bodies": "No water bodies within 10.0km"
}
}
Key Observations¶
✅ Appropriate Prioritization: Low severity = P4 (5-day response)
✅ Minimal Actions: Only routine monitoring and logging
✅ Resource Efficiency: No urgent response for minor issue
✅ Reporter Acknowledgment: Still sends confirmation email
Testing the Complete Workflow¶
End-to-End Test Script¶
#!/bin/bash
# Complete workflow demonstration
BASE_URL="http://localhost:8000"
echo "=== Testing Health Check ==="
curl -s $BASE_URL/health | jq .
echo -e "\n=== Scenario 1: Critical Incident ==="
curl -s -X POST $BASE_URL/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "water_pollution",
"description": "Toxic chemical spill near drinking water",
"location": "London",
"latitude": 51.5074,
"longitude": -0.1278,
"urgency": "critical"
}' | jq '{incident_id, severity, priority, actions: .actions[:3]}'
echo -e "\n=== Scenario 2: High Priority with Coordinates ==="
curl -s -X POST $BASE_URL/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "water_pollution",
"description": "Oil spill in Lake Windermere",
"location": "Lake Windermere, Cumbria",
"latitude": 54.3500,
"longitude": -2.9333,
"urgency": "high"
}' | jq '{incident_id, severity, spatial_context: .spatial_context.protected_sites}'
echo -e "\n=== Scenario 3: Low Priority ==="
curl -s -X POST $BASE_URL/api/v1/incidents/submit \
-H "Content-Type: application/json" \
-d '{
"incident_type": "noise_pollution",
"description": "Minor construction noise",
"location": "Manchester",
"urgency": "low"
}' | jq '{incident_id, severity, priority}'
echo -e "\n=== All tests complete ==="
Save this as demo_test.sh, make it executable, and run:
Monitoring and Debugging¶
Check Service Health¶
# API health
curl http://localhost:8000/health
# Neo4j browser
open http://localhost:7475
# Check logs
docker compose logs api --tail=50
docker compose logs neo4j --tail=50
docker compose logs postgres --tail=50
Verify Database Contents¶
Neo4j (Protected Sites):
PostgreSQL (Guidance Documents):
SELECT title, length(content) as content_length, metadata->>'source' as source
FROM documents
LIMIT 10;
Run Automated Tests¶
# All tests
pytest
# With coverage
pytest --cov=app --cov-report=html
# Specific scenario
pytest tests/integration/test_agent_workflow.py::TestIncidentAgentWorkflow::test_complete_workflow_high_severity -v
Architecture Overview¶
The demo showcases this workflow:
1. HTTP Request → FastAPI (/api/v1/incidents/submit)
2. Agent Initialization → LangGraph Workflow
3. Classification → classify_incident tool (severity, priority, actions)
4. Spatial Analysis → Neo4j queries (protected sites, water bodies)
5. Guidance Search → pgvector semantic search
6. Notifications → GOV.UK Notify (email)
7. Response Assembly → JSON with complete context
8. HTTP Response → Client receives results
Key Metrics Demonstrated¶
| Metric | Value |
|---|---|
| Average Response Time | 2-5 seconds |
| Classification Accuracy | 100% for keyword-based severity |
| Spatial Query Range | 5km (sites), 10km (water) |
| Guidance Retrieval | Top 3 relevant documents |
| Notification Delivery | Real-time email acknowledgment |
| Test Coverage | 72 tests, 57% code coverage |
Next Steps¶
After completing the demo:
- Review Logs: Check
docker compose logsfor detailed workflow execution - Examine Coverage: Open
htmlcov/index.htmlto see test coverage - Explore Neo4j: Use Neo4j Browser to visualize spatial relationships
- Check Emails: Review GOV.UK Notify dashboard (if using real API key)
- Customize: Modify incident types, add new protected sites, update guidance
Troubleshooting¶
Issue: Service not responding
Solution: Check Docker containers are running: docker compose ps
Issue: No spatial results
Solution: Verify Neo4j has data: docker compose exec neo4j cypher-shell -u neo4j -p <password> "MATCH (s) RETURN count(s);"
Issue: No guidance results
Solution: Check PostgreSQL embeddings: docker compose exec postgres psql -U defra -d defra_agent -c "SELECT count(*) FROM documents;"
Issue: OpenAI errors
Solution: Verify OPENAI_API_KEY in .env file is valid
Success Criteria¶
✅ All HTTP requests return 200 status
✅ Critical incidents get P1 priority
✅ Spatial queries find nearby protected sites
✅ Guidance search returns relevant documents
✅ Email notifications sent successfully
✅ Complete workflow executes in < 10 seconds
Demo Complete! 🎉