Map Control — from natural-language commands to nautical-chart coordinate resolution
Walk one cycle of routing operator natural-language commands through intent classification → tactical zone lookup → coordinate resolution, driving automated pan / zoom / overlay on an electronic nautical chart.
Workshop goal
By the time you finish this Workshop, you will have walked through one full cycle of the following flow inside D.Hub.
- Load a single scenario into portal so that two sub-collections (
tactical_datafor definitions andmap_opsfor runtime), 4 datasets, 3 code nodes, 3 pipelines, an ontology with 3 entities and 2 relations, a dashboard, one knowledge, and one agent are all registered together. - Inspect 7 tactical zone types (safety / operation / patrol / boundary / ADIZ / surveillance / port control) defined for the maritime operations domain.
- Walk through the
map_controlagent's 5-step workflow: classify an operator's natural-language command (e.g. "Show me the 15NM safety zone") into intent → look up zone → resolve WGS84 coordinates → determine zoom level → emit structured JSON. - Confirm that every command call is logged to
om_event_historyas an audit trail of who · what · when · where. - Expand
mc_tactical_zone↔mc_graphic_overlay↔mc_event_historygraph to see command call history for one zone on one screen. - Read the
map_operationsdashboard for intent distribution / user activity from the operator's vantage point.
The core lesson is the pattern of unpacking natural-language commands into structured actions and handing them off to external UI systems. Recommended duration: 90 minutes.
Prerequisites
- An analyst or engineer account with access to D.Hub portal (Editor or higher)
- ~44 KB of download room for one scenario zip
1. Load the scenario (10 min)
map_control.zip Download(45 KB)Go to Collections → more (⋯) menu → Import (가져오기) and upload the zip.
Following manifest.json, the import creates the following in order:
- Two collections —
tactical_data(alias: Tactical Data),map_ops(alias: Map Operations) - Four datasets —
om_tactical_zone(tactical_data),om_graphic_overlay(tactical_data),om_event_history(map_ops),ui_control_parameters(map_ops) - Three codes (Python) —
zone_resolver,parameter_formatter,build_map_control_ontology - Three pipelines —
zone_data_ingestion,map_control_execution,ontology_materialization - Ontology — 3 entities (
mc_tactical_zone,mc_graphic_overlay,mc_event_history), 2 relations (mc_has_spatial_coordinates,mc_referenced_in_event) - One knowledge —
operation_guide(operations guide — intent classification criteria + output schema) - One dashboard —
map_operations - One agent —
map_control(natural language → coordinates)
2. Browse the tactical-zone definitions (10 min)
Open the tactical_data collection. The scenario's starting point is tactical zone definitions.
om_tactical_zone (8 rows) — Columns: zone_id, zone_name, zone_type (safety / operational / patrol / boundary / adiz / surveillance / port_control), description, priority_level, created_at. The seed data defines 8 zones in Korean territorial waters (e.g. 15NM Safety Zone, Operational Zone Alpha, Patrol Zone B-3, Busan Port Entry/Exit Control Zone).
om_graphic_overlay (8 rows) — WGS84 coordinates and recommended zoom level for the same 8 zones. Columns: overlay_id, zone_id (foreign key), center_longitude, center_latitude, recommended_zoom_level, boundary_polygon (WKT text), display_color.
The separation between the two is intentional. Splitting zone semantics (tactical definition) from zone coordinates (geographic representation) means coordinate updates don't disturb semantics, and vice versa. The §3 pipeline joins them by zone_id into one operational table.
3. Operational pipeline — zone data integration (15 min)
In the map_ops collection's Pipelines section, open zone_data_ingestion. One node — zone_resolver combines the two inputs.
zone_resolver processing:
- Inner-join
om_tactical_zone+om_graphic_overlayonzone_id. - Normalize WGS84 coordinates to decimal degree standard (convert DMS format if input).
- Fill missing
recommended_zoom_levelwithzone_type-specific defaults (e.g.port_control= 11,patrol= 8). - Output
ui_control_parameters— Columns:zone_id,zone_name,zone_type,longitude,latitude,zoom_level,display_color,priority_level.
This one table is the form the UI can consume directly per command. The next-step agent's core job is to unpack a natural-language command into one row of this table.
Press Run. When it finishes, open ui_control_parameters and confirm all 8 rows carry populated coordinates and zoom.
4. Intent classification + safety gating (10 min)
This is the Workshop's safety design core. The map_control agent's first tool is classify_intent — the LLM classifies a natural-language command into one of three intents.
UI_CONTROL— Electronic nautical chart control intent (pan / zoom / overlay display). Allowed.DATA_QUERY— Data query intent (e.g. "Tell me which zones got patrolled today"). Blocked (a separate operational data tool should handle this).SYSTEM_CONFIG— System configuration change intent (e.g. "Change the screen color"). Blocked (requires separate admin privileges).
Blocked intents don't enter the map_control_execution pipeline. The response reads "This command is out of this agent's scope. Please use the ___ tool.".
This allow-list gating is the standard safety pattern that narrows the agent's misbehavior surface. Even if the intent-classification LLM operates with a single-digit error rate, the probability that an out-of-allowlist intent slips through is a multiplicative step lower (it would have to be misclassified as UI_CONTROL to pass).
5. One agent cycle — command → coordinates (20 min)
In the map_ops collection's Agents section, open map_control and start a new session.
The agent's 5-step workflow:
classify_intent— Classify the natural-language command intoUI_CONTROL/DATA_QUERY/SYSTEM_CONFIG(§4).lookup_zone— ForUI_CONTROL, find the best-matching row inui_control_parametersagainst the command's zone keyword (exact match first, fuzzy match as fallback).resolve_coordinates— Extractlongitude,latitude,zoom_levelfrom the matched row. Relative location expressions (e.g. "10 NM out from Busan offshore") compute bearing and distance from the reference zone's coordinates.format_parameters— Emit structured JSON the external UI consumes:{"command": "pan_and_zoom", "longitude": 129.12, "latitude": 35.05, "zoom": 8, "zone_id": "Z-003", "overlay_color": "#ff0000"}.log_event— Record one call as one row inom_event_history. Columns:event_id,user_id,command_text,intent,target_zone_id,output_json,created_at.
In the session, enter the following commands in order. The seed om_tactical_zone carries 8 zones — 15NM Safety Zone, Operational Zone Alpha, Patrol Zone B-3, Jinhae Bay Boundary Zone, Jeju South ADIZ, East Sea Operational Zone Charlie, West Sea NLL Surveillance Zone, Busan Port Entry/Exit Control Zone — so the zone keywords in the commands map directly.
- Command 1: "Show me the 15NM safety zone" — Classifies as
UI_CONTROL; the coordinates and zoom forTZ-001emit as JSON. - Command 2: "Zoom in to Busan Port Entry/Exit Control Zone" — Matches
TZ-008and zooms +2 above theport_controlrecommended zoom level. - Command 3: "Tell me today's patrol history" — Classifies as
DATA_QUERYand returns a rejection response. The rejection is also logged as one row inom_event_history.
After each command, switch to om_event_history's preview and confirm one row per call was recorded.
6. Ontology + graph exploration (10 min)
Run ontology_materialization. build_map_control_ontology reads the 4 datasets in batch mode and lands the 3 entities + 2 relations in upsert mode.
| Entity | Key | Key attributes |
|---|---|---|
mc_tactical_zone | zone_id | zone_name, zone_type, priority_level |
mc_graphic_overlay | overlay_id | longitude, latitude, zoom_level, display_color |
mc_event_history | event_id | user_id, intent, command_text, created_at |
Relations × 2:
mc_has_spatial_coordinates(mc_tactical_zone→mc_graphic_overlay)mc_referenced_in_event(mc_tactical_zone→mc_event_history) — Linked when a command targeted that zone
In the Graph explorer, surface command call history for one zone on one screen.
MATCH (z:mc_tactical_zone {zone_type: 'port_control'})-[:mc_referenced_in_event]->(e:mc_event_history)
OPTIONAL MATCH (z)-[:mc_has_spatial_coordinates]->(o:mc_graphic_overlay)
RETURN z, o, e
ORDER BY e.created_at DESC
LIMIT 20
One port-control zone's 20 most recent command events fall out. When the same zone fires multiple commands in a short window, that's an operator-attention spike signal; when one zone gets concurrent commands from different users, that's a shared operations window signal.
7. Dashboard + next steps (10 min)
The map_operations (alias: Map Operations Dashboard) dashboard's 4 widgets all read from om_event_history.
- Total Events (statistic) —
COUNT(*) - Events by Intent Type (donut) — Counts per
intent_type(UI_CONTROL/DATA_QUERY/SYSTEM_CONFIGdistribution) - Events by User (bar, Top 20) — Counts per
user_iddescending - Recent Events (data table) — 100 most recent rows by
created_atdesc
The key operational signal is the Events by Intent Type donut. If the rejected-intent ratio (DATA_QUERY + SYSTEM_CONFIG) stays consistently above 30%, audit two things at once — whether the LLM's allow-list conservatism is too tight, and whether operators are routing intents that belong elsewhere through this agent. Both are next-round topics.
The Recent Events table is the audit-trail surface. Each row records who · what · when · with which intent, mapping directly to operator-style recent-activity review. Time-of-day trend / zone-access-pattern widgets aren't built into the seed; once operational data accumulates and analytical needs sharpen, adding those widgets is a natural follow-up.
Next directions:
- The Agents Path (Phase 2) covers the allow-list gating pattern as it maps onto other domains.
- Map *your own domain's command → structured action flow (smart factory work orders, call center customer responses) onto this shape.
Verification checklist
- Both
tactical_dataandmap_opscollections appear in the tree with 4 datasets loaded. - After
zone_data_ingestion, all 8 rows ofui_control_parameterscarry populatedlongitude·latitude·zoom_levelcolumns. - After the 3-command session cycle,
om_event_historyrecords exactly 3 rows (theDATA_QUERYrejection must also leave one row). - In the Graph explorer, starting from one
mc_tactical_zoneyou can expand both neighbors — coordinates (mc_graphic_overlay) and events (mc_event_history) — on one screen. - The
map_operationsdashboard's Events by Intent Type donut showsUI_CONTROLas the largest slice, withDATA_QUERYandSYSTEM_CONFIGreflected as rejection statistics.