Harness engineering para agentes de IA
Más allá del modelo de lenguaje (LLM): qué convierte a un modelo en un agente
Durante meses hemos construido agentes como si todo girara alrededor del modelo. Incluso pensando que si el modelo no tiene más de X billones de parámetros es inservible para desplegarlo como un agente autónomo.
No es una locura. El modelo es lo más visible, lo que más mejora y lo que parece explicar el comportamiento.
Modelos más pequeños pueden comportarse como agentes autónomos útiles, pero no por el modelo en sí, sino por la infraestructura que los rodea.
Más allá del modelo: el harness
Un agente es más que solo un modelo de lenguaje. Está definido por el entorno en el que ese modelo se ejecuta. A ese entorno le llamamos harness.
Este entorno está compuesto por varias capas que hacen posible que el agente opere más allá de una llamada:
Estado inicial
Gestión de estado
Memoria persistente
Acceso a herramientas
Aislamiento por sesión o usuario
Routing de inputs y outputs
Políticas de ejecución
Recuperación tras fallos
Estas capas no son inherentes al modelo de lenguaje. Tampoco pertenecen necesariamente al prompt. Sin embargo, son las que determinan cómo evoluciona el sistema a lo largo del tiempo.
Para este experimento utilizamos Hermes Agent, desarrollado por Nous Research, como base. No como sistema final, sino como punto de partida sobre el que añadiremos más capas.
El experimento
Utilizamos Hermes Agent como base por dos razones: facilidad de despliegue y soporte nativo para múltiples canales de comunicación (Discord, Slack, Signal, WeChat, Telegram, WhatsApp). Esto nos permitió centrarnos en la capa operativa sin tener que construir el gateway desde cero.
Desde el inicio, el problema no era desplegarlo, sino el control del entorno de ejecución. En particular:
Aislamiento entre usuarios
Aislamiento entre agentes
Control explícito de estado
Prevención de acceso cruzado a memoria o recursos
Para resolver estos puntos, decidí añadir capas adicionales orientadas a definir fronteras claras para los usuarios de prueba y sus agentes.
La primera decisión fue separar el ambiente de ejecución (usuario) del perfil de cada agente. A nivel de usuario definimos los recursos disponibles, los servicios accesibles, las configuraciones compartidas y la red interna. A nivel de agente definimos la identidad, configuración, memoria y políticas de comportamiento.
Esto permite desplegar múltiples usuarios y múltiples agentes de forma controlada, evitando interferencias y manteniendo el estado aislado.
La segunda decisión fue cómo permitir que los agentes mejoren y se adapten con el tiempo. Para esto utilizamos Honcho, que gestiona la memoria de corto y largo plazo de forma aislada por agente. Esto permite que el agente evolucione a medida que interactúa con el usuario.
Adicionalmente, introdujimos un proceso de introspección en background. En periodos de inactividad, el agente puede revisar interacciones pasadas y evaluar cómo podría haber respondido mejor. Este proceso no es continuo ni global, y se controla de forma explícita.
La tercera decisión fue desacoplar las capacidades externas del agente. Servicios como búsqueda en internet, crawling o ejecución se tratan como infraestructura externa. El agente no contiene estas capacidades, solo define cómo utilizarlas. Esto permite modificar la infraestructura sin afectar directamente a los agentes.
La cuarta decisión fue que no todos los agentes deben comportarse igual. Esto va más allá del prompt. Definimos dos tipos de agentes: el agente general y el agente acompañante. Ambos comparten capacidades, pero difieren en comportamiento. El primero es reactivo. El segundo puede iniciar interacción bajo ciertas condiciones, por ejemplo para hacer seguimiento o retomar contexto previo.
Finalmente, como todo sistema, es necesario un módulo de observabilidad. Para esto registramos eventos como uso de herramientas, transiciones de estado, errores, sesiones, actividad de memoria, latencias y comportamiento por agente. Esto nos permite analizar el sistema y ajustar configuraciones de forma controlada.
Resultados
Esta vez el experimento contó con usuarios beta. Participaron más de 10 usuarios activos (en su mayoría perfiles no técnicos) a lo largo del mes de abril y más de 20 agentes operando en paralelo. En total, se generaron aproximadamente 360 millones de tokens (casi 220 millones de palabras) a través de OpenRouter. El modelo principal fue Nemotron 120B A12B; para tareas de visión utilizamos Gemma 4 26B A4B en todos los perfiles.
Más allá de los números, lo relevante fue la interacción entre los usuarios y sus agentes.
Varios usuarios comentaron que la experiencia se sentía distinta a usar ChatGPT, no tanto por la calidad de la respuesta, sino por el contexto de la conversación y el entendimiento que se construía a medida que interactuaban más. El agente recordaba, mantenía líneas de conversación y no requería repetir instrucciones constantemente.
También apareció algo inesperado: el canal importa. Poder interactuar a través de Discord cambió la forma de uso. Esto aumentó la frecuencia de interacción sin necesidad de “abrir” el agente explícitamente. Muchos usuarios mencionaron que tenerlo en aplicaciones que utilizan con frecuencia facilitaba la experiencia, algo que también se observó en otras plataformas de mensajería.
En tareas concretas, algunos usuarios lograron automatizar flujos pequeños que antes no resolvían bien con herramientas tradicionales. No por la capacidad del modelo en sí, sino por la combinación de memoria, herramientas y persistencia.
La funcionalidad de companion tuvo un comportamiento distinto al esperado. No se utilizó como un asistente utilitario, sino como un espacio de reflexión. Algunos usuarios lo integraron en procesos de journaling, aprovechando la memoria y la continuidad para dar seguimiento a ideas, decisiones y estado personal a lo largo de varios días. Otros destacaron la capacidad de hacer follow-up incluso sobre temas que habían conversado una semana antes.
Lo interesante de estos agentes no es solo su capacidad, sino su maleabilidad para adaptarse a distintas tareas y roles según el usuario.
Conclusiones
La principal conclusión de este experimento es que no necesitamos los modelos más grandes para tener agentes autónomos funcionales. Con la infraestructura adecuada, incluso un modelo más pequeño puede tener un desempeño comparable al de modelos significativamente mayores.
Esto no implica que no existan diferencias. En tareas específicas o en el uso de ciertas herramientas, los modelos más grandes siguen teniendo ventaja, en gran parte porque es más probable que hayan visto ese tipo de problemas durante su entrenamiento.
Sin embargo, al centrarnos en un usuario más estandarizado, en este caso perfiles no técnicos, estas diferencias resultan mucho menos perceptibles en el uso cotidiano.
Si te interesa probar este tipo de agentes o explorar cómo se comportan en tu propio flujo de trabajo, puedes comentar al final del post o escribirme directamente.


