Engineering the Agentic Stack · Parte 6

Harness engineering para AI Agents: diseño de bucles de control

Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.

El reasoning loop de un agent elige la siguiente acción. Su harness proporciona el contexto, valida los tool calls propuestos, los autoriza, despacha los que acepta, registra los resultados y decide si la tarea ha terminado.

Los tres primeros trabajos ya tienen su propio artículo. Memory proporciona el contexto, tool use define qué se puede proponer y security decide qué se ejecuta. Se publicaron como artículos separados porque son problemas de ingeniería distintos. Elegir entre Qdrant y pgvector no tiene nada que ver con escribir una regla deny de PreToolUse.

También comparten un momento: la brecha entre que el modelo nombre una acción y que la máquina la ejecute. Cada uno responde a una pregunta sobre esa brecha, y la harness es el código que la mantiene abierta el tiempo suficiente para plantear las tres.

Para los ingenieros que construyen o revisan harnesses de coding agents, el trabajo restante consiste en decidir si el trabajo terminado está realmente completo y demostrar que cada control del bucle justifica su coste. La Parte 5 cubría el runtime que mantiene vivo el proceso subyacente.

Más allá del primer acceptance check explícito, cada retry, handoff o evaluator adicional es una hipótesis sobre un fallo observado. Solo merece un lugar cuando una comparación controlada demuestra que ayuda.

El acceptance check más sencillo es fácil de escribir para un pequeño research agent como el que ha ido construyendo esta serie: un agent de LangGraph que obtiene datos de mercado y redacta un informe de analista. Un hook externo al modelo valida el informe frente a un schema y comprueba que realmente contiene stock tickers; un informe mal formado mantiene abierto el run. Doce líneas de código normal, y el modelo no puede declarar que su propia salida está bien formada. El gate del propio repo es más flexible: un evaluator con fresh context que vota y después interviene un humano. La Parte 4 esboza la versión determinista.

Lo que ese ejemplo no puede mostrar es la parte interesante: qué ocurre cuando la evidencia es ambigua, cuando un retry podría cobrar dos veces a alguien o cuando el trabajo sobrevive a la sesión que lo inició. Para eso hace falta una tarea con un límite de aprobado/suspendido más nítido que el de un informe de investigación. El research agent se mantiene como ejemplo de acceptance check; un pequeño repositorio de tienda ficticio se incorpora para los casos de retry y handoff. La tarea de coding consiste en reducir el umbral para aplicar automáticamente un descuento del 10 % de $100 a $75 en src/checkout.py. El repositorio tiene dos checks obligatorios:

  • pytest tests/test_checkout.py verifica el cálculo del descuento.
  • pnpm playwright test tests/checkout_discount.spec.ts añade un artículo de $80 en una tienda de pruebas local y comprueba que la página de checkout muestra un descuento de $8.

El ejemplo es un fixture didáctico, no una aplicación real ni un benchmark. Cada intento parte del mismo commit y de los mismos datos de prueba inicializados. La harness solo puede aceptar el cambio cuando pasan ambos comandos y el trace vincula esos resultados al commit probado.

El diagrama sigue el cambio del descuento desde la propuesta hasta la evidencia. La harness proporciona la tarea y los archivos, comprueba los argumentos y permisos propuestos de edit_file y despacha el call aceptado. Después de que el runtime aplique la edición, la harness ejecuta los tests de aceptación unitarios y de navegador indicados. Un comando fallido vuelve al modelo como evidencia para otro turno; dos comandos correctos hacen que el cambio pueda aceptarse.

Un cambio de descuento a través del bucle de control de la harnessUn cambio de descuento a través del bucle de control de la harness


Qué controla la harness

El recorrido del bucle de Codex de OpenAI describe el ciclo básico. La harness monta un prompt, pide al modelo la siguiente acción, envía un tool call aceptado al runtime y añade el resultado. Después vuelve a preguntar. El ciclo se repite hasta que la harness acepta el resultado o devuelve el control al usuario.

Las implementaciones pueden fusionar varias responsabilidades en un mismo proceso. No obstante, los límites de fallo siguen siendo distintos:

TérminoFunciónEjemplo en un coding agent
ModelPropone texto, un tool call o una respuesta finalSugiere una edición de src/checkout.py
Reasoning loopElige el siguiente movimiento a partir del contexto disponibleInspeccionar, editar, probar, volver a inspeccionar
HarnessProporciona contexto, valida propuestas, las autoriza, despacha los calls aceptados, registra resultados y comprueba el cierrePermite ediciones bajo src/ y exige ambos tests indicados
RuntimeEjecuta los calls aceptados y mantiene el estado vivo fuera del proceso workerSession log, sandbox, checkpoint store, trace backend

La fila del runtime cubre cuatro elementos: session, sandbox, checkpoint y trace. Los cuatro almacenan estado o restringen la ejecución. El modelo propone la acción y el reasoning loop elige el siguiente movimiento. La harness decide si un call propuesto puede ejecutarse y si la evidencia basta para finalizar; por eso tiene su propio artículo. La Parte 5 cuenta la harness junto a esos cuatro elementos como uno de los cinco primitives que hay que situar antes de lanzar el sistema; este artículo vuelve a separarla.

Cuando aparece un fallo, diagnostica el límite que debería responder. Un plan deficiente puede necesitar mejores instrucciones o un mejor reasoning del modelo. Si edit_file apunta a una ruta fuera de src/, la harness debe rechazarlo. Un proceso de sandbox que muere antes de ejecutar la edición pertenece al runtime, que debe reiniciar el worker o informar del crash.

Dónde encajan las partes anteriores

La fila de la harness hace la mayor parte del trabajo en esa tabla y es donde terminan las Partes 2, 3 y 4. Cada una decide una cosa sobre un turno concreto:

Parte anteriorQué decide para este turnoDónde actúa en el recorrido de la sección siguiente
Parte 2 — memoryQué estado previo entra en el promptPaso 1, el context builder
Parte 3 — tool useQué acciones existen y cómo es un resultado validadoValidación de argumentos del paso 3 y forma del resultado en el paso 4
Parte 4 — securitySi este call concreto puede ejecutarse ahoraPaso 3, comprobación de ruta y decisión de aprobación
Parte 6 — este artículoSi la evidencia resultante pone fin al runPasos 5 a 7, acceptance checks y trace

Dónde se sitúa cada parte de la serie Engineering the Agentic StackDónde se sitúa cada parte de la serie Engineering the Agentic Stack

Las Partes 3 y 4 comparten el paso 3, y ese solapamiento es precisamente el argumento para tratarlas como un único programa. La misma capa de código de la harness que rechaza un argumento mal formado también rechaza un call permitido pero aún no aprobado. Si se dividen entre dos servicios, ambos rechazos divergen y un call que supera la validación del schema puede autorizarse en un lugar que nunca vio ese schema.

La separación sigue siendo importante para depurar: una edición en el archivo equivocado es una regla de rutas de la Parte 4, no un problema de retrieval de la Parte 2. Una sección cercana al final de este artículo lo convierte en una tabla de enrutamiento.

El propio caso práctico de harness engineering de OpenAI describe una instancia de aplicación arrancable para cada worktree. El equipo también conectó la automatización del navegador al entorno del agent y expuso logs, métricas y traces.

Una tarea como «ningún span de estos cuatro recorridos críticos de usuario supera los dos segundos» se volvió comprobable porque el agent podía ejecutar la aplicación y consultar las mismas señales que inspeccionaría un ingeniero. El caso práctico es específico del producto. Lo que se puede trasladar es la condición que explica el resultado: la aplicación y sus señales de rendimiento tenían que estar disponibles dentro del entorno del agent.

Lopopolo, autor de ese caso práctico, mantiene una guía de campo sobre harness engineering. En ella nombra las dos palancas que utiliza este artículo: mantener el modelo y el coding agent fijos como una caja negra, e implementar el contexto y las tools que los rodean. Su enfoque también explica por qué gran parte de la harness acaba siendo código normal.

El umbral de calidad de una organización, sus procedimientos, el historial de excepciones y las relaciones de autoridad quedan fuera de lo que un modelo general puede conocer. La harness los expone como instrucciones del repositorio, reglas de permisos y acceptance checks. Cada run aceptado puede devolver sus aprendizajes a esos artefactos, en lugar de confiar en que la siguiente sesión los redescubra.


Sigue el cambio del descuento desde la propuesta hasta la aceptación

Para la tarea del descuento definida arriba, el modelo propone cambiar calculate_discount en src/checkout.py. Antes de que esa edición cuente como progreso ocurren varias cosas:

  1. El context builder proporciona la tarea, las instrucciones del repositorio, los archivos relevantes, los resultados de tools anteriores y el plan actual.
  2. El modelo propone un call de edit_file con una ruta y el texto de sustitución.
  3. El límite de la tool (el código de la harness entre la propuesta y la ejecución) valida los argumentos, comprueba la ruta frente al ámbito permitido y solicita aprobación si la operación la necesita.
  4. El runtime aplica la edición en el sandbox y devuelve un resultado estructurado.
  5. La harness ejecuta pytest tests/test_checkout.py, seguido de pnpm playwright test tests/checkout_discount.spec.ts, y lee ambos códigos de salida. El test de navegador comprueba el descuento visible de $8 en el carrito inicializado de $80.
  6. La harness decide qué significan los resultados. Un check fallido se convierte en nuevo contexto para el siguiente turno del modelo, y un run correcto convierte la tarea en candidata a completarse.
  7. Un resultado correcto solo se convierte en evidencia de finalización después de que la harness registre en el trace el comando, el código de salida y la versión del artefacto probado.

Después del paso 2 no ha cambiado ningún archivo. La harness puede rechazar ../../secrets.env, exigir aprobación para un comando destructivo o detener un run que haya agotado su presupuesto. Ese es el último momento barato del que dispones. Después de ejecutar los tests, la harness lee por sí misma sus códigos de salida. El modelo no puede marcar su propia edición como correcta.

El trace debería mostrar la ruta y el texto de sustitución propuestos, la decisión de permisos, los archivos modificados, el commit probado y los resultados de ambos comandos. Un mensaje final de done sin esos registros no demuestra que este cambio haya superado sus checks obligatorios.


Decide dónde se aplica cada regla

El requisito de que tests/checkout_discount.spec.ts pase debe estar en código determinista, no en el prompt. La harness despacha el comando de Playwright al runtime, lee su código de salida y se niega a cerrar el run mientras falle. Un prompt puede recordar al modelo que ejecute el test. No puede impedir que el modelo declare el éxito sin evidencia.

Otras reglas encajan en capas diferentes:

Coloca la regla enEncaja bienEjemplo
Prompt o skillOrden de búsqueda, convenciones de coding y formato del planLeer AGENTS.md antes de editar código de checkout
Límite de la toolValidación de argumentos, rutas permitidas, aprobaciones y acceso a toolsPermitir escrituras solo bajo src/
Código deterministaPresupuestos, timeouts, retries, códigos de salida de tests y gates de releaseMantener abierto el run mientras falle el test de Playwright
Evaluator con fresh contextRevisión visual o criterios que requieren juicio similar al humanoComparar un diagrama generado con una rúbrica escrita

Los contratos de tools separan propuesta y permiso

La tarea del descuento solo necesita ediciones de archivos y comandos de test. Una API que cambia estado tiene otro modo de fallo, así que cambiemos los ejemplos de esta sección. Supón que el agent puede llamar a create_test_order contra un servicio de pedidos de staging mientras prepara los datos de prueba. Esta tool no es uno de los acceptance checks de la tarea del descuento. Resulta útil aquí porque un timeout puede ocultar si el servicio ha creado un pedido.

El límite de la tool necesita algo más que una descripción en lenguaje natural. Necesita un contrato de tool explícito. La Parte 3 defendía uno desde el lado del modelo: acciones claras, feedback compacto y errores recuperables. La harness necesita el mismo contrato por otro motivo. Tiene que decidir, sin preguntar al modelo, si un call puede ejecutarse y si un call fallido puede repetirse. Para create_test_order, eso implica un contrato con:

  • argumentos validados, para rechazar las entradas mal formadas antes de la ejecución
  • un resultado estructurado como { "order_id": "123", "created": true }, para que los checks posteriores no tengan que analizar texto libre
  • una categoría de efecto que registre si el call solo obtiene información o cambia un archivo, un registro de base de datos o un servicio externo. También registra si es seguro repetir el call. Esta etiqueta indica a la harness si un retry automático podría duplicar el trabajo. La harness puede reintentar get_order_status cuando el servicio define esa consulta como de solo lectura. No debe reintentar ciegamente create_test_order, porque la primera llamada podría haber creado ya el pedido
  • una política de timeout y retry, para que una respuesta perdida no active una secuencia ilimitada de calls
  • una regla de permisos que indique qué aprobación se requiere. La consulta del estado del pedido puede ejecutarse automáticamente, mientras que crear un pedido puede requerir confirmación

La descripción en lenguaje natural es el texto que se muestra al modelo. Podría decir: «Crea un pedido de prueba para verificar el checkout». Esa frase ayuda al modelo a decidir cuándo proponer create_test_order. No autoriza el call. En este ejemplo, el cliente de Model Context Protocol (MCP) de la harness valida los argumentos, aplica sus propias reglas y comprueba la confianza en el servidor, los requisitos de aprobación y la seguridad del retry antes de despachar nada. Es la misma cadena ordenada deny/ask/hook/allow de la Parte 4, con una pregunta adicional: si un call que ya ha fallado puede volver a enviarse.

Un servidor MCP publica descripciones de tools y anotaciones opcionales de comportamiento al cliente. Un servidor defectuoso o malicioso podría describir una tool que cambia estado como inofensiva. Un cliente que aceptase automáticamente esa afirmación podría ejecutar o reintentar create_test_order sin aprobación y crear un duplicado. Por eso la especificación MCP exige que los clientes traten las anotaciones de tools como no fiables, salvo que el propio servidor sea de confianza.

La especificación no prescribe una única configuración universal de confianza, así que necesitas una política de confianza explícita para tu despliegue; un servidor no puede hacer fiables sus propias anotaciones. Esa política decide qué metadatos pueden influir en las decisiones de permisos o retries y qué anotaciones siguen siendo meramente informativas.

Repetir un call que cambia estado requiere protección frente a replay

La Parte 5 añade una idempotency key a cada call de tool con efectos secundarios. La harness es la que decide cuándo esa clave debe asumir el peso. create_test_order crea el pedido, pero su respuesta HTTP se pierde. La harness ve un timeout y no puede saber si el servidor ha completado la petición. Repetir el call podría crear un segundo pedido.

Una consulta de estado puede reintentarse cuando el servicio la define como de solo lectura. Un call de creación necesita la clave: el cliente adjunta un identificador único de petición y el servicio devuelve el primer resultado en vez de crear otro pedido cuando vuelve a ver ese identificador. Sin esta protección, la harness debe comprobar si existe el pedido o pedir una decisión humana antes de otro intento. AWS documenta este patrón en sus recomendaciones sobre APIs idempotentes.

La aceptación necesita evidencia independiente

Una respuesta correcta de create_test_order solo demuestra que la tool ha devuelto datos. No prueba que una tarea de coding haya superado sus tests. Si un test de navegador posterior depende del pedido preparado, la harness debe validar el schema de la respuesta y ejecutar igualmente ese test antes de aceptar el cambio de código.

Algunos criterios no pueden reducirse a un código de salida. Para una tarea independiente de diseño visual, un evaluator con fresh context puede comparar una página o un diagrama renderizado con una rúbrica escrita —«fresh context» significa una segunda sesión del modelo que empieza sin historial del run y lee los artefactos producidos en lugar del transcript—. Contrasta ese evaluator con revisiones humanas antes de permitir que bloquee la finalización.


Una migración del adaptador de pagos necesita un handoff

Cambiemos de tarea otra vez, pero mantengámonos en el repositorio de tienda ficticio. Ahora el agent debe migrar el checkout del adaptador de pagos v1 al v2. El trabajo abarca el handler de checkout, el cliente de pagos, la configuración y los tests, por lo que puede durar más que una sesión de modelo —un tramo continuo de contexto del modelo, terminado por un reinicio o por un inicio nuevo deliberado, en lugar de conservarse—.

Antes de que la primera sesión alcance su límite de contexto, ha modificado varios archivos, ha iniciado un sandbox de pagos local y ha dejado tests/payment_migration.spec.ts fallando. Ese test de aceptación del navegador completa un pago mediante el adaptador v2 y verifica el ID del proveedor registrado. Un resumen de la conversación puede orientar a la siguiente sesión del modelo, pero no puede reiniciar el sandbox ni demostrar qué archivos están modificados actualmente.

La siguiente sesión tiene que recuperar tres cosas:

Qué debe recuperarseQué incluyeCómo puede fallar
Historial de la conversaciónMensajes, tool calls y resultados devueltosLos detalles antiguos desplazan la tarea actual
Entorno de trabajoArchivos, sandbox de pagos y estado del test de navegadorEl transcript dice que un servicio está activo después de que haya muerto
Progreso de la tareaPlan, checks completados, aprobación pendiente y siguiente acciónLa siguiente sesión repite trabajo ya terminado

La compaction sustituye los mensajes antiguos por un resumen más corto para que la sesión actual pueda continuar. Un progress handoff registra lo que necesita la siguiente sesión: la rama actual, los archivos modificados, el último comando de test y su salida, y el siguiente paso no resuelto.

Un archivo de handoff es document memory escrito para un lector concreto —la siguiente sesión del modelo— y es un artefacto distinto del checkpoint que restaura el runtime. El checkpoint responde a dónde se detuvo la ejecución. El handoff responde a qué significa el trabajo y qué queda pendiente. Si restauras un checkpoint sin handoff, la siguiente sesión obtiene un proceso reanudable, pero no sabe cuál de las cuatro áreas modificadas —handler, cliente, configuración o tests— ha terminado ya. Eso es lo que produce trabajo duplicado.

Si la conversación antigua contiene suposiciones obsoletas, la harness puede iniciar una sesión nueva del modelo con ese handoff y el workspace actual. Sustituir un worker caído y restaurar sus procesos es una tarea independiente de recuperación del runtime.

Una pequeña edición de documentación puede no necesitar ninguno de estos mecanismos. La migración de pagos necesita un handoff cuando el trabajo cruza sesiones, porque la siguiente sesión del modelo debe reconstruir tanto el workspace como el estado de la tarea.

Los experimentos de Anthropic con coding agents de larga duración utilizaron el historial de git y un archivo de progreso entre sesiones. El posterior informe de diseño de harness de Anthropic separa la compaction del handoff con fresh context e indica que los handoffs añaden orquestación, uso de tokens y tiempo de pared, sin publicar cifras que atribuyan específicamente ese overhead al handoff.


Usa traces para distinguir tres fallos

Las tres filas siguientes son esquemas ilustrativos de trace, no ejecuciones medidas ni salidas del companion lab. Cada fila muestra un fallo distinto y, por tanto, una respuesta diferente de la harness.

Qué registra el traceQué ocurrióRespuesta correcta
El call de solo lectura get_order_status devuelve 503; no hay ningún call que cambie estado en cursoFalló una consulta transitoriaReintentar la consulta con límites y backoff
create_test_order agota el timeout y después una consulta de estado encuentra el pedido 123 con la idempotency key checkout-42El servicio creó el pedido, pero se perdió la respuestaDevolver el pedido existente; no crear otro
La edición y el test unitario pasan, pero el trace no contiene ningún resultado de tests/checkout_discount.spec.ts para el commit probadoFalta evidencia de aceptación obligatoriaMantener abierto el run y despachar el test de aceptación del navegador

Un fallo que parece transitorio no hace que todos los calls sean seguros para retry. La primera fila es una consulta de solo lectura. La segunda es una petición que cambia estado, así que la idempotency key y el estado del servidor determinan si se permite otro intento de creación. La tercera no es un fallo de tool; la harness todavía no ha recopilado la evidencia necesaria para aceptar el cambio del descuento.

Un transcript de chat registra lo que vio el modelo. No puede demostrar si el servicio de pedidos confirmó una petición antes de que desapareciera la respuesta. El transcript es el relato de los hechos del agent; el trace es lo que realmente hizo la máquina. Cuando ambos discrepan, confía en el trace. El trace debe vincular el call del cliente, la decisión de aprobación, la idempotency key, el resultado del servidor o de la consulta de estado, el commit probado y el resultado del test de aceptación. Esos campos indican a la harness cuál de los tres caminos debe seguir.

Síntoma repetidoPequeño cambio que probarQué medir
Las consultas de solo lectura fallan de forma transitoriaRetry limitado con backoffTasa de recuperación, calls adicionales y tiempo de pared
Las sesiones reanudadas repiten trabajo completadoProgress handoff estructuradoTool actions duplicadas después de reanudar
Faltan tests obligatorios al finalizarAcceptance gate fail-closedTareas aceptadas sin todos los checks obligatorios
Los defectos visuales sobreviven a los checks deterministasEvaluator con fresh context y una rúbricaDefectos detectados, rechazos falsos y tiempo de revisión
El agent edita fuera de su ámbitoPermisos de tools más restrictivosCalls bloqueados y overrides manuales
La memoria recuperada desplaza la tarea actualLimitar los hechos recuperados; clasificarlos antes de inyectarlosTokens dedicados al recall, tareas completadas y coste por tarea

Antes de añadir un componente, nombra el fallo repetido que debería reducir y el número que vas a seguir. Elimina el componente si una comparación controlada no mueve ese número lo suficiente para compensar su coste. La mayoría de las harnesses que he visto crecen al revés: alguien sufre un run defectuoso, añade un guard y el guard permanece para siempre porque nadie puede demostrar que sea seguro eliminarlo. Así acabas con un bucle que nadie quiere tocar.

Convertir esos fallos repetidos en una regression suite versionada es un trabajo aparte. Lo he explicado por separado en AI Agent Evaluation in Production.


Mide un cambio cada vez

Una ablation mide si un componente de la harness produce el efecto esperado cambiándolo o eliminándolo mientras el resto del experimento permanece fijo. Por ejemplo: ¿ayuda el linting del editor a este modelo en este conjunto de tareas?

Usa el siguiente protocolo:

  1. Fija la versión del modelo, las instancias de tarea, el entorno, el grader y los prompts que queden fuera del componente bajo prueba.
  2. Asigna a ambas variantes el mismo presupuesto total de tokens, tiempo y dinero.
  3. Elige el número de trials o la regla de parada antes de ejecutar la comparación.
  4. Ejecuta las mismas instancias de tarea en ambas variantes. Como las salidas del modelo varían, repite cada tarea varias veces.
  5. Informa de la media junto con la dispersión o el intervalo de confianza.
  6. Cuenta todos los trials iniciados, incluidos timeouts, paradas por política, crashes de la harness y fallos del evaluator.

La tasa de éxito por sí sola puede ocultar un componente caro. Como mínimo, registra las tareas defectuosas aceptadas como completas, el coste y el tiempo de pared por tarea completada, los errores de tools, los pedidos duplicados, los minutos de revisión y los overrides manuales de permisos. Elige la métrica que refleje el coste real de tu producto. Un aumento de dos puntos en las tareas completadas es un mal intercambio si duplica tu cola de revisión.

Un experimento emparejado de migración de pagos hace medible el progress handoff. Cada pareja control/tratamiento parte del mismo commit del repositorio y del mismo checkpoint inicializado, con el mismo modelo, tarea, grader y presupuesto total. El handoff es el único interruptor. La métrica principal cuenta las tool actions duplicadas después de reanudar: una acción es duplicada cuando su operación y artefacto coinciden con un paso que la sesión anterior ya había completado.

Una prueba de ablation emparejada del progress handoffUna prueba de ablation emparejada del progress handoff

El artículo de SWE-agent fija GPT-4 Turbo en la partición de 300 tareas de SWE-bench Lite y comunica un 18,0 % de tareas resueltas con su interfaz completa, frente al 11,0 % de un agent basado solo en shell con una demostración guiada y el 7,3 % del mismo agent sin ella. La diferencia principal de 10,7 puntos del artículo se mide frente a esa baseline del 7,3 %; la Parte 3 trabaja los mismos tres números desde la perspectiva del diseño de interfaces. El artículo también modificó funciones individuales de la interfaz:

Cambio en la interfazResueltas
Interfaz completa de SWE-agent (referencia, sin cambios)18,0 %
Editor sin linting15,0 %
Archivo completo en lugar de un visor de 100 líneas12,7 %
Historial completo de observaciones en lugar de las cinco últimas15,0 %

Estas cifras corresponden a ese modelo, benchmark y límite de $4 por tarea. Las tres filas inferiores a la referencia son las pruebas útiles de una sola función: cada una cambió una función de la interfaz mientras el modelo y la configuración de evaluación permanecían fijos.

LangChain publicó una comparación con modelo fijo más amplia para deepagents-cli. Comunica un aumento del 52,8 % al 66,5 % en Terminal-Bench 2.0 con gpt-5.2-codex fijo, mientras su equipo modificaba el system prompt, las tools y el middleware. El artículo agrupa varios cambios y omite un intervalo de confianza, una comparación con presupuesto total fijo y una tabla de ablation por cambio. Por tanto, el resultado no permite identificar qué cambio ayudó. Los nombres de los modelos de esta sección son los que cada estudio fijó cuando se ejecutó; lo que se puede trasladar es el protocolo, no la lista de modelos.

El informe de aplicación de larga duración de Anthropic es un caso práctico cualitativo y específico del producto, no un benchmark controlado. La aplicación es RetroForge, un creador de juegos retro 2D; en el Sprint 3, el evaluator de la harness comprobó 27 criterios relacionados con su editor de niveles. El trabajo comenzó con modelos Opus anteriores y, cuando se lanzó Opus 4.6, el equipo eliminó los componentes de la harness uno a uno para comprobar cuáles se habían vuelto redundantes con el modelo más nuevo. El informe indica que los calls del evaluator se convirtieron en overhead en tareas que Opus 4.6 podía completar de forma fiable por sí solo, aunque seguían ayudando cerca del límite del modelo. El ejemplo es un motivo para volver a validar la infraestructura antigua cuando cambia el modelo; no estima un tamaño de efecto general.


Mantén la harness editable después de justificar su lugar

La ablation mantiene pequeña la harness, pero su código puede sobrevivir al modelo para el que se ajustó. Una petición como «enmascara los secretos en cada ruta de captura» describe un comportamiento, no un archivo. En una harness de producción, ese comportamiento puede abarcar varias fases de ejecución y estado compartido. Antes de cambiarlo de forma segura, tienes que encontrar todos los puntos de implementación; y el coding agent al que delegues la tarea también.

Un preprint de 2026 de Wang et al., el Harness Handbook, denomina a esta búsqueda behavior localization. El handbook construye un mapa de la base de código de la harness centrado en comportamientos. El análisis estático, que no necesita calls al modelo, extrae un grafo del programa y un LLM organiza después sus unidades en fases de ejecución.

El maintainer o coding agent comienza con una visión general del sistema, abre la fase de ejecución relevante y desciende hasta entradas ancladas en el código fuente para una función o archivo. Un registro de estado anota dónde se escribe y se lee el estado compartido entre fases. Esta jerarquía mantiene pequeño el resumen y conserva una ruta hasta el código fuente.

La frescura es una regla independiente. Cada locator debe resolverse contra el repositorio activo. El handbook congela las entradas obsoletas en lugar de adivinar, y cada diff no vacío vuelve a sincronizar las entradas que afecta.

El diagrama comprime el bucle de modificación: una petición centrada solo en el comportamiento desciende por los niveles del handbook, cada locator candidato se verifica contra el repositorio activo antes de redactar el plan y cada diff aplicado vuelve a sincronizar el mapa.

Enrutamiento de un cambio de comportamiento mediante un handbook de harnessEnrutamiento de un cambio de comportamiento mediante un handbook de harness

La evaluación del Handbook sigue el protocolo que defiende este artículo. Cubre dos harnesses open source: Terminus-2 (seis archivos Python) y el monorepo de Codex (2.267 archivos Rust). En ambos casos, un planner de solo lectura impulsado por DeepSeek-V4-Pro exploró el repositorio directamente o se enrutó a través del handbook. Las peticiones, el repositorio, los permisos de tools y el decoding eran idénticos en ambos brazos. Tres jueces (GPT-5.5, Opus 4.8 y DeepSeek-V4-Pro) puntuaron cada plan de edición en localization, control de ámbito y reasoning; observa que uno de los jueces es el mismo modelo que produjo los planes:

HarnessTasa de victoria de la baselineCon ayuda del HandbookTokens del planner
Terminus-2 (6 archivos)26,7 %45,6 %−8,6 %
Monorepo de Codex (2.267 archivos)28,3 %38,3 %−12,7 %

El planner asistido por el handbook ganó con mayor frecuencia y utilizó menos tokens de planner en ambos repositorios. Las condiciones siguen formando parte del resultado: tres jueces LLM puntuaron planes de edición producidos por un único modelo planner en dos harnesses. El estudio evaluó planes, no diffs ejecutados ni tasas de defectos en producción.


Prueba el método en el companion lab

El proyecto harness-demo en el commit 517353f3 es un ejercicio pequeño y determinista con 12 tareas sintéticas genéricas que cubren cambios de código como fix-parser-edge-case, split-large-module y wire-browser-test. No implementa el repositorio de tienda ficticio.

Cada fixture de tarea declara una dificultad y cuatro condiciones booleanas: una tool flaky, pérdida de progreso, una brecha de implementación no detectada y finalización ambigua. El simulador deriva una quinta condición para las tareas difíciles que también necesitan un archivo de progreso: sin context_reset, la compaction conserva suposiciones obsoletas. Un grader determinista marca una tarea como superada solo cuando la configuración seleccionada gestiona todas las condiciones aplicables. No se ejecutan modelos ni servicios externos.

Los comandos responden a preguntas distintas:

  • make check ejecuta Ruff y siete tests unitarios, incluido el validador que rechaza cualquier pareja de ablation que cambie más de un componente.
  • make run muestra una matriz didáctica acumulativa y después cinco comparaciones válidas de leave-one-component-out.
  • make failures indica la condición no gestionada para cada tarea fallida. La harness completa debería terminar con all synthetic tasks pass.
make check
make run
make failures

La sección causal de make run tiene este aspecto:

component                 control  treatment  delta
retry_policy              8/12     12/12       +4
progress_handoff          7/12     12/12       +5
evaluator                 8/12     12/12       +4
fail_closed_acceptance    7/12     12/12       +5
context_reset            10/12     12/12       +2

En cada fila, el control es la configuración completa con un componente eliminado; el tratamiento restaura únicamente ese componente. La matriz acumulativa anterior resulta útil para orientarse, pero algunas de sus filas adyacentes añaden varios componentes a la vez y, por tanto, no pueden identificar una causa.

El lab valida cada pareja declarada antes de ejecutarla. Sus regression tests también incluyen una pareja intencionadamente no válida que cambia a la vez la política de retry y el evaluator; el validador la rechaza.

El lab compara los cinco campos de componentes al validar una pareja. Este fragmento ejecutable muestra la misma protección en una pareja válida de progress handoff:

from dataclasses import dataclass, fields

@dataclass(frozen=True)
class Config:
    progress_handoff: bool = False
    evaluator: bool = False
    retry_policy: bool = False
    fail_closed_acceptance: bool = False
    context_reset: bool = False

def changed_components(control: Config, treatment: Config) -> tuple[str, ...]:
    return tuple(
        field.name
        for field in fields(control)
        if getattr(control, field.name) != getattr(treatment, field.name)
    )

control = Config(progress_handoff=False, evaluator=True, retry_policy=True)
treatment = Config(progress_handoff=True, evaluator=True, retry_policy=True)
assert changed_components(control, treatment) == ("progress_handoff",)

Qué capa abrir cuando un run falla

La serie avanzaba de dentro hacia fuera, y aquí es donde ese orden resulta útil. Un run fallido de un agent suele tener un único responsable:

Qué hizo el runDónde vive la soluciónParte
Eligió un siguiente paso deficiente con la información correcta ya disponibleReasoning loop o modelo1
Repitió trabajo o perdió una decisión tomada una hora antesEnsamblado de contexto y handoffs2
No pudo expresar la acción que necesitaba o interpretó mal un resultado devueltoContrato de tool3
Hizo algo que nunca debería haber podido hacerReglas de permisos4
Lo perdió todo cuando un worker murió en mitad de un callSession, checkpoint y sandbox5
Declaró que el trabajo estaba terminado cuando no lo estabaAcceptance checks y traces6

Cuatro de esas seis filas son código de la harness. La fila 5 es el runtime que la sustenta, y la fila 1 es la única sobre la que todavía puede influir un prompt.


Empieza con un bucle y un acceptance check

Yo empezaría un harness de coding agent con un modelo capaz, instrucciones del repositorio, unas pocas tools estrechas, un sandbox y un único test de aceptación explícito. Registraría los tool calls, los resultados, los costes y ese test final en un único trace, para que los primeros fallos útiles fueran visibles sin tener que reconstruirlos a partir de logs del terminal y transcripts de chat. Esto es una baseline propuesta, no evidencia de un sistema desplegado.

A partir de ahí, añade solo lo que justifique un trace. Registra quién mantiene cada componente, cuántos tokens o segundos añade y qué regression test justificaría eliminarlo después de una actualización del modelo.

Seis meses después, alguien que vea progress_handoff=True debería poder encontrar los traces fallidos que justificaron su incorporación y los casos de regresión que aún justifican mantenerlo. Los traces explican por qué existe el componente; un mapa de comportamientos actualizado explica dónde tocarlo.

Si has llegado aquí desde una búsqueda, los cinco artículos anteriores construyeron un sistema alrededor de un reasoning loop:

  1. El bucle elige el siguiente movimiento.
  2. Memory proporciona el contexto y un checkpoint store real de Postgres lo conserva.
  3. Los contratos de tools definen las acciones y las formas de resultado que pueden leer los checks posteriores.
  4. Security añade el deny hook y el validador stop-hook. Ambos siguen siendo esquemas en el ejemplo, pero señalan los puntos de control.
  5. El runtime mantiene vivo el proceso entre sesiones y fallos.

La serie también añadió un sidecar MCP para mostrar dónde deben situarse los tokens de los data providers y un nodo evaluator que comprueba el borrador del informe antes de que lo vea un humano. Son piezas de código normales alrededor de un call al modelo. El router es código de la harness por el mismo motivo: elige el patrón de reasoning antes de que comience el reasoning loop.

Tu siguiente paso es instrumentar un bucle pequeño. Registra tool calls, resultados, costes y un acceptance check explícito. Añade un único control solo después de que un trace muestre el fallo al que responde. Compáralo con un control fijo y elimínalo cuando desaparezca el beneficio medido.


Referencias


El código del Market Analyst Agent está disponible en GitHub.