Soy Carlos, estudiante de Diseño de Software en la Universidad Nacional de Catamarca, Argentina. Este post cuenta cómo construí FaroIQ durante el Microsoft Agents League 2026, qué decisiones tomé, por qué las tomé, y qué problemas encontré en el camino.


De dónde vino la idea

Crecí en San Juan, Argentina, viendo a organizaciones como Cáritas recolectar donaciones a través de escuelas y universidades. Siempre me pareció que el problema no era la falta de voluntad sino la falta de herramientas. Esas organizaciones saben perfectamente qué necesitan sus comunidades. Lo que les falta es una forma de convertir ese conocimiento en algo concreto: un plan con datos, fases y presupuesto.

Cuando empezó el hackathon, quería construir algo que resolviera eso. No una demo de tecnología. Algo que, si alguien lo usara, le sirviera de verdad.

La idea fue esta: el usuario describe su organización en lenguaje natural, y el sistema produce en menos de 90 segundos un análisis de necesidades, un plan de implementación por fases, proyecciones de impacto, una propuesta de financiamiento lista para presentar, y ejecuta todo eso en Microsoft 365 (Calendar, To Do, OneDrive, Email) de forma automática.


Qué es FaroIQ

FaroIQ es una plataforma de inteligencia comunitaria construida sobre las tres capas de Microsoft IQ:

  • Foundry IQ: Azure AI Foundry con el modelo gpt-oss-120b para el razonamiento de los agentes
  • Fabric IQ: Azure Blob Storage para persistencia de sesiones y analytics agregados
  • Work IQ: Microsoft 365 via Azure Logic Apps para la ejecución

El nombre viene de la palabra faro. No hay mucho más que explicar ahí.


La arquitectura

Por qué un pipeline secuencial y no agentes paralelos

Una de las primeras decisiones fue cómo estructurar los nueve agentes. Había dos opciones obvias: correrlos en paralelo para reducir el tiempo total, o en secuencia donde cada uno recibe el output de los anteriores como contexto.

Opté por la secuencia. El razonamiento fue que un plan de acción coherente requiere que cada etapa construya sobre la anterior. Si el agente de Planificación no sabe qué necesidades identificó el de Análisis, o qué capacidad de recursos estimó el de Clasificación, termina generando algo genérico. Con el encadenamiento de contexto, cada agente recibe el output estructurado de todos los anteriores más su propio system prompt y un schema JSON que define exactamente qué tiene que devolver.

AgenteQué hace
InvestigaciónBúsqueda web en vivo con Tavily para estadísticas reales y programas comparables
ClasificaciónClasifica sector, urgencia, población objetivo y capacidad de recursos
AnálisisIdentifica necesidades primarias, causas raíz y fortalezas existentes
PlanificaciónGenera plan por fases con hitos, victorias rápidas y factores de riesgo
EvaluaciónProyecta beneficiarios, puntaje de factibilidad y resultados esperados
CríticaRevisa el output completo y activa revisión automática si la calidad cae por debajo de 0.70
EjecuciónConstruye los payloads para Microsoft 365 y activa los Logic Apps
SubsidioRedacta una propuesta de financiamiento completa
ConsultaAgente conversacional con todo el análisis como contexto, puede re-ejecutar agentes si cambian las restricciones

Todos los agentes usan AsyncAzureOpenAI contra el endpoint de Azure AI Foundry. Cada evento (inicio, progreso, completion) se transmite al frontend en tiempo real via WebSocket, así el usuario ve el pipeline ejecutarse en lugar de esperar una pantalla en blanco.

El bucle de revisión autónoma

Esto fue lo que más me costó pensar bien. Después de que el Evaluator termina, el agente Critique puntúa el output completo entre 0.0 y 1.0. Si el puntaje cae por debajo de 0.70, el sistema no le pregunta al usuario qué hacer. Inyecta el feedback del Critique como contexto adicional y re-ejecuta el Planner y el Evaluator con esas observaciones incorporadas. Hasta dos ciclos.

La decisión de poner el límite en dos fue pragmática: un tercer ciclo rara vez mejoraba el resultado de forma significativa, y el tiempo total ya era cercano a los 90 segundos. Más de dos revisiones empezaba a verse como un loop que el usuario no podía predecir.

En la UI, el usuario puede ver el puntaje de calidad, el número de ciclos completados, las brechas críticas identificadas y las recomendaciones específicas. Hay un panel expandible que muestra exactamente qué detectó el Critique y por qué decidió revisar. Transparencia total sobre lo que el sistema hizo y por qué.

Fabric IQ: por qué persistir todo

Desde el principio quise que los análisis sobrevivieran más allá de la sesión del browser. No tiene sentido que una ONG pierda un análisis porque cerró la pestaña o porque la conexión se cayó en iOS (más sobre eso después).

Cada análisis completado se guarda como JSON estructurado en Azure Blob Storage bajo el contenedor faroiq-lakehouse. Cada sesión tiene un código de 8 caracteres derivado del UUID, lo que permite recuperarla sin necesidad de autenticación. Un segundo contenedor llamado reports almacena la versión HTML renderizada del reporte como URL pública permanente.

El Intelligence Dashboard agrega datos de todas las sesiones: distribución por sector, puntajes de factibilidad promedio, tendencias de urgencia, proyecciones acumuladas de beneficiarios. Esto transforma análisis individuales en algo más útil a largo plazo.

Work IQ: ejecución en Microsoft 365

Cuatro Azure Logic Apps conectan el sistema a Microsoft 365:

  • Calendar: crea eventos de Outlook para cada fase del plan
  • To Do: genera listas de tareas con el nombre de la organización como prefijo, por ejemplo [Cáritas San Juan] Fase 1: Diagnóstico
  • OneDrive: guarda el reporte HTML en /FaroIQ Reports
  • Email: entrega el análisis completo via Outlook

Todos los calls a los Logic Apps se ejecutan como tareas async en el backend para no bloquear la respuesta de la API. Si alguno falla, se loguea pero no aparece como error para el usuario, porque las integraciones de M365 son secundarias al análisis principal.

También hay un Declarative Agent manifest en /teams-plugin/appPackage/ para despliegue en Microsoft 365 Copilot en entornos enterprise, con instrucciones de razonamiento en nueve pasos y seis conversation starters en inglés y español.


Las partes difíciles

El diseño tardó más de lo esperado

Subestimé cuánto tiempo iba a llevar la interfaz. Hay mucha información que mostrar: el visualizador del pipeline con los estados de cada agente, el panel de revisión autónoma, el reporte completo con tabs, los paneles de critique, el chat, las integraciones de M365. Encontrar la jerarquía visual correcta para que todo eso tenga sentido sin abrumar al usuario llevó bastante iteración.

El fondo del faro en Three.js fue un caso aparte. Modo día y modo noche renderizan escenas completamente distintas: torre crema con luz solar en día, azul oscuro con campo de estrellas y rayo volumétrico en noche. Al principio intenté mutar la escena al cambiar el tema, pero Three.js no limpia bien ese estado. Terminé forzando un remount completo via una key prop en React cada vez que cambia el tema. Es la solución más directa y funciona sin efectos extraños.

Evitar que los agentes inventen datos

Uno de los requisitos que me puse desde el principio fue que el sistema no podía devolver estadísticas inventadas. Si una ONG toma decisiones basándose en este análisis, los datos tienen que venir de algún lado verificable.

Por eso el primer agente hace búsqueda web en vivo con Tavily antes de que arranque el resto del pipeline. Los resultados se truncan a 3.000 caracteres para no explotar el token budget de los agentes siguientes, pero preservan la información relevante. El Analyzer y el Planner tienen acceso a esos datos reales desde el primer paso.

WebSocket e iOS

Mantener una conexión WebSocket abierta durante 60 a 90 segundos tiene sus problemas. En iOS, tanto Safari como Chrome usan WebKit, que tiene límites de conexión más agresivos que desktop o Android. La conexión se cierra antes de que el pipeline termine.

Resolví esto en capas. Primero, un ping keepalive cada 8 segundos para mantener la conexión activa. Segundo, el backend envía el session_id al frontend antes de que empiece el pipeline, así el usuario tiene el código de sesión desde el primer segundo. Si la conexión cae, el pipeline sigue corriendo en el servidor y el usuario puede recuperar el análisis completo ingresando ese código en la página de Session Lookup. Tercero, un componente ErrorBoundary muestra el código de sesión en cualquier estado de error para que nunca se pierda.

No hay una solución perfecta para iOS sin refactorizar todo el streaming a Server-Sent Events o polling, que implicaba reescribir partes importantes del backend. La solución actual cubre el caso de uso sin romper nada.


Lo que me sorprendió al correrlo por primera vez

Esperaba que el pipeline generara algo útil. No esperaba el nivel de detalle que lograba cuando los agentes tenían buena información de entrada.

La primera vez que corrí un análisis sobre una ONG real, el output tenía actividades específicas por fase, hitos medibles, factores de riesgo con sus mitigaciones, una propuesta de financiamiento con teoría del cambio y plan de sostenibilidad, y proyecciones de impacto con intervalos de confianza. Nada de eso estaba hardcodeado. Venía del encadenamiento de contexto entre los nueve agentes.

Ahí entendí que la complejidad de hacer el pipeline secuencial en lugar de paralelo tenía sentido.


Stack completo

Backend: Python 3.12 · FastAPI · uvicorn · AsyncAzureOpenAI · azure-storage-blob · Tavily

Frontend: React 18 · TypeScript · Vite · Three.js · WebSocket

Infraestructura: Railway (backend, plan Hobby) · Vercel (frontend) · Azure Blob Storage · Azure Logic Apps · Azure AI Foundry

Integraciones: Microsoft 365 (Calendar, To Do, OneDrive, Email) · Microsoft 365 Copilot (Declarative Agent)


Cierre

Terminé el hackathon con 227 commits, un deploy en producción, sesiones reales de organizaciones reales, un README con screenshots de cada funcionalidad, un video de demo y la submission entregada.

Cuando vi el visualizador del pipeline corriendo en tiempo real, el panel de revisión expandible con el razonamiento del agente Critique, la propuesta de financiamiento generada en segundos, y las tareas apareciendo en Microsoft To Do de forma automática, me di cuenta de que había construido algo que funciona de principio a fin.

Participé en el Microsoft Agents League 2026 en el track de Reasoning Agents. No gané, pero el proyecto quedó deployado, funciona, y cualquier ONG que llegue a él puede usarlo hoy. Eso me parece suficiente razón para haberlo construido.



Microsoft Agents League 2026 · Reasoning Agents Track · Hack for Good