Inspiration
Traffic congestion in the Greater Toronto and Hamilton Area costs a staggering $44.7 billion annually in lost productivity and quality of life. In 2024 alone, Toronto saw 69,141 automobile accidents, with 1,436 involving pedestrians. But fixing this is a political nightmare. Urban planning decisions—like adding a bike lane or a transit corridor—take years to approve and often devolve into bitter neighborhood battles. We wanted to see what happens when you pit AI agents against real-world physics to negotiate these street layouts before a single dollar is spent. We were inspired by agent-based modeling but wanted to build an adversarial engine that felt alive and grounded in real math. The idea was simple: turn a real intersection into a living simulation where stakeholders debate safety, throughput, and emissions, and let them fight it out until they reach a mathematically viable compromise.
What it does
EO is a generative urban planning simulation running on a 3D map of Toronto. You start by selecting an intersection and issuing a user directive (e.g., "Ban cars and prioritize buses"). Instantly, a multi-agent AI council, comprising a Traffic Engineer, a Vision Zero Safety Advocate, a Local Business Coalition, and an Environmental Advocate debates your directive. They argue in real-time, fiercely defending their specific metrics. These agents do more than just generate text, as their compromises are fed into a deterministic physics scorer that calculates real-world impacts on vehicular throughput, CO2 emissions, walkability, and safety. If the math falls below the initial state, the graph forces the agents back to the negotiating table. Once a valid consensus is reached, the frontend, built with Mapbox GL, instantly physically alters the 3D map, rendering glowing neon bus lanes, protected bike lanes, and green infrastructure. You also get a complete council report with an itemized, estimate budget quote for the construction costs. Finally, you can trigger a "5-Year Future Simulation" to see how the agents react to compounded urban decay and increased traffic demands over time, remembering their past decisions.
How we built it
The backend is written in Python using FastAPI and LangChain. We built a parallelized StateGraph that handles the multi-agent orchestration. Each simulation tick starts with a Fan-out pattern: the 4 stakeholder agents evaluate the current layout and the user's prompt in parallel using Google Gemini 2.5 Flash. Their aggressive critiques are fed to a Synthesizer agent, which proposes a new structured JSON layout. The Synthesizer's layout is evaluated by a strict, deterministic Python scorer hat scores the throughput, safety, and emissions. If the safety index is below our threshold, the LangChain Conditional Edge loops the layout back to the stakeholders for another round of debate.
Throughput Capacity ($T$): Evaluated based on lane modality conversion.$$T = (N_c - N_b) \cdot 1900 + N_b \cdot 4200$$(Where $N_c$ is total car lanes and $N_b$ is bus lanes, factoring in the 4200 pax/hr multiplier for dedicated transit).
Daily CO2 Emissions ($E$):$$E = \max(0, 0.32 N_c + 0.18(\frac{T}{10000}) - 1.8 G)$$(Calculating base lane emissions + congestion variables, offset by the green infrastructure ratio $G$).
Vision Zero Safety Index ($S$):$$S = \max(0, \min(100, S_{base} + 20 B_p + 10 P_i - 15 \Delta N_c))$$(Applying modifiers for protected bike lanes $B_p$ and pedestrian islands $P_i$, heavily penalizing induced demand from new car lanes).
The frontend is a React application using Vite. It uses Mapbox GL for the 3D Toronto map. When the backend resolves, the frontend dynamically maps the JSON output to WebGL layers, injecting GeoJSON line strings and polygons to visually build the new infrastructure on the street. State and memory are preserved using LangChain's MemorySaver with a SQLite database. If the Traffic Engineer gets rejected twice for proposing a car-centric layout because it destroys the emissions score, it reads the thread history, learns from the failure, and stops proposing it.
Challenges we ran into
Our biggest challenge was LangChain's infinite loops and Gemini rate limits. Because our 4 agents ran in parallel, we instantly hit Google Gemini's RPM limits, causing silent backoff timeouts without us realizing. To solve this, we built a dynamic API key rotation system. Our backend actively monitors rate-limit headers and usage metrics, hot-swapping between a pool of API keys on the fly. We paired this rotation with staggered async execution and hard micro-timeouts to prevent Google from thinking we were up to something shady. Another massive hurdle was state key inconsistencies in LangChain, where missing dictionary keys caused the agents to loop indefinitely because the Physics Scorer couldn't validate the safety index. We had to build a hardcoded escape in the conditional edge to force the graph to resolve. Lastly, translating arbitrary backend JSON into physical 3D map layers was incredibly difficult. We had to create a "Neon Overlay Illusion" using invisible GeoJSON skeletons over the Mapbox streets, conditionally rendering them based on the LLM's final choices.
Accomplishments that we're proud of
We are really proud of our reasoning engine. By combining a multi-agentic pipeline with a scorer based in math, we are able to use LLMs to represent complex, multi-faceted stakeholders, while mitigating halucination to harness the best of both worlds. Even though the system could obviously be improved, we feel that this is a good abstraction of how a city's various interests may interplay. The use of Langchain's persistent memory threads also allows the agents to learn from past uses, making the system more dynamic for further use.
What we learned
We learned that orchestrating multi-agent workflows is a massive debugging challenge, particularly when LLMs fail silently in parallel and cause cascading timeouts without throwing clear errors. We also discovered the brutal reality of custom 3D rendering. Our original vision was to build a live, animated simulation of cars and buses physically driving through the newly optimized intersection. However, due to severe time constraints and the sheer complexity of WebGL animation, we had to pivot away from moving vehicles and focus our efforts on perfecting the static, data-driven highlighted overlays instead.
What's next for EO
We want to integrate real-time traffic APIs and OpenStreetMap data so users can click any intersection in the world, not just our hardcoded Toronto nodes. We also plan to implement an Agent Persona Slider on the UI, allowing users to dynamically adjust the political weight of each agent. Finally, we want to export the generated intersection geometries into standard CAD formats so that actual city planners can use EO's output as a baseline for real-world infrastructure proposals.
Built With
- fastapi
- gemini
- langchain
- mapbox
- pydantic
- python
- typescript
- webgl
Log in or sign up for Devpost to join the conversation.