GEO_COPILOT: copiloto geoespacial con IA multiagente
Le preguntas en español y te responde con análisis PostGIS, capas en el mapa e imágenes de Sentinel-2. Seis agentes, y una persona que aprueba el SQL y el código antes de que corran.
LangGraph, PostGIS, HITL, Sentinel 2, MapLibre, Python, FastAPI, React

Créditos
Captura de pantalla de una versión anterior de GEO_COPILOT, con la pregunta por las estaciones de bomberos de Bogotá.
El detalle
GEO_COPILOT convierte una pregunta en lenguaje natural en un análisis espacial completo: descubre datos en servicios abiertos, escribe el SQL PostGIS, elige la simbología, corre operaciones espaciales en Python y calcula índices sobre imágenes de Sentinel-2.
Esos pasos se los reparten agentes especializados que LangGraph coordina, y la teledetección va por un servidor MCP aparte (MCP es el protocolo con el que un modelo usa herramientas externas).
Lo que más trabajo me dio está entre el modelo y tus datos: el SQL y el código que escribe el LLM no se ejecutan hasta que una persona los aprueba viendo el artefacto íntegro. El código corre en un contenedor aislado y sin red; el SQL, en una transacción de solo lectura con un rol que no es superusuario.
Está construido y funcionando, con 1.795 tests de backend que pasan en local; el repositorio se abre cuando alguien más pueda clonarlo y correrlo de principio a fin sin ayuda.
Características
- Seis agentes especializados:
- descubrimiento de datos, SQL PostGIS, simbología, operaciones espaciales en Python, insights y enrutamiento, coordinados con LangGraph
- Imágenes satelitales vía un servidor MCP propio: búsqueda de escenas, NDVI, cambio entre fechas y composiciones en color sobre Sentinel-2, con teselas servidas al mapa
- Human-in-the-Loop:
- el SQL, el código Python y el acceso a datos externos esperan aprobación; en el SQL y el código, el sistema compara la huella SHA-256 antes de ejecutar, así que corre exactamente lo que se aprobó
- El SQL del modelo corre con un rol de mínimos privilegios, dentro de una transacción de solo lectura
- El código Python del modelo corre en un contenedor aparte, sin red y de solo lectura
- Descubrimiento dinámico:
- lee en vivo el esquema de la base PostGIS y busca en servicios abiertos del IGAC, el DANE, el IDEAM y el SGC
- Mapa web con MapLibre GL:
- capas vectoriales, ráster y teselas, con simbología elegida por el agente
- Multi-LLM:
- OpenAI, Azure OpenAI y Anthropic
- WebSocket para el flujo de aprobación y las actualizaciones del mapa
- 1.795 tests de backend (74,8 % de cobertura), 464 de frontend y 28 E2E de navegador con Playwright, medidos en local el 8 de septiembre de 2026
Stack tecnológico
- Backend: FastAPI, LangGraph, asyncpg, Pydantic 2
- Frontend: React 18, Vite, MapLibre GL 5.x, Recharts, Zustand, Tailwind CSS
- Datos: PostgreSQL 18 + PostGIS, Redis 7
- Teledetección: STAC (Planetary Computer / Earth Search), rio-tiler, COG de Sentinel-2 L2A
- LLMs: OpenAI, Azure OpenAI, Anthropic
- Geo: GeoPandas, Shapely, GDAL/OGR
- DevOps: Docker Compose, Python 3.11, GitHub Actions con ruff, pytest y Vitest; Playwright en local
Lo difícil
- Que el SQL escrito por un modelo no pueda hacer daño. Hoy lo contienen la transacción de solo lectura y el rol sin privilegios; el validador sobre el árbol sintáctico ya registra lo que rechazaría, pero todavía no bloquea
- Que el humano apruebe exactamente lo que se va a ejecutar: el panel mostraba los primeros 500 caracteres y se ejecutaba la consulta completa
- Que la aprobación falle cerrada: si vence el plazo y nadie contesta, no se ejecuta (antes sí se ejecutaba)
- Coordinar a los agentes sin que la orquestación se vuelva un grafo que nadie puede seguir
- Corregir el sesgo del NDVI: desde la versión de procesamiento 04.00 (enero de 2022), el L2A de Sentinel-2 trae los valores con mil de más; en la resta del índice se cancela y en la suma cuenta doble, así que un NDVI de 0,67 salía en 0,47
- Probar un sistema no determinista sin volverse loco: separar lo que el modelo decide de lo que el sistema garantiza
Lo aprendido
- En un sistema agéntico, la seguridad vive en el rol de base de datos, en el contenedor y en el paso de aprobación
- Un control que falla abierto es peor que no tenerlo, porque además da confianza
- Enseñarle al modelo el patrón correcto en el prompt ayuda; impedir el incorrecto le toca al validador
- Por cada hallazgo de una auditoría adversa, primero el test que falla contra el código de ayer y después el arreglo
- Documentación que nadie mantiene vuelve a mentir en seis semanas; mejor archivar que maquillar
¿Quieres colaborar en este proyecto?
El repositorio todavía no es público. Si quieres colaborar, escríbenos desde la comunidad.