Back to projects

~/projects

Multi-Agent Formation Control (LangGraph)

langgraphmulti-agentdrone-swarmgeminimlflowsqlite

Repo: mohd-vasim/ai-engineering → mas-formation-control

Five drones over a wheat field, holding a grid formation while a single tree stands in their path. A naive agent loop would treat the whole mission as one opaque LLM call chain — swarm size, formation choice, physics, and compliance review all blurred together. This project is the opposite: an explicit six-node LangGraph StateGraph where LLM decisions happen in exactly two nodes (planning and verdict), and every deterministic step — simulation, analysis, persistence — is a named, inspectable, typed node.

The Six-Node StateGraph

START → assess_mission → plan_swarm (Gemini) → dispatch_simulation → analyze_telemetry → persist_telemetry (SQLite) → generate_verdict (Gemini) → END

  • assess_mission — logs field dimensions, mission brief, and obstacle list.
  • plan_swarm — Gemini returns a structured SwarmDispatchPlan (3–8 drones, line/v_shape/grid, spacing 8–12 m, justification). Falls back to a deterministic 5-drone grid if the model is unavailable or fails.
  • dispatch_simulation — runs the decentralized physics simulation: 160 steps at 0.1 s, leader Drone_A at constant 2.5 m/s survey speed, followers steering from local sensing only.
  • analyze_telemetry — reduces 160 steps to three metrics (max deviation, final formation error, min clearance) and renders the trajectory plot.
  • persist_telemetry — writes the run to SQLite data/telemetry.db (run ID, formation, spacing, metrics, timestamp).
  • generate_verdict — Gemini audits the mission against a 5-stage FDS compliance rubric, returning a structured FDSVerificationVerdict. The fallback verdict applies the same thresholds programmatically (clearance > 3 m, final error < 2 m).

All state flows through a typed MissionState TypedDict — no globals, no hidden channels.

Decentralized Control Laws

Each follower drone carries only its neighbor ID, its designated offset from that neighbor, and local sensing. No drone knows the full swarm state:

  • Formation tracking — proportional correction toward neighbor_position + offset (, tolerance 0.2 m).
  • Obstacle avoidance — within radius + 3 m of an obstacle, a repulsion force plus a tangential term bends the path into an arc; avoidance forces outweigh formation error 7.5:1 while dodging.
  • Peer yielding (self-organization) — any peer within 4.5 m contributes a push-away force, guaranteeing inter-agent clearance.
  • Speed invariant — every velocity update clamps to 5 m/s in code, not by prompt.

Concretely: What a Run Looks Like

The planner reads a 100 m × 80 m wheat field with one tree obstacle at (20, 40) and decides the swarm geometry; the simulation executes it; the analysis plots per-drone trajectories against the tree hazard along with formation error over time (tolerance and safety lines drawn in); SQLite records the run; and the verdict node reports all five FDS stages as pass/fail with an executive summary. Every LLM call, tool call, and trace is autologged to a Databricks MLflow experiment — with a deliberate payload optimization: per-step logs carry only instantaneous position snapshots, and full trajectories are appended once at the end, so traces stay linear instead of quadratic.

Tech Stack

  • LangGraph StateGraph + InMemorySaver checkpointer — orchestration and short-term thread memory with step-by-step replay.
  • Google Gemini (gemini-3.5-flash-lite) — structured-output swarm planning and FDS compliance verdicts via Pydantic contracts.
  • Pydantic v2SwarmDispatchPlan, FDSStageVerdict, FDSVerificationVerdict; every model output validated at the boundary.
  • SQLite — persistent cross-session mission history, queryable with pandas.read_sql().
  • MLflow on Databricks — automatic tracing of all LLM calls and tool invocations.

How to Run

bash
git clone https://github.com/mohd-vasim/ai-engineering.git
cd ai-engineering/mas-formation-control
uv sync

# .env
GEMINI_API_KEY=...
MLFLOW_TRACKING_URI=databricks
MLFLOW_EXPERIMENT_ID=3192447675404693
DATABRICKS_HOST=...
DATABRICKS_TOKEN=...

Run the notebook notebooks/formation_control_poc_v2.ipynb top to bottom. Without a Gemini key the graph still completes every mission using deterministic fallbacks — an LLM outage degrades the run, it never crashes it.

Status

Working end-to-end. The graph has been run repeatedly, with each mission accumulating rows in data/telemetry.db for cross-run comparison. Next steps I'd want:

  • Durable checkpointerInMemorySaver dies with the process; a Postgres or file-backed checkpointer would make missions resumable across restarts.
  • Multi-obstacle missions — the course is currently a single static tree; dynamic obstacles would exercise the adaptation stage harder.
  • Leader failover — the formation follows Drone_A; designating a second leader enables formation continuation if the lead drone is lost.
  • Verdict post-processingmission_ok is inserted as a placeholder; backfilling it from the verdict closes the loop between the DB and the compliance report.