Tenía la optimización clarísima. Y la maté con un solo dato, antes de escribir una sola línea de código.

En esta edición te cuento cómo un umbral fijado de antemano me ahorró construir un daemon que no servía para nada, por qué el cuello de botella de tus agentes casi nunca está donde crees, y la métrica incómoda que decide si un modelo open-source sirve para tool-calling.

Esto es lo que separa al prompt engineer del ingeniero de software de IA: el segundo mide antes de tocar nada.

Optimizar agentes de IA: la intuición obvia casi siempre apunta al sitio equivocado

Optimizar un agente de IA no va de afinar prompts. Va de medir dónde se queman de verdad el tiempo y el dinero, y de resistir la tentación de optimizar por instinto. La mayoría de las "mejoras" que parecen obvias atacan el 1% del problema mientras el 99% sigue intacto.

Te lo cuento con un caso real de mi propio sistema: un centro de control interno que decodifica capturas de protocolos industriales con agentes especializados sobre modelos open-source vía LiteLLM (con qwen3.6 por defecto).

La trampa: cada llamada a una herramienta arrancaba un proceso Python

La arquitectura es deliberada: los agentes no reescriben los parsers en TypeScript, sino que delegan en scripts de Python (clasificar tramas, parsear protocolos). El problema es que cada llamada a una herramienta arranca un proceso Python desde cero: lanzar el proceso, cargar el intérprete, resolver los imports.

La optimización saltaba a la vista. "Eso es un desperdicio. Monta un daemon —un único proceso que se queda vivo y atiende todas las operaciones por stdin/stdout— o un pool de procesos ya arrancados. Te quitas el arranque repetido y recortas latencia."

Suena obvio. Suena a ingeniería seria. Y es justo el tipo de cosa que te tiras tres días construyendo para descubrir que no cambió nada.

La regla que lo cambia todo: define el umbral antes de medir

Antes de escribir el daemon, fijé por escrito y de antemano un criterio de éxito: Solo se construye si el arranque de Python supone más del 25% del P50 de una ejecución.

El P50 es la mediana: el tiempo que tarda la mitad de las ejecuciones, o sea, el caso típico. Lo uso en lugar de la media porque un par de ejecuciones lentas no me distorsionan el número.

Y esto es lo más importante de toda la edición: si mides después de decidir que quieres construir algo, siempre encontrarás la forma de justificarlo. El umbral fijado de antemano es lo que te protege de ti mismo.

Luego medí. Construí solo el instrumento de medición, no la optimización.

  • Arranque de Python: 75–130 ms por llamada.

  • P50 de la ejecución completa: ~19 segundos, dominados por el LLM.

  • Peso del arranque sobre el P50: 1%.

Uno por ciento. El umbral era el 25.

Para que el arranque de Python llegara al 25% del P50 harían falta entre 40 y 60 arranques por ejecución. Las ejecuciones reales hacen 5–8. Ni forzando la caché totalmente fría el peor caso pasa del 2–3%.

Veredicto: NO-GO. El daemon no se construyó.

El giro: maté la feature, conservé el medidor

Lo único que sobrevivió fue la instrumentación: una sonda que mide el arranque en cada operación, una métrica pythonShare en el evaluador, y un comando para volver a comprobar el umbral si el perfil de rendimiento cambia.

La funcionalidad murió; el termómetro se queda puesto por si algún día el perfil cambia (un P50 mucho menor, o muchos más arranques por ejecución).

Eso es optimizar de verdad: a veces el resultado de optimizar es no construir nada y dejar montada la prueba de por qué.

El cuello de botella real es el LLM. Y con open-source, no es lo que crees

Si el 99% del P50 es el LLM, ahí es donde hay que mirar. Y aquí viene el dato que te frena en seco.

Con modelos open-source el cuello de botella no es el razonamiento. Es la fiabilidad del tool-calling. Mi medición base lo deja brutal: una tasa de fuga (leak rate) del 0,79.

Te traduzco el número: en lugar de invocar la herramienta por el canal estructurado —el mecanismo que el runtime ejecuta de verdad—, el modelo la escribe como texto plano dentro de su respuesta el 79% de las veces. Casi cuatro de cada cinco. Un agente que escupe <tool_call>... como si fuera prosa, en vez de ejecutarlo.

Eso no se arregla con un prompt más bonito. Se arregla con ingeniería defensiva alrededor del modelo:

  • Una herramienta por turno. Una instrucción explícita —"llama exactamente a UNA herramienta por turno y espera el resultado"— porque los modelos OSS encadenan llamadas caóticas si les dejas.

  • Conversión defensiva de tipos. El modelo te devuelve "1" (cadena) donde esperas un entero, o un booleano donde esperas un número. Una única función auxiliar normaliza esas salidas raras antes de que rompan nada.

  • Recuperación de la respuesta final. Lógica dedicada a rescatar la respuesta cuando el modelo la deja escrita en el texto en vez de cerrar limpio.

  • Topes de seguridad (anti-bucle). Límite de llamadas por turno y de turnos sin contenido, para que un modelo confundido no se quede dando vueltas.

Con open-source, buena parte de tu ingeniería se te va en domesticar el formato, no en el contenido.

La optimización que SÍ funcionó: capacidades bajo demanda (a 1/15 del coste)

No todo fue matar ideas. La que sobrevivió a la medición fue la carga diferida de capacidades.

Cada ejecución arrancaba con decenas de miles de tokens de system prompt dedicados solo a describir lo que el agente podría hacer. La solución no fue montar un orquestador con sub-agentes por dominio (más caro, más frágil). Fue más simple:

El system prompt lleva solo el índice de skills. El cuerpo completo de cada skill —especificaciones, tablas, referencias— se carga bajo demanda, mediante una herramienta load_skill, solo cuando el agente la necesita para la tarea que tiene entre manos.

Esa carga bajo demanda da la misma especialización que un esquema orquestador-trabajador, pero a 1/15 del coste.

Un detalle de implementación que ahorra idas y vueltas al modelo: marca los stubs (las skills aún sin implementar) en su descripción, no en el cuerpo. Si el "esto todavía no está hecho" vive dentro del cuerpo, el modelo gasta un load_skill entero solo para descubrir que está vacío. Si vive en el índice, lo ve gratis.

Y una regla de higiene que se valida en CI: cada SKILL.md es solo enrutamiento, no un manual. Dice cuándo cargar la skill, no replica la especificación. El detalle vive en ficheros aparte que se leen bajo demanda.

Para aplicar esta semana

Tres cosas que puedes llevarte hoy:

  1. Antes de optimizar, define por escrito el umbral de éxito. Si la mejora no supera un número que fijaste antes de medir, se descarta. Sin excepciones.

  2. Mide dónde está el P50 antes de tocarlo. El cuello de botella casi nunca es lo que parece "obviamente lento".

  3. Si tu agente tiene más de 10 capacidades, no las metas todas en el system prompt. Carga solo el índice; el cuerpo, bajo demanda.

Cada token que no gastas describiendo lo que el agente podría hacer es un token disponible para la tarea real.

Herramienta de la semana: Microsoft Scout

Microsoft Scout — El primer "Autopilot" autónomo integrado en el ecosistema Microsoft 365.

A diferencia de Copilot, que espera a que le pidas algo, Scout funciona en segundo plano sobre Teams, Outlook y SharePoint, actuando como un agente always-on que anticipa flujos de trabajo.

Lo probé y me genera dudas. La promesa de autonomía es brutal, pero el objetivo de Microsoft de crear usuarios "adictos" (según documentos filtrados) y la falta de controles granulares para administradores de IT ahora mismo, lo hacen arriesgado.

Útil para: Usuarios de Microsoft que buscan automatización invisible y delegación de tareas administrativas. No útil para: Empresas con políticas de seguridad estrictas o que necesiten control total sobre la ejecución de agentes.

Opinión

El futuro de los agentes no es el "prompt engineering". Es la ingeniería de software aplicada a la orquestación de IA.

Quien domine la arquitectura de contextos, dominará el coste de los agentes.

Preguntas frecuentes sobre arquitectura de agentes

¿Es mejor usar tool calling o ejecución de código para agentes IA? Depende de la complejidad. Para tareas simples, el tool calling directo funciona. Pero para flujos complejos con muchas herramientas, la ejecución de código reduce drásticamente el uso de tokens y mejora la precisión.

¿Cuántos tokens puede perder un agente por mal diseño de contexto? En arquitecturas con muchas herramientas, un modelo puede gastar más de 50.000 tokens solo leyendo definiciones antes de ejecutar la primera línea, lo que encarece la operación y ralentiza la respuesta.

¿Qué es el "Tool Search Tool" de Anthropic? Es una función que permite a los agentes descubrir herramientas bajo demanda en lugar de cargarlas todas en el prompt inicial, mejorando la precisión de modelos como Opus del 49% al 74%.

Al final, construir agentes no es cuestión de qué APIs conectas, sino de cuánta basura dejas que el modelo tenga que procesar. La eficiencia real está en el diseño de la arquitectura de contexto.

¿Prefieres ahorrar tokens con ejecución de código o te quedas en el tool calling tradicional? — Respóndeme a este email con un "CÓDIGO" o "API" y cuéntame qué arquitectura te está funcionando mejor ahora mismo. → [Responder al email]

P.S. — El ahorro del 98% que mencionamos no es un caso aislado; es la diferencia entre un prototipo y un producto escalable.

Reply

Avatar

or to participate