Saltar a contenido

Últimos Artículos

En esta sección voy publicando todos mis experimentos, reflexiones técnicas y arquitecturas, ordenados cronológicamente del más reciente al más antiguo.

Fundamentos de un Agente y Gestión de Estado

Llevo tiempo diseñando sistemas donde la Inteligencia Artificial pasa de ser un simple loro estocástico a algo que realmente hace cosas. La diferencia técnica entre mandar una petición a una API y construir un agente no es trivial.

Para dummies: El bucle de decisión

En términos de marketing, te dirán que un agente de IA "razona y toma decisiones autónomas". Si bajamos esto a la realidad de la ingeniería, un agente no es más que un patrón de diseño. Concretamente, un bucle while.

Un script tradicional ejecuta pasos de forma secuencial: lee de base de datos, transforma, escribe. Un agente evalúa el estado actual, decide qué herramienta usar (si necesita alguna), ejecuta la herramienta, observa el resultado y vuelve a evaluar. Sigue atrapado en este ciclo de razonamiento (ReAct: Reason + Act) hasta que determina que tiene la respuesta final o hasta que choca con un límite de iteraciones. No hay magia, hay una máquina de estados determinista gobernando llamadas no deterministas.

Memoria: El problema del contexto

He visto a muchos programadores atascar la ventana de contexto de un LLM a la primera de cambio. Meten todo el historial de conversación, todos los logs, el esquema entero de la base de datos, y luego se sorprenden cuando el modelo alucina o la API les cobra una barbaridad.

Un agente en producción necesita memoria a corto y largo plazo. - Corto plazo: El contexto de la tarea actual. Qué intentamos resolver ahora mismo. - Largo plazo: Conocimiento almacenado en bases de datos vectoriales u otros sistemas persistentes.

La técnica real aquí es el windowing o resumen progresivo. No le pasas al agente los 50 últimos mensajes. Le pasas los últimos 3, y un resumen comprimido de los 47 anteriores.

Ejemplo Práctico: Un agente mínimo con retención controlada

Vamos a ver un esqueleto en Python de cómo estructurar un agente usando un enfoque de grafo (algo similar a lo que hace LangGraph, que me ha salvado la vida en más de un despliegue pesado).

import operator
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage

# Definimos el estado global del agente.
# Annotated con operator.add indica que los mensajes se concatenan, no se sobrescriben.
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    summary: str

def agent_node(state: AgentState):
    """
    El nodo principal de decisión.
    Aquí llamaríamos al LLM pasándole el resumen y los mensajes recientes.
    """
    # Filtramos para quedarnos solo con los últimos 3 mensajes
    recent_messages = state["messages"][-3:]
    context = f"Resumen previo: {state.get('summary', 'Sin contexto previo.')}"

    # Simulación de la respuesta del modelo
    response = AIMessage(content=f"Evaluando con contexto: {context}. Acción decidida.")

    return {"messages": [response]}

def memory_manager_node(state: AgentState):
    """
    Este nodo se encarga de evitar que el contexto explote.
    Si hay más de 5 mensajes, comprime los antiguos en un resumen.
    """
    messages = state["messages"]

    if len(messages) > 5:
        # Aquí llamaríamos a un modelo ligero para resumir.
        new_summary = "El usuario pidió una tarea y el agente empezó a investigar."
        # Nos quedamos con el resumen y purgamos los mensajes viejos
        # Devolviendo una estructura que nuestra máquina de estado entienda como un "reinicio" de la lista
        return {"summary": new_summary, "messages": messages[-2:]}

    return state

# El flujo real (simplificado) sería:
# 1. agent_node()
# 2. ejecuta_herramienta() si aplica
# 3. memory_manager_node() para mantener limpio el contexto
# 4. Repetir hasta terminar

Estructurar el estado de forma explícita es lo que te salva de que el agente se pierda en su propio ruido. No dependas de que la librería gestione el contexto por debajo. Hazlo tú. Así es como mantienes el control cuando el sistema empieza a crecer.

Gobernanza y Guardrails en Producción

Integrar IA en el ciclo de vida de desarrollo de software (SDLC) no consiste solo en empujar código a main y rezar para que el agente no borre el servidor de base de datos. Requiere barreras de seguridad inflexibles. Si no puedes auditar por qué un agente tomó una decisión, no deberías ponerlo en producción.

Para dummies: La tarjeta de crédito del bot

Piensa en esto como darle a un becario la tarjeta de crédito de la empresa. No le das acceso ilimitado el primer día. Le pones un límite de gasto de 50 euros, configuras alertas por SMS para cada transacción y, si intenta comprar algo que cueste más, el sistema bloquea la compra hasta que un mánager la aprueba.

En el desarrollo de agentes, esto se llama guardrails y human-in-the-loop (humano en el bucle). Consiste en establecer reglas estrictas (como "jamás ejecutar un comando que contenga la palabra DROP") e interceptar acciones peligrosas para que un operador humano valide la intención del agente antes de apretar el gatillo.

Aislamiento y Artefactos Inspeccionables

Me he encontrado infraestructuras enteras comprometidas porque un agente tenía demasiados permisos. La regla de oro es el principio de menor privilegio. Si el agente solo necesita leer logs, su rol de AWS no debería permitirle levantar instancias EC2.

Además, el agente debe producir artefactos inspeccionables. No me vale un "tarea completada" en la terminal. Quiero un archivo de plan detallado o un volcado de logs donde pueda ver exactamente qué herramientas invocó y con qué argumentos.

Ejemplo Práctico: Interceptando una acción destructiva

Vamos a simular un guardrail que detiene la ejecución y exige aprobación humana si el agente intenta usar una herramienta de base de datos para borrar registros.

import sys

def ejecutar_sql(query: str, auto_aprobacion: bool = False) -> str:
    """
    Herramienta simulada de base de datos con interceptor human-in-the-loop.
    """
    # Detectamos acciones potencialmente destructivas
    palabras_peligrosas = ["DROP", "DELETE", "TRUNCATE", "ALTER"]
    es_peligrosa = any(p in query.upper() for p in palabras_peligrosas)

    if es_peligrosa and not auto_aprobacion:
        print(f"\n[ALERTA GUARDRAIL] El agente intenta ejecutar: {query}")
        respuesta = input("¿Apruebas esta operación destructiva? (s/N): ")

        if respuesta.lower() != 's':
            # Devolvemos el rechazo al agente para que busque otra estrategia
            return "Error: Permiso denegado por el usuario humano. Busca otra alternativa."

    # Si es segura o fue aprobada, procedemos
    return f"Éxito: Se ejecutó '{query}' en la base de datos."

# Simulación de un agente intentando limpiar una tabla
intento_agente = "DELETE FROM usuarios WHERE activo = 0;"

resultado = ejecutar_sql(intento_agente)
print(f"Resultado devuelto al agente: {resultado}")

Este es un mecanismo primitivo pero efectivo. En sistemas reales, esta aprobación se hace mediante eventos asíncronos que llegan a Slack o Teams, permitiendo a los ingenieros de guardia aprobar o rechazar con un solo clic. La autonomía total está sobrevalorada; el control determinista es lo que te deja dormir tranquilo.

Productividad artificial y la deuda técnica

En los últimos dos años, el tejido empresarial global ha sucumbido a una narrativa de optimismo radical respecto a la Inteligencia Artificial Generativa (GenAI). Impulsadas por la promesa de una automatización sin precedentes y reducciones drásticas de costes operativos, múltiples organizaciones implementaron mandatos corporativos verticales ("top-down") para forzar la adopción de la IA en todas sus áreas, con especial énfasis en el desarrollo de software y la generación de contenidos. Sin embargo, los mercados y los comités ejecutivos continúan subestimando un factor crítico que amenaza con desestabilizar la infraestructura digital corporativa: el problema del "AI slop" (código y contenido basura generado por IA) y la acumulación acelerada de deuda técnica.

Yo mismo he visto cómo se han ejecutado UPDATEs en PRO escritos con ChatGPT. Que sí, que fueron bien, pero las corporaciones no son conscientes del riesgo que lleva confiar tanto en la IA.

La adopción de herramientas de IA bajo la premisa de que pueden sustituir de inmediato el criterio humano o reemplazar a los desarrolladores de software está demostrando ser un intercambio peligroso. Muchas empresas están canjeando un pico de productividad aparente a corto plazo por problemas estructurales graves a largo plazo.

El caso OpenClaw: una advertencia desde las trincheras

La brecha entre la percepción del mercado y la realidad operativa ha comenzado a manifestarse en testimonios de los propios creadores de estas tecnologías. Recientemente, los ingenieros principales detrás del agente de IA OpenClaw lanzaron una advertencia explícita sobre los riesgos de confiar ciegamente en estos sistemas para la escritura de código. Mario Zechner, creador de Pi (el entorno agéntico dentro de OpenClaw), señaló que los sistemas supuestamente capaces de reemplazar a ingenieros de software cualificados están inundando los repositorios globales con código defectuoso, redundante y, en última instancia, peligroso.

Según Zechner, la industria se enfrenta actualmente a infraestructuras digitales que comienzan a fragmentarse y a software significativamente más inestable ("buggy") que el producido hace unos años. El diagnóstico es severo: las empresas pueden sostener esta dinámica durante unos meses o quizás un par de años, pero los efectos residuales terminarán por manifestarse en interrupciones masivas del servicio, brechas de seguridad severas y apagones sistémicos.

La paradoja del talento y la deuda técnica

El argumento financiero original en favor de la GenAI en el desarrollo de software sugería que estas herramientas harían tan productivos a los ingenieros senior que las empresas podrían prescindir del talento junior. No obstante, esta estrategia introduce dos fallas sistémicas estructurales:

  1. Compromiso de la mitigación del error: Las deficiencias intelectuales intrínsecas de la GenAI (alucinaciones, falta de comprensión del contexto profundo y repetición de patrones obsoletos) introducen fallas sutiles en los productos de trabajo. Paradójicamente, la automatización masiva erosiona la experiencia organizacional y el sentido crítico necesarios para detectar y mitigar dichas fallas.

  2. Ruptura de la línea de sucesión de conocimiento: Al eliminar las posiciones junior, las empresas secan el flujo de talento futuro. Sin ingenieros junior que aprendan cometiendo errores controlados, no habrá ingenieros senior en el futuro capaces de auditar y corregir el código complejo generado por las máquinas.

El retorno a la cautela: del mandato general a la evaluación caso por caso

Esta acumulación de ineficiencias, a menudo denominada "productivity drag" o freno de productividad, ya está forzando un cambio de rumbo en sectores altamente digitalizados. Publicaciones como el Wall Street Journal han documentado cómo grandes corporaciones, particularmente en el sector de medios y tecnología, que inicialmente impusieron el uso de la IA de forma obligatoria, han tenido que retroceder estratégicamente. En la actualidad, estas firmas han relegado el uso de la IA a una recomendación sujeta a evaluación caso por caso.

El motivo de este retroceso no es la falta de capacidades de la tecnología, sino el coste oculto de revisar, corregir y mantener el "slop" generado. Cuando el tiempo dedicado por un ingeniero senior a depurar y reescribir el código defectuoso de una IA supera el tiempo que le habría tomado escribirlo desde cero, el Retorno de Inversión (ROI) prometido se desploma.

Una asunción mal calculada en los mercados

Existe una desconexión fundamental entre las valoraciones de mercado y la viabilidad técnica real de la IA autónoma a gran escala. Tecnólogos, consultores e inversores han promovido la idea de que las debilidades actuales de la GenAI son transitorias y se resolverán con la próxima iteración del modelo. Sin embargo, los límites actuales no son de potencia de cómputo, sino de arquitectura cognitiva.

La IA generativa está demostrando una sólida utilidad y retornos reales en tareas acotadas y de baja responsabilidad (automatización de plantillas, resúmenes preliminares o soporte técnico de primer nivel). No obstante, para que la tecnología escale de manera segura y libere el verdadero potencial que los inversores esperan, las empresas deben abandonar el optimismo ciego.

La sostenibilidad tecnológica del futuro dependerá de una gobernanza estricta, donde la IA sea tratada como un asistente de copiloto altamente supervisado y nunca como un sustituto del juicio experto y la formación del talento humano. Ignorar esto es diseñar arquitecturas destinadas a colapsar bajo el peso de su propia deuda técnica.

Integración de Herramientas y el Protocolo MCP

Un modelo fundacional puro, por muy avanzado que sea, vive en una burbuja. No sabe qué hora es, no puede consultar el inventario de tu base de datos y no puede desplegar código. Para que un agente interactúe con el mundo, necesita herramientas.

Para dummies: Brazos robóticos para cerebros digitales

En el mundo corporativo te hablarán de "orquestación de microservicios mediante capacidades cognitivas ampliadas". En código, esto se traduce en darle al LLM acceso a funciones específicas de tu sistema.

Imagina que el LLM es un cerebro brillante metido en un tarro. MCP (Model Context Protocol) es la API estándar que le enchufa brazos robóticos a ese tarro. Antes, cada proveedor de modelos tenía su propio formato privativo para llamar a funciones externas. Ahora, MCP estandariza cómo un modelo descubre y ejecuta herramientas, independientemente de si estás usando OpenAI, Anthropic o un modelo local.

El problema de las herramientas a medida

He lidiado con docenas de implementaciones donde los programadores crean wrappers gigantescos para cada endpoint de su API solo para que el LLM lo entienda. Eso escala fatal. Si cambias el contrato de la API, el agente se rompe y empieza a alucinar parámetros.

Adoptar MCP te obliga a pensar en tus herramientas como servidores independientes. El agente actúa como cliente MCP, consulta qué herramientas están disponibles en el servidor y luego pide ejecutar una de ellas pasándole un JSON estandarizado.

Ejemplo Práctico: Un servidor MCP básico

Vamos a ver cómo levantar un servidor MCP mínimo en Python usando el SDK oficial. Este servidor expone una herramienta para leer el contenido de un archivo local.

from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.types as types
import mcp.server.stdio
import os

# Inicializamos el servidor con un nombre identificativo
server = Server("mi-servidor-local")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """
    Le dice al agente qué herramientas tenemos disponibles.
    """
    return [
        types.Tool(
            name="leer_archivo",
            description="Lee el contenido de un archivo de texto en disco.",
            inputSchema={
                "type": "object",
                "properties": {
                    "ruta": {"type": "string", "description": "Ruta absoluta al archivo"}
                },
                "required": ["ruta"]
            }
        )
    ]

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """
    Ejecuta la herramienta solicitada por el agente.
    """
    if name == "leer_archivo":
        ruta = arguments.get("ruta")
        if not ruta or not os.path.exists(ruta):
            return [types.TextContent(type="text", text="Error: Archivo no encontrado.")]

        try:
            with open(ruta, 'r', encoding='utf-8') as f:
                contenido = f.read()
            return [types.TextContent(type="text", text=contenido)]
        except Exception as e:
            return [types.TextContent(type="text", text=f"Error leyendo el archivo: {str(e)}")]

    raise ValueError(f"Herramienta desconocida: {name}")

async def main():
    # El servidor se comunica con el agente a través de la entrada/salida estándar (stdio)
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="mi-servidor-local",
                server_version="1.0.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                )
            )
        )

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

Este enfoque aísla los permisos. Puedes correr este script en un entorno restringido donde solo tenga acceso de lectura a una carpeta específica, sin preocuparte de que el agente en sí intente hacer algo extraño con el sistema operativo de la máquina principal. Así es como aseguras despliegues reales.

Coordinación Multi-agente y Evaluación

Cuando intentas que un solo modelo de lenguaje escriba código, consulte la base de datos, mande correos y analice datos financieros todo a la vez, el fracaso está garantizado. La tasa de alucinaciones se dispara y el prompt de sistema se vuelve un monstruo inmanejable. La solución es dividir para vencer.

Para dummies: El fin del empleado orquesta

Si diriges una empresa, no contratas a una sola persona para que sea el contable, el programador, el conserje y el jefe de ventas simultáneamente. Es un desastre esperando a ocurrir. Creas departamentos y pones a un mánager para que coordine.

En IA, esto se llama arquitectura multi-agente. En lugar de un "agente orquesta" sobrecargado, despliegas varios agentes especialistas. Uno sabe buscar información, otro sabe redactar y un agente supervisor decide a quién encargarle qué. Se pasan el estado entre ellos hasta que el supervisor determina que el trabajo está hecho.

Patrones de coordinación

He probado desde estructuras jerárquicas estrictas hasta mercados de agentes donde "pujan" por tareas. Al final, lo que mejor funciona en producción es el patrón de Supervisor-Trabajador (Routing). El usuario habla con el supervisor, el supervisor delega en el trabajador A, recibe el resultado, se lo pasa al trabajador B para que lo revise, y te devuelve la respuesta.

El reto principal aquí es la evaluación. ¿Cómo sabes que el agente "Redactor" no se ha inventado los datos que le pasó el "Investigador"? La respuesta es LLM-as-a-judge o evaluaciones basadas en aserciones rígidas en tu pipeline de CI/CD.

Ejemplo Práctico: Un grafo de Supervisor y Especialistas

Imagina que usamos un motor de grafos para orquestar la delegación. En vez de poner todo el código de fontanería, veamos la estructura de toma de decisiones del supervisor:

from typing import TypedDict, Literal

class MultiAgentState(TypedDict):
    task: str
    draft: str | None
    research_notes: str | None
    next_agent: str

def supervisor_node(state: MultiAgentState) -> dict:
    """
    El supervisor decide quién tiene que actuar a continuación.
    """
    if not state.get("research_notes"):
        # No hay datos, mandamos al investigador
        return {"next_agent": "Investigador"}

    if not state.get("draft"):
        # Hay datos pero no hay borrador, mandamos al redactor
        return {"next_agent": "Redactor"}

    # Si tenemos borrador y notas, asumimos que hemos terminado
    # En un sistema real, aquí habría un agente 'Evaluador' que revisa la calidad
    return {"next_agent": "FIN"}

def investigador_node(state: MultiAgentState) -> dict:
    """Simula al agente investigador"""
    notas = f"Datos encontrados sobre: {state['task']}..."
    return {"research_notes": notas, "next_agent": "Supervisor"}

def redactor_node(state: MultiAgentState) -> dict:
    """Simula al agente redactor"""
    texto = f"Basado en las notas ({state['research_notes']}), redacto este texto."
    return {"draft": texto, "next_agent": "Supervisor"}

# El sistema encolaría estos nodos basándose en el valor de "next_agent".
# Supervisor -> Investigador -> Supervisor -> Redactor -> Supervisor -> FIN

Este diseño te permite cambiar el modelo del "Investigador" por uno más barato o más rápido sin afectar a la calidad del "Redactor". Aísla los problemas, que es exactamente lo que buscas cuando pasas de un prototipo a un sistema robusto y auditable.

Antigravity 2.0: La evolución hacia el desarrollo "Agent-First"

Acaban de presentar Antigravity 2.0 y quizás la noticia marque un punto de inflexión en la forma en que los ingenieros y arquitectos de software interactúan con la Inteligencia Artificial. Ha dejado de ser un simple "autocompletador de código" o un IDE tradicional vitaminado, para convertirse en un centro de mando y orquestación de agentes autónomos impulsado por el modelo Gemini 3.5 Flash.

Traduciendo "agente" a lenguaje de desarrollador

Antes de entrar en profundidad, si llevas años escribiendo código y la terminología de IA te parece humo de marketing, te lo bajo a tierra.

Olvídate de la palabra "agente". Piensa en ello como una función o un microservicio no determinista. En la programación clásica, escribes una función que recibe A, ejecuta una serie de pasos fijos y devuelve B. Si algo se sale del guion, el código revienta y lanza una excepción.

Un "agente" es simplemente un bucle de ejecución (un while loop) donde el motor de decisión es un modelo de lenguaje. Le pasas un objetivo y le das acceso a un conjunto de herramientas (funciones estándar: leer un archivo, ejecutar un comando de terminal, lanzar una query a base de datos). El modelo decide qué herramienta usar, analiza el resultado que devuelve y decide el siguiente paso. Si falla, evalúa el error e intenta otra ruta hasta que resuelve el problema o agota sus iteraciones.

Desde esta perspectiva, Antigravity 2.0 no es magia. Es un orquestador. Funciona de manera muy parecida a un director de procesos o un message broker: levanta estos bucles en entornos aislados (para que no compartan ni contaminen la misma memoria), les asigna permisos específicos y coordina las salidas de unos como entradas de otros.

¿Para qué sirve exactamente?

Con la versión 2.0, Google separó la herramienta en un ecosistema enfocado en flujos de trabajo paralelos. Su premisa principal es que, gracias a las nuevas capacidades de razonamiento de los modelos, el cuello de botella ya no es escribir el código, sino la integración y arquitectura de sistemas complejos. Ya no escribes línea por línea, sino que defines objetivos, estableces restricciones de infraestructura y dejas que la IA haga el trabajo pesado.

El ecosistema se divide en estos pilares clave: 1. Desktop App Independiente: Una interfaz sin editor de texto puro, pensada para coordinar proyectos completos interactuando con equipos de agentes de manera síncrona y asíncrona. 2. Antigravity CLI (agy): Una herramienta de terminal de altísima velocidad que reemplaza al antiguo Gemini CLI, perfecta para ejecutar integraciones agentiles directas y conectarlas al CI/CD. 3. Subagentes Dinámicos y Tareas Programadas (Cron): Puedes delegar un problema grande para que el sistema lo fragmente dinámicamente, asignando subagentes aislados (para no sobrecargar su ventana de contexto) que trabajarán en paralelo o en segundo plano a determinadas horas. 4. Antigravity SDK: Librería oficial en Python que te permite gobernar esta orquestación mediante código, integrando servidores MCP (Model Context Protocol).

Antigravity vs. tu IDE (VS Code + Gemini Code Assist)

Si en tu día a día usas Visual Studio Code apoyado por Gemini Code Assist, quizás te preguntes dónde encaja esta nueva herramienta. La diferencia radica en quién tiene el volante.

En un editor clásico, tú eres el orquestador. Tienes el control, abres los archivos y le pides a la IA que te genere una función específica o te explique un error. La IA es reactiva. Espera tus instrucciones. Si el código falla al compilar, tú lees el error, tú decides la solución y le pides otra sugerencia.

Antigravity 2.0 funciona por delegación asíncrona. Le entregas un objetivo macro ("migra el esquema de users.db a PostgreSQL y actualiza las rutas del backend en Node"). A partir de ahí, el sistema lanza subagentes que abren archivos, tiran comandos de terminal, instalan dependencias y ejecutan tests. Si algo rompe, ellos mismos leen el volcado de memoria y corrigen su código hasta cumplir la tarea.

Dejas de escribir líneas para empezar a dirigir sistemas.

Un caso de uso real y práctico: Pipeline y Dashboard automatizado

Imagina que trabajas en operaciones de datos y te pasan un archivo desorganizado sales_dump.csv. Necesitas limpiarlo, cruzar los datos para sacar KPIs y montar un panel de visualización web interactivo para dirección.

En lugar de abrir el IDE, escribir el script de ETL en Pandas, luego programar el frontend en HTML/JS y conectar las dos partes, el flujo operativo con el CLI de Antigravity 2.0 es el siguiente:

  1. Abres tu terminal en la carpeta del proyecto.
  2. Lanzas el comando de objetivo (/goal):
    agy /goal "Analiza sales_dump.csv, limpia la data corrupta, extrae KPIs de ventas y constrúyeme un dashboard HTML/JS interactivo para visualizarlos."
    
  3. Orquestación en vivo: En este punto, el orquestador principal de Antigravity evalúa la tarea y crea subagentes dinámicos paralelos:
  4. Subagente A (Especialista Python): Explora los datos, lanza un script seguro en el entorno local, limpia el CSV y deja los resultados en un data.json curado.
  5. Subagente B (Especialista Frontend): Al mismo tiempo, estructura el HTML y configura las librerías gráficas (como Chart.js).
  6. Ensamblaje y Entrega: El orquestador verifica que el JSON generado por el Agente A se inyecte correctamente en el código del Agente B. Genera el entregable (Artifact) y levanta un servidor de pruebas en segundo plano para que veas el resultado.

Todo este ciclo se completa de forma autónoma, usando un contexto aislado para cada subagente.

Evolucionando proyectos existentes en la versión Desktop

Levantar proyectos desde cero está muy bien para las demos, pero en producción pasamos casi todo el tiempo leyendo y modificando código antiguo. Antigravity Desktop resulta útil precisamente cuando le tiras un repositorio legado.

Si ya tienes un proyecto construido, el proceso es directo. Abres la aplicación de escritorio y arrastras la carpeta local de tu repositorio. El sistema mapea los archivos y absorbe el contexto de tu arquitectura.

A partir de ahí, en vez de pedir código nuevo al aire, asignas un objetivo de mejora. Por ejemplo: "Abre el módulo de autenticación, elimina la validación JWT estática y monta un flujo con OAuth2. Ejecuta y actualiza los tests afectados".

¿Cómo gestiona esto la aplicación de escritorio bajo el capó? En lugar de saturar un único hilo de pensamiento, el orquestador principal utiliza herramientas integradas para definir e invocar subagentes especializados (mediante tool calls como define_subagent e invoke_subagent). De forma dinámica, el sistema descompone tu petición y lanza un equipo:

  • Agente Investigador: Nace con herramientas de solo lectura. Escanea tu base de código, capta tus convenciones y entiende tus dependencias de forma segura. Se adapta a tu código existente.
  • Agente Constructor: Recibe el contexto del investigador y tiene permisos de escritura en su propio espacio de trabajo aislado. No va a inyectar una librería aleatoria; aplica parches precisos.
  • Agente Tester: Toma el relevo asíncronamente, ejecuta los tests y, si algo falla, se comunica en segundo plano con el constructor para iterar la solución.

Todo esto ocurre sin que tengas que microgestionar las tareas. Al terminar, el sistema agrupa el trabajo y tú revisas el diff completo en la interfaz antes de volcar los cambios reales a tu disco. Cero saltos de fe, es revisión de código en estado puro.

La transición a este tipo de herramientas cambia el foco del "desarrollo de código" a la "dirección técnica". En arquitecturas de datos donde un fallo rompe procesos críticos, disponer de subagentes que no comparten el mismo hilo de memoria baja drásticamente la tasa de fallos. Pasas de ser el que pica la piedra a ser el que diseña el puente.

Por qué los flujos de trabajo de agente único están muertos

Si llevas más de un mes pegado a la interfaz de chat de Claude o ChatGPT y no has salido de ahí, tengo una mala noticia. Estás usando un solo agente cuando podrías estar ejecutando un equipo entero.

Vamos a bajar el hype a la tierra. Para los de marketing, un "agente autónomo" es magia que lee la mente. En términos de ingeniería real para los que picamos código, un agente único es un script monolítico inflado. Es meter todo el contexto, reglas, estado y objetivos en un solo prompt gigantesco, cruzar los dedos y rezar para que el modelo no pierda el hilo. Un equipo de agentes, por el contrario, es arquitectura de microservicios. Divides la carga, limitas el contexto por tarea y pasas estado estructurado (normalmente JSON) entre nodos especializados.

El problema de meter todo en el mismo saco es que los modelos de lenguaje diluyen su atención.

Ese 14% que tiras a la basura antes de empezar

Tienes tu proyecto. Tienes un archivo CLAUDE.md o GEMINI.md lleno de reglas globales. Convenciones, directrices, estilo. Lo metes en cada petición.

Antes de que escribas la primera palabra de tu prompt real, ya has quemado un porcentaje nada despreciable de la ventana de contexto. Hablo de un 10% a un 14% de "impuesto de atención". Le pides al modelo que averigüe por qué el recolector de basura de tu app en Go está fallando, pero al mismo tiempo tiene que mantener en memoria que debe "escribir en primera persona y no usar la palabra sinergia".

Es absurdo. Le exiges que sea analista, arquitecto, programador junior y corrector de estilo en el mismo ciclo de reloj.

La solución no son prompts más largos o detallados. El futuro son equipos de agentes.

La arquitectura que separa a los aficionados de los constructores

Los amateurs se dedican al mega-prompting. Escriben biblias de texto intentando cubrir todos los casos extremos.

Los que construyen de verdad asumen algo básico: el modelo va a fallar. Por diseño. Así que construyen arquitecturas basadas en orquestación y tolerancia a fallos. La estructura mínima viable que veo funcionar en producción se divide en cuatro partes:

  1. El que investiga: Tiene acceso de lectura. Busca en la base de datos vectorial, lee la documentación, revisa el código fuente. No escribe nada. Su output es un reporte puro.
  2. El que construye: Recibe el reporte. Su única directriz es escribir la implementación técnica. No sabe nada de convenciones de negocio, solo sabe hacer que el código funcione y cumpla el requerimiento.
  3. El que revisa: Tiene un prompt cínico y destructivo. Recibe el código generado, ejecuta el linter, pasa los tests y busca agujeros de seguridad. Si encuentra un fallo, rechaza el trabajo y se lo devuelve al constructor.
  4. El que orquesta: El router. Mantiene el estado del flujo, decide cuándo pasar de investigación a construcción y decide cuándo el código revisado está listo para hacer merge.

Las 3 propiedades de un equipo que sobrevive

Si intentas montar esto con un script básico de Python y bucles while, te vas a dar contra un muro. Un equipo de agentes de verdad necesita tres cosas para no colapsar:

  • Estado inmutable entre transiciones: El orquestador debe guardar la entrada y salida de cada agente de forma independiente. Si el revisor rechaza un cambio, el constructor necesita ver exactamente qué produjo antes y por qué falló, sin contaminar la memoria general.
  • Alcance limitado: El investigador jamás debe tener la herramienta de escribir archivos. El constructor jamás debe tener acceso a las variables de entorno de producción.
  • Criterio de parada determinista: Nada de "revisa hasta que te parezca correcto". Las condiciones de salida tienen que ser binarias. Los tests pasan o fallan. El linting devuelve 0 o 1. Si dejas la salida a la interpretación del LLM, acabarás en un bucle infinito gastando tokens.

Ejemplo práctico: Montando un equipo simple

No hace falta irse a frameworks complejos si quieres empezar. Aquí tienes un ejemplo crudo de cómo se ve esta separación en un pipeline de Python puro.

import json

def agente_investigador(query):
    # Prompt enfocado solo en buscar información
    system_prompt = "Eres un investigador. Devuelve un JSON con los archivos a modificar."
    # Llamada a la API del LLM simulada
    return {"archivos": ["main.py"], "contexto": "Falta manejar excepciones en DB."}

def agente_constructor(contexto):
    # Prompt enfocado solo en picar código
    system_prompt = "Eres programador. Usa el contexto para generar el parche."
    # Llamada a la API del LLM simulada
    return "try:\n    db.connect()\nexcept Exception:\n    log.error('Fallo de red')"

def agente_revisor(codigo):
    # Prompt enfocado en buscar fallos
    system_prompt = "Analiza el código. Devuelve 'OK' o el error."
    if "log.error" not in codigo:
        return "Falta logging"
    return "OK"

def orquestador_pipeline(tarea):
    print("Iniciando investigación...")
    contexto = agente_investigador(tarea)

    intentos = 0
    while intentos < 3:
        print(f"Construyendo (Intento {intentos + 1})...")
        codigo = agente_constructor(contexto)

        print("Revisando...")
        revision = agente_revisor(codigo)

        if revision == "OK":
            print("Pipeline completado con éxito.")
            return codigo

        print(f"Fallo en revisión: {revision}. Reintentando.")
        contexto["feedback_previo"] = revision
        intentos += 1

    raise RuntimeError("El equipo falló tras 3 intentos.")

orquestador_pipeline("Añadir manejo de errores en base de datos")

Dejar que un solo modelo cargue con todo el peso es cómodo para empezar, pero inútil para escalar. Abandona la ventana de chat.

Agent Payment Protocol (AP2): Pagos autónomos y seguros en la era de los agentes

Con el Protocolo de Pagos de Agentes (AP2), tu información de pago y datos permanecen privados y tus compras siguen siendo seguras, incluso cuando es un agente de Inteligencia Artificial quien realiza la transacción por ti.

Llevamos años diseñando flujos de pago (gateways, tokens, redirecciones a bancos) asumiendo una regla sagrada: hay un humano al otro lado de la pantalla haciendo clic en "Comprar". El auge de la IA ha roto esa asunción. Si un agente va a gastar tu dinero, el protocolo AP2 viene a ser la capa de confianza para que las transacciones ocurran sin intervención humana pero con tu permiso explícito.

AP2 para dummies (traducción para desarrolladores)

Si lees "Protocolo de Pagos de Agentes", probablemente pienses en una nueva API de Stripe o PayPal. No es exactamente eso.

En términos de ingeniería, AP2 no procesa el dinero directamente. Es un marco de trabajo, una capa de identidad y autorización compartida que se asienta por encima de MCP (Model Context Protocol). Funciona mediante la emisión de mandatos digitales. Piensa en un mandato como un JSON Web Token (JWT) vitaminado o un smart contract firmado criptográficamente por una Credencial Verificable (VC).

Cuando le pides a tu agente que compre algo, generas un "Mandato de Intención" (Intent Mandate). El agente lleva ese token al agente del comercio. El comercio verifica criptográficamente que las condiciones (presupuesto, producto) no han sido alteradas. Si hay match, se ejecuta un "Mandato de Carrito" (Cart Mandate) y se cierra el pago usando las pasarelas tradicionales (tarjetas, transferencias o stablecoins). En resumen: es un protocolo de consenso entre máquinas para evitar que una IA alucinada te vacíe la cuenta bancaria.

¿Cómo funciona AP2 bajo el capó?

La promesa de AP2 se sostiene en una arquitectura basada en límites y trazabilidad:

  1. Límites de seguridad estrictos (Intent Mandate): Todo comienza cuando estableces las reglas del juego. No le das acceso libre a tu tarjeta. Le dices a tu agente las marcas, los productos específicos que quieres y, lo más importante, cuánto puede gastar. Todo esto se encapsula en tu mandato inicial.
  2. Ejecución condicional (Match): Solo cuando el agente del comercio devuelve una oferta que cumpla exactamente esos parámetros firmados, tu agente completará automáticamente la transacción por ti. Si el vuelo cuesta 201€ y tu límite eran 200€, el mandato es inválido y la transacción aborta.
  3. Privacidad y mandatos a prueba de manipulaciones: La tecnología utiliza firmas criptográficas para preservar la privacidad de tus datos. Al usar estos mandatos digitales a prueba de manipulaciones, AP2 asegura que el agente (ya sea tuyo, del comercio, o del proveedor de pago) siempre actúe en tu nombre sin exponer tu tarjeta de crédito cruda por el camino.
  4. El rastro de papel digital (Accountability): Cada paso del proceso queda firmado y registrado. Obtendrás un rastro permanente y verificable. Si alguna vez necesitas hacer una devolución o hay una disputa por fraude, tú y el comerciante tienen el mismo registro criptográfico. Sabrás exactamente qué instrucción le diste a la máquina y qué respondió el comercio.

¿En qué se diferencia de la tokenización clásica o 3D Secure?

Es una duda lógica. Cuando los ingenieros escuchan hablar de AP2, la primera reacción suele ser: "¿Pero esto no lo hacen ya los network tokens de Stripe o el 3DS del banco?". La respuesta corta es no. Resuelven capas distintas del problema.

La tokenización (Apple Pay, PCI Vaults de Stripe) Su único trabajo es ofuscar el PAN (el número largo de tu tarjeta). Cambian el dato real por un identificador temporal. El problema es que un token no tiene "contexto de negocio". Si le das acceso a tu token a un agente y este alucina, puede ejecutar 50 cargos de 1.000€ seguidos. La tokenización protege contra el robo de datos, no contra el gasto no autorizado.

3D Secure (3DS2 y PSD2) Es un protocolo de autenticación humana. Su propósito es detener el proceso de pago, mandarte un SMS o abrir la app del banco para pedirte la huella dactilar (FaceID). Responde a la pregunta: "¿Eres tú el humano haciendo clic ahora mismo?". Si tu agente autónomo encuentra una oferta de un vuelo a las 4 de la madrugada mientras duermes e intenta comprarlo, 3DS bloqueará la transacción. El agente no puede leer tu SMS ni usar tu huella dactilar.

El hueco que cubre AP2 AP2 no reemplaza a los tokens ni a las pasarelas, los envuelve. Actúa como un sistema de delegación asíncrono. Tú firmas criptográficamente el "Intent Mandate" con tus reglas. Cuando el agente cierra el trato con la tienda, envía ese mandato junto al token de pago.

La pasarela de pagos usa el mandato del AP2 como prueba criptográfica irrefutable de que preautorizaste esa compra exacta. Esto permite a los bancos considerar la operación como "exenta de fricción", saltándose el desafío de 3DS (y el SMS a las 4 AM) sin incumplir las normativas de seguridad financiera.

Un ejemplo práctico: Comprando zapatillas en piloto automático

Imagina que necesitas unas zapatillas para correr muy específicas, pero no tienes tiempo de buscar ofertas durante la semana.

  1. La instrucción: Abres tu terminal o app y le dices a tu agente: "Encuéntrame unas zapatillas Nike Pegasus 40, talla 43, color blanco. Tienes permiso para comprarlas si el precio total con envío baja de 110€".
  2. El agente busca y negocia: Tu agente se conecta a internet y empieza a comunicarse mediante el protocolo A2A (Agent-to-Agent) con los agentes de distintas tiendas.
  3. Generación del Mandato: La tienda X le responde a tu agente con un precio de 105€. Tu agente valida que cumple tu Intent Mandate y emite el Cart Mandate firmado criptográficamente.
  4. Cierre de transacción: El protocolo AP2 verifica las credenciales de ambas partes. El agente de la tienda cobra los 105€ de tu wallet (usando tu token de pago seguro) y procesa el pedido.

Tú estabas durmiendo o trabajando. Cuando miras el móvil, tienes el recibo digital verificable y un correo con el número de seguimiento. Sin AP2, el riesgo de que el agente comprase tres pares por error, o que el comercio alterase el precio final, sería inasumible.

De cero a producción con MkDocs, GitHub y Vercel

Tras años gestionando entornos de datos, he decidido crear esta bitácora para documentar mis historias. Para ello, necesitaba una infraestructura robusta, automatizada y con aspecto profesional.

En este primer artículo detallo la arquitectura elegida y el paso a paso para montar este portal técnico, sorteando los bloqueos habituales de despliegue.


1. El Stack Tecnológico: ¿Por qué estas herramientas?

Para este proyecto, descarté los sistemas de gestión de contenido tradicionales (como WordPress) en favor de una arquitectura de Sitio Estático. He usado Wordpress muchas veces en el pasado, y quiero simpleza. El objetivo era coste cero, máxima velocidad y un control total mediante código.

MkDocs (con Material for MkDocs)

  • ¿Qué es? Es un generador de sitios estáticos escrito en Python. Coge archivos de texto simples (escritos en Markdown) y los transforma en una web completa (HTML/CSS).
  • ¿Por qué usarlo? Es el estándar de la industria para documentación técnica y APIs. El tema "Material" le da un aspecto corporativo inmediato, buscador integrado y un modo oscuro nativo, ideal para leer código. Al estar basado en Python, se integra perfectamente con las herramientas que usaré para IA. En mi día a día tanto personal como profesional, lo documento todo en Obsidian. Por lo que markdown es mi fiel amigo.

GitHub

  • ¿Qué es? Una plataforma de alojamiento para control de versiones utilizando Git. Es la "nube" donde guardo el código de mi web.
  • ¿Por qué usarlo? Me permite tener un historial exacto de todos los cambios, revertir errores si algo se rompe y, lo más importante, sirve como puente para automatizar la subida a internet.

Vercel

  • ¿Qué es? Una plataforma en la nube (PaaS) optimizada para alojar sitios web estáticos y frameworks de frontend.
  • ¿Por qué usarlo? Automatiza el despliegue (CI/CD). En lugar de alquilar un servidor, configurar Nginx o subir archivos por FTP, Vercel "escucha" a mi GitHub. Cuando detecta un cambio, él solo instala Python, compila la web y la distribuye por todo el mundo en unos 15 segundos.

2. El Paso a Paso: Construyendo la Infraestructura

Fase A: Entorno Local (Windows)

  1. Aislé el entorno creando la carpeta D:\fsrdata para evitar problemas con rutas largas en Windows (MAX_PATH).
  2. Instalé el framework usando Python:
    python -m pip install mkdocs-material
    
  3. Inicialicé el proyecto, lo que generó el archivo de configuración mkdocs.yml y la carpeta docs/ donde van los artículos:
    python -m mkdocs new .
    
  4. Creé el archivo requirements.txt y añadí mkdocs-material>=9.5.0 para estabilizar futuras instalaciones en la nube.

Fase B: Control de Versiones (GitHub)

  1. Creé un repositorio privado en GitHub llamado fsrdata.
  2. En local, configuré mis credenciales y subí el código inicial:
    git init
    git add .
    git commit -m "Arquitectura inicial"
    git branch -M main
    git remote add origin https://github.com/TU_USUARIO/fsrdata.git
    git push -u origin main
    

Fase C: Despliegue en la Nube (Vercel)

  1. Conecté mi cuenta de GitHub en Vercel.com y seleccioné el proyecto fsrdata.
  2. La corrección crítica (PEP 668): Vercel utiliza entornos Linux seguros que bloquean instalaciones globales de Python. Para solucionarlo, configuré el "Build Command" en Vercel de la siguiente manera:
    pip install -r requirements.txt --break-system-packages && mkdocs build
    
  3. Lancé el despliegue y Vercel generó la URL pública en menos de 20 segundos.

3. El Flujo de Trabajo Operativo (Git Flow)

Para no "romper producción", he implementado un ciclo de vida basado en dos entornos (ramas de Git).

Entorno de Desarrollo (La rama dev)

Aquí es donde experimento. Cuando escribo un borrador, me sitúo en esta rama (git checkout dev). Al subir los cambios (git push origin dev), Vercel genera una URL temporal y privada (Preview). Esto me permite auditar cómo se ve la web en internet sin que los usuarios reales vean el artículo a medio hacer.

Entorno de Producción (La rama main)

Es la versión pública y oficial de FSRdata. Cuando el artículo en la URL de prueba está perfecto, fusiono los cambios desde Visual Studio Code (git merge dev) y los subo a la rama principal (git push origin main). Vercel detecta el cambio y actualiza la web oficial al instante y sin tiempos de caída.

Y eso es todo amigos.