By Sagar Shankaran, Founder of CallSphere
Learn how to build an AI agent for emergency management agencies that distributes disaster alerts, maps shelter locations, coordinates resource information, and provides real-time updates to affected citizens.
Key takeaways
During natural disasters — hurricanes, wildfires, floods, earthquakes — emergency management agencies face a communications crisis of their own. Hundreds of thousands of people need answers simultaneously: "Is my area under evacuation?" "Where is the nearest shelter?" "Is the shelter pet-friendly?" "When will power be restored?" "Where can I get drinking water?"
911 and emergency hotlines are overwhelmed. Social media fills with rumors. Official websites crash under traffic spikes. An AI agent can serve as a scalable, always-available information channel that provides accurate, location-specific answers to these questions. It does not coordinate the actual emergency response — it handles the citizen-facing communication layer so that emergency managers can focus on operations.
Emergency management agents must work under constraints that normal government agents do not face. Internet connectivity may be intermittent. Power may be out. People are stressed, frightened, and may not speak English. The agent must be designed for degraded conditions from day one.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
class DisasterType(Enum):
HURRICANE = "hurricane"
WILDFIRE = "wildfire"
FLOOD = "flood"
EARTHQUAKE = "earthquake"
TORNADO = "tornado"
WINTER_STORM = "winter_storm"
HAZMAT = "hazardous_materials"
TSUNAMI = "tsunami"
class AlertLevel(Enum):
ADVISORY = "advisory" # be aware
WATCH = "watch" # be prepared
WARNING = "warning" # take action
EMERGENCY = "emergency" # take action immediately
@dataclass
class DisasterEvent:
event_id: str
disaster_type: DisasterType
name: str # e.g., "Hurricane Maria"
alert_level: AlertLevel
affected_zones: list[str] # zip codes, zone IDs
start_time: datetime
summary: str
instructions: list[str]
evacuation_zones: list[str] = field(default_factory=list)
curfew_hours: str | None = None
updated_at: datetime = field(default_factory=datetime.utcnow)
@dataclass
class EmergencyUpdate:
update_id: str
event_id: str
timestamp: datetime
message: str
category: str # shelter, power, water, roads, rescue
affected_zones: list[str]
source: str # "County EOC", "National Weather Service"
During evacuations, shelter information is the most critical data the agent provides. People need to know where to go, whether the shelter has capacity, and whether it accommodates their specific needs (pets, medical equipment, accessibility).
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
@dataclass
class Shelter:
shelter_id: str
name: str
address: str
latitude: float
longitude: float
capacity: int
current_occupancy: int
status: str # open, full, closed, opening_soon
amenities: list[str] = field(default_factory=list)
pet_friendly: bool = False
ada_accessible: bool = True
medical_staff: bool = False
accepts_medical_equipment: bool = False
generator_powered: bool = False
last_updated: datetime = field(default_factory=datetime.utcnow)
SHELTER_REGISTRY: list[Shelter] = []
def find_nearest_shelters(
user_lat: float,
user_lon: float,
needs_pet_friendly: bool = False,
needs_medical: bool = False,
needs_accessible: bool = False,
max_results: int = 5,
) -> list[dict]:
"""Find nearest open shelters matching the user's needs."""
from math import radians, sin, cos, sqrt, atan2
def haversine(lat1, lon1, lat2, lon2):
R = 3959
dlat = radians(lat2 - lat1)
dlon = radians(lon2 - lon1)
a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
return R * 2 * atan2(sqrt(a), sqrt(1-a))
candidates = []
for shelter in SHELTER_REGISTRY:
if shelter.status not in ("open", "opening_soon"):
continue
if needs_pet_friendly and not shelter.pet_friendly:
continue
if needs_medical and not shelter.medical_staff:
continue
if needs_accessible and not shelter.ada_accessible:
continue
distance = haversine(user_lat, user_lon, shelter.latitude, shelter.longitude)
spots_remaining = shelter.capacity - shelter.current_occupancy
candidates.append({
"name": shelter.name,
"address": shelter.address,
"distance_miles": round(distance, 1),
"status": shelter.status,
"spots_remaining": max(0, spots_remaining),
"capacity_pct": round(shelter.current_occupancy / shelter.capacity * 100),
"pet_friendly": shelter.pet_friendly,
"ada_accessible": shelter.ada_accessible,
"has_medical_staff": shelter.medical_staff,
"generator_powered": shelter.generator_powered,
"amenities": shelter.amenities,
"last_updated": shelter.last_updated.isoformat(),
})
candidates.sort(key=lambda x: x["distance_miles"])
return candidates[:max_results]
The alert engine determines which information to push to which citizens based on their location and the disaster's affected zones.
from datetime import timedelta
class AlertDistributor:
"""Distribute disaster alerts to affected citizens."""
def __init__(self):
self.active_events: dict[str, DisasterEvent] = {}
self.updates: list[EmergencyUpdate] = []
def get_alerts_for_location(self, zipcode: str) -> list[dict]:
"""Get all active alerts affecting a specific location."""
relevant = []
for event in self.active_events.values():
if zipcode in event.affected_zones or "all" in event.affected_zones:
is_evacuation = zipcode in event.evacuation_zones
relevant.append({
"event_name": event.name,
"type": event.disaster_type.value,
"alert_level": event.alert_level.value,
"summary": event.summary,
"instructions": event.instructions,
"evacuation_required": is_evacuation,
"curfew": event.curfew_hours,
"last_updated": event.updated_at.isoformat(),
})
# Sort by severity (emergency first)
level_order = {
"emergency": 0, "warning": 1, "watch": 2, "advisory": 3,
}
relevant.sort(key=lambda x: level_order.get(x["alert_level"], 4))
return relevant
def get_recent_updates(
self, event_id: str, since_hours: int = 6
) -> list[dict]:
"""Get recent updates for a specific disaster event."""
cutoff = datetime.utcnow() - timedelta(hours=since_hours)
recent = [
u for u in self.updates
if u.event_id == event_id and u.timestamp >= cutoff
]
recent.sort(key=lambda u: u.timestamp, reverse=True)
return [
{
"time": u.timestamp.strftime("%I:%M %p"),
"category": u.category,
"message": u.message,
"source": u.source,
}
for u in recent
]
Beyond shelters, citizens need to know about water distribution points, food banks, fuel availability, and medical facilities that are operational.
@dataclass
class ResourcePoint:
resource_id: str
resource_type: str # water, food, fuel, medical, charging_station
name: str
address: str
latitude: float
longitude: float
hours: str
status: str # open, closed, limited
notes: str = ""
last_verified: datetime = field(default_factory=datetime.utcnow)
def find_resources(
user_lat: float,
user_lon: float,
resource_type: str,
resources: list[ResourcePoint] = None,
max_distance: float = 15.0,
) -> list[dict]:
"""Find nearby resource distribution points."""
from math import radians, sin, cos, sqrt, atan2
def haversine(lat1, lon1, lat2, lon2):
R = 3959
dlat = radians(lat2 - lat1)
dlon = radians(lon2 - lon1)
a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
return R * 2 * atan2(sqrt(a), sqrt(1-a))
results = []
for r in resources or []:
if r.resource_type != resource_type:
continue
if r.status == "closed":
continue
distance = haversine(user_lat, user_lon, r.latitude, r.longitude)
if distance > max_distance:
continue
results.append({
"name": r.name,
"address": r.address,
"distance_miles": round(distance, 1),
"hours": r.hours,
"status": r.status,
"notes": r.notes,
"last_verified": r.last_verified.strftime("%b %d, %I:%M %p"),
})
results.sort(key=lambda x: x["distance_miles"])
return results[:10]
The agent's language during emergencies must follow established crisis communication principles: be first, be right, be credible.
EMERGENCY_AGENT_PROMPT = """You are an emergency information agent for the
county emergency management agency.
CRISIS COMMUNICATION RULES:
1. Be SPECIFIC and ACTIONABLE. Not "seek shelter" but "go to Lincoln High
School shelter at 1234 Oak Street, capacity available, pet-friendly."
2. Lead with the most critical information. Evacuation orders first,
then shelter locations, then resource points.
3. Include timestamps on all information. "As of 3:00 PM" matters during
rapidly evolving situations.
4. Acknowledge uncertainty. If you do not have current shelter occupancy
data, say so rather than guessing.
5. Never minimize danger. If an evacuation order is active, communicate
urgency clearly.
6. Provide information in the user's language if possible.
7. For life-threatening emergencies, always direct to 911 first.
8. Include accessibility information for shelters proactively.
You have access to these tools:
- get_alerts(zipcode): Get active disaster alerts for a location
- find_shelters(lat, lon, needs): Find nearby open shelters
- find_resources(lat, lon, type): Find water, food, fuel, medical points
- get_updates(event_id): Get latest situational updates
Always end emergency responses with the local emergency hotline number.
"""
The language design is critical. During Hurricane Harvey, official communications that said "GET OUT OR DIE" were more effective than polite suggestions because they conveyed urgency without ambiguity. The agent should calibrate its tone to the alert level — advisory messages are informational, but emergency-level messages should convey urgency clearly.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
The agent is designed with a fallback architecture. The primary mode is full LLM-powered conversation over the internet. If connectivity is limited, the agent falls back to a keyword-matching mode that runs on cached data locally — it can still answer "nearest shelter" and "am I in an evacuation zone" using pre-downloaded shelter data and zone maps. For complete outage scenarios, the emergency management agency deploys SMS-based querying where citizens text a keyword (SHELTER, WATER, POWER) to a short code and receive automated responses from a lightweight backend that does not require internet access for the citizen.
Shelter occupancy is updated through multiple channels. Staff at each shelter report check-ins through a mobile app or phone call to the Emergency Operations Center (EOC). The EOC dashboard updates the central database, which the agent queries in real-time. Updates flow every 15-30 minutes during active operations. The agent always displays the "last updated" timestamp so citizens can assess how current the information is. If a shelter has not been updated in over 2 hours, the agent flags this: "Occupancy data for Lincoln High School was last updated at 2:00 PM — call the shelter directly at (555) 123-4567 for current availability."
Yes. After the immediate emergency phase, the agent shifts to recovery mode. It helps citizens report property damage to the local emergency management agency, guides them through FEMA Individual Assistance applications, provides information about SBA disaster loans, and connects them with volunteer organizations (Red Cross, local relief agencies). It also tracks the status of utility restoration by neighborhood, road closures and reopenings, and boil-water advisories. The agent's role evolves with the disaster lifecycle: from preparedness (before), to response (during), to recovery (after).
#GovernmentAI #EmergencyManagement #DisasterResponse #ShelterMapping #CrisisCommunication #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Build an AI agent for municipal parks and recreation departments that handles program catalog search, class registration, facility reservations, and seasonal event information for community members.
Learn how to build an AI agent for court systems that provides case lookup, hearing date information, filing requirements, and attorney resources while maintaining strict accuracy standards for legal information.
Learn how to build an AI agent that handles 311 citizen complaints by classifying request types, routing to the correct city department, tracking status, and automating follow-up communications.
The Biden administration's AI modernization push leads to rapid deployment of AI agents across IRS, VA, SSA, and USPS, transforming public service delivery.
Build an AI agent that walks citizens through permit application processes, generates document checklists, calculates fees, and provides real-time status updates on submitted applications.
Build an AI agent for public libraries that searches the catalog, places and manages holds, handles account inquiries, and helps patrons discover library programs and events.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI