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.
Actualización del artículo
Publicado originalmente el 22 de julio de 2026. Revisado y actualizado el 6 de septiembre de 2026. La actualización añade evidencias más recientes de benchmarks de harness y casos de intervención del proveedor, y aclara qué demuestran los resultados publicados.
Un agent puede terminar su turno mientras el trabajo sigue incompleto. Para un coding agent, las evidencias útiles son el artefacto modificado y los resultados de los tests requeridos. Un mensaje final que diga «hecho» no demuestra ninguna de las dos cosas.
El harness es el código de control que rodea al reasoning loop. Proporciona contexto, valida y autoriza los tool calls, registra los resultados y decide si las evidencias son suficientes para aceptar el trabajo. El runtime mantiene la ejecución y el estado activos por debajo de esta capa.
Al revisar un harness, plantearía dos preguntas: ¿qué impide que acepte trabajo incompleto y qué fallos justifican añadir controles? En este artículo se recorren los acceptance checks, los reintentos y los handoffs, y después se muestra cómo comparar un control con una baseline fija. Los ejemplos de la tienda son ficticios; el lab complementario es una simulación determinista, no una medición de un agent en producción.
El acceptance check más sencillo es fácil de escribir para un pequeño research agent como el que se ha construido en esta serie: un agent de LangGraph que obtiene datos de mercado y redacta un informe de analista. Un hook externo al model valida el informe contra un schema y comprueba que realmente contiene tickers bursátiles; un informe mal formado mantiene abierta la ejecución. Doce líneas de código convencional, y el model no puede declarar que su propia salida está bien formada. El repo utiliza un check más flexible: un evaluator con fresh context emite su voto y después una persona revisa el resultado. (La parte 4 esboza la versión determinista).
Lo que ese ejemplo no puede mostrar es la parte interesante: qué ocurre cuando las
evidencias son ambiguas, cuando un retry podría cobrar dos veces a alguien o cuando
el trabajo dura más que la sesión que lo inició. Para eso hace falta una tarea con
un límite de aprobado/suspenso más claro que el de un informe de investigación. El
research agent se mantiene como ejemplo de acceptance check; un pequeño repositorio
ficticio de una tienda se incorpora para los casos de retry y handoff. La tarea de
coding consiste en bajar el umbral para aplicar un descuento automático del 10 % de
$100 a $75 en src/checkout.py. El repositorio tiene dos checks requeridos:
pytest tests/test_checkout.pyverifica el cálculo del descuento.pnpm playwright test tests/checkout_discount.spec.tsañ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. El harness solo puede aceptar el cambio cuando ambos comandos terminan correctamente y un registro de aceptación duradero vincula ambos resultados a un candidato commiteado limpio o a un digest de la snapshot completa probada, incluidos los archivos sin seguimiento relevantes.
El diagrama sigue el cambio del descuento desde la propuesta hasta las evidencias.
El harness proporciona la tarea y los archivos, comprueba los argumentos y los
permisos propuestos para edit_file y despacha el call aceptado. Después
de que el runtime aplique la edición, el harness ejecuta los tests de unidad y de
aceptación en el navegador indicados. Un comando fallido vuelve al model como
evidencia para otro turno; dos comandos correctos hacen que el cambio pueda aceptarse.
Qué controla el harness
El recorrido del bucle de Codex de OpenAI describe el ciclo básico. El harness ensambla un prompt, pide al model 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 el harness acepta el resultado o devuelve el control al usuario.
Las implementaciones pueden agrupar varias responsabilidades en un mismo proceso. Los límites de fallo siguen siendo distintos:
| Término | Función | Ejemplo en un coding agent |
|---|---|---|
| Model | Propone texto, un tool call o una respuesta final | Sugiere una edición en src/checkout.py |
| Reasoning loop | Elige el siguiente movimiento a partir del contexto disponible | Inspeccionar, editar, probar, volver a inspeccionar |
| Harness | Proporciona contexto, valida propuestas, las autoriza, despacha calls aceptados, registra resultados y comprueba el fin | Permite editar bajo src/ y exige ambos tests indicados |
| Runtime | Ejecuta calls aceptados y mantiene el estado fuera del proceso worker | Log de sesión, sandbox, almacén de checkpoints, backend de trazas |
La fila del runtime cubre cuatro elementos: sesión, sandbox, checkpoint y trace. Los cuatro almacenan estado o limitan la ejecución. El model propone la acción y el reasoning loop elige el siguiente movimiento. El harness decide si un call propuesto puede ejecutarse y si las evidencias bastan para terminar, por eso tiene su propio artículo. La parte 5 cuenta el harness junto a esos cuatro elementos como uno de los cinco primitives que hay que situar antes de poner el sistema en producción; este artículo lo separa de nuevo.
Cuando aparece un fallo, diagnostica el límite que debería responder. Un plan
deficiente puede requerir mejores instrucciones o mejor reasoning del model. Si
edit_file apunta a una ruta fuera de src/, el 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 del harness de la tabla anterior hace la mayor parte del trabajo, y ahí es donde desembocan las partes 2, 3 y 4. Cada una decide una cosa sobre un único turno:
| Parte anterior | Qué decide para este turno | Dónde actúa en el recorrido de la siguiente sección |
|---|---|---|
| Parte 2 — memoria | Qué estado previo entra en el prompt | Paso 1, el constructor de contexto |
| Parte 3 — tool use | Qué acciones existen y cómo es un resultado validado | Validación de argumentos del paso 3 y forma del resultado en el paso 4 |
| Parte 4 — seguridad | Si este call concreto puede ejecutarse ahora | Paso 3, comprobación de ruta y decisión de aprobación |
| Parte 6 — este artículo | Si las evidencias resultantes terminan la ejecución | Pasos 5 a 7, acceptance checks y trace |
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 del harness que rechaza un argumento mal formado también rechaza un call permitido pero aún no aprobado. Si la validación y la autorización se ejecutan en servicios separados, conserva los argumentos validados a través de ese límite para que la decisión de autorización se aplique al call que se va a ejecutar.
La separación sigue siendo importante para depurar: una edición en el archivo equivocado es una regla de ruta 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 routing.
El propio caso práctico de harness engineering de OpenAI describe una instancia de aplicación arrancable para cada worktree. El equipo también integró browser automation en el entorno del agent y expuso logs, métricas y trazas.
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 transferir 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 identifica las dos palancas que utiliza este artículo: mantener el model y el coding agent fijos como una caja negra, e idear el contexto y las tools que los rodean. Su planteamiento también explica por qué gran parte del harness acaba siendo código convencional.
El umbral de calidad de una organización, sus procedimientos, el historial de excepciones y sus relaciones de autoridad quedan fuera de lo que un model general puede conocer. El harness los expone como instrucciones del repositorio, reglas de permisos y acceptance checks. Cada ejecución aceptada puede devolver sus lecciones a esos artefactos, en lugar de confiar en que la siguiente sesión las redescubra.
Sigue el cambio del descuento desde la propuesta hasta la aceptación
Para la tarea de descuento definida anteriormente, el model propone cambiar
calculate_discount en src/checkout.py. Antes de que esa edición cuente como
progreso, ocurren varias cosas:
- El constructor de contexto proporciona la tarea, las instrucciones del repositorio, los archivos relevantes, los resultados anteriores de los tools y el plan actual.
- El model propone un call a
edit_filecon una ruta y el texto de sustitución. - El límite de la tool (el código del 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.
- El runtime aplica la edición en el sandbox y devuelve un resultado estructurado.
- El harness ejecuta
pytest tests/test_checkout.py, seguido depnpm playwright test tests/checkout_discount.spec.ts, y lee ambos exit codes. El test de navegador comprueba el descuento visible de $8 en el carrito inicializado de $80. - El harness decide qué significan los resultados. Un check fallido se convierte en contexto nuevo para el siguiente turno del model, y una ejecución correcta hace que la tarea sea candidata a completarse.
- Un resultado correcto solo se convierte en evidencia de finalización después de que el harness registre de forma duradera el comando, el exit code, la snapshot probada, el grader y las versiones del entorno; un trace puede enlazar con ese registro.
Después del paso 2 no ha cambiado ningún archivo. El harness puede rechazar
../../secrets.env, exigir aprobación para un comando destructivo o detener una
ejecución que haya agotado su presupuesto. Ese es el último momento barato que tienes.
Después de ejecutar los tests, el harness lee por sí mismo sus exit codes. El model no
puede marcar su propia edición como correcta.
El registro de aceptación debe identificar la snapshot probada, ambos comandos y sus
resultados, así como las versiones del grader y del entorno; los traces pueden
enlazar con ese registro. Mantén los tests requeridos fuera del ámbito de escritura
del agent o aprueba los cambios de forma independiente antes de hacer el grading.
Cualquier edición posterior de un archivo invalida el resultado. Estos checks
implementan los principios de entorno estable y grader resistente a bypass de la
guía de evaluación de Anthropic. Un mensaje
final de done sin esos registros no demuestra que este cambio haya
superado sus checks requeridos.
Decide dónde se aplica cada regla
El requisito de que tests/checkout_discount.spec.ts termine correctamente
pertenece al código determinista, no al prompt. El harness despacha el comando de
Playwright al runtime, lee su exit code y se niega a terminar la ejecución mientras
falle. Un prompt puede recordar al model que ejecute el test. No puede impedir que
el model declare que ha terminado sin evidencias.
Otras reglas encajan en capas distintas:
| Situar la regla en | Encaja bien con | Ejemplo |
|---|---|---|
| Prompt o skill | Orden de búsqueda, convenciones de coding y formato del plan | Leer AGENTS.md antes de editar código de checkout |
| Límite de la tool | Validación de argumentos, rutas permitidas, aprobaciones y acceso a tools | Permitir escrituras solo bajo src/ |
| Código determinista | Presupuestos, timeouts, reintentos, exit codes de tests y requisitos de release | Mantener abierta la ejecución mientras falle el test de Playwright |
| Evaluator con fresh context | Revisión visual o criterios que requieren juicio similar al humano | Comparar un diagrama generado con una rúbrica escrita |
Los contratos de tools separan propuesta y permiso
La tarea de descuento solo necesita ediciones de archivos y comandos
de tests. Una API que cambia estado tiene un modo de fallo distinto, así que cambiaremos
de ejemplo en esta sección. Supón que el agent puede llamar a
create_test_order contra un servicio de pedidos de staging mientras prepara
datos de prueba. Esta tool no es uno de los acceptance checks de la tarea de descuento.
Resulta útil aquí porque un timeout puede ocultar si el servicio ha creado un pedido.
El límite de la tool necesita más que una descripción en lenguaje natural. Necesita
un contrato explícito de tool. La parte 3
defendía uno desde el lado del model: acciones claras, feedback compacto y errores
recuperables. El harness necesita el mismo contrato por otro motivo. Tiene que decidir,
sin preguntar al model, si un call puede ejecutarse y si un call fallido puede repetirse.
Para create_test_order, eso significa 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 repetir el call es seguro. Esta etiqueta indica al harness si un retry automático podría duplicar trabajo. El harness puede reintentar
get_order_statuscuando el servicio define esa consulta como de solo lectura. No debe reintentar a ciegascreate_test_order, porque el primer call 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 necesita. Consultar el estado de un 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 model. Podría decir:
«Crea un pedido de prueba para verificar el checkout». Esa frase ayuda al model a
decidir cuándo proponer create_test_order. No autoriza el call. En este ejemplo,
el cliente de Model Context Protocol (MCP) del 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. Esto combina las reglas
de permisos y los checks previos a la tool tratados en 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 para el cliente. Un servidor defectuoso o malicioso podría describir
una tool que cambia estado como inofensiva. Un cliente que aceptara 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 de 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 de confianza universal, 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 retry y qué anotaciones siguen siendo meramente informativas.
Reintentar un call que cambia estado requiere protección frente a replay
La parte 5 exige una identidad de operación duradera para los efectos secundarios que pueden duplicarse al reintentar. El harness es quien decide cuándo esa clave debe soportar esa carga. create_test_order crea el pedido, pero se pierde su respuesta HTTP. El harness ve un timeout y no puede saber si el servidor completó la petición. Repetir el call podría crear un segundo pedido.
Persiste un ID de operación propiedad de la aplicación antes del dispatch y vincúlalo a los argumentos aprobados. Reutilízalo al recuperar el mismo pedido previsto, aunque el model genere un ID de tool call nuevo; conserva los IDs del model por separado para la correlación. Reconcilia los payloads modificados o las ventanas de deduplicación del proveedor expiradas en lugar de reenviar a ciegas. El contrato de Stripe, por ejemplo, permite eliminar las keys después de al menos 24 horas.
Una consulta de estado puede reintentarse cuando el servicio la define como de solo lectura. Un call de creación necesita la key: el cliente adjunta un identificador de petición único y el servicio devuelve el primer resultado en lugar de crear otro pedido cuando vuelve a ver ese identificador. Sin esta protección, el harness debe comprobar si el pedido existe o solicitar una decisión humana antes de otro intento. AWS documenta este patrón en su guía sobre APIs idempotentes.
La aceptación necesita evidencias independientes
Una respuesta correcta de create_test_order solo demuestra que
la tool ha devuelto datos. No demuestra que una tarea de coding haya superado sus
tests. Si un test de navegador posterior depende del pedido preparado, el 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 exit code. Para una tarea independiente de diseño visual, un evaluator con fresh context puede comparar una página renderizada o un diagrama con una rúbrica escrita —«fresh context» significa una segunda sesión del model que empieza sin historial de la ejecución y lee los artefactos producidos en lugar del transcript. Compara ese evaluator con revisiones humanas antes de permitir que su resultado decida si la tarea ha terminado.
Una migración del adaptador de pagos necesita un handoff
Volvamos a cambiar de tarea, pero mantengámonos en el repositorio ficticio de la tienda. Ahora el agent tiene que 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 model: un tramo continuo de contexto del model, terminado por un reinicio o por un nuevo comienzo deliberadamente limpio, en lugar de prolongarse.
Antes de que la primera sesión alcance su límite de contexto, ha modificado varios
archivos, ha iniciado un sandbox local de pagos y ha dejado
tests/payment_migration.spec.ts fallando. Ese test de aceptación en el 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 model, 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 recuperarse | Qué incluye | Cómo puede fallar |
|---|---|---|
| Historial de la conversación | Mensajes, tool calls y resultados devueltos | Los detalles antiguos desplazan la tarea actual |
| Entorno de trabajo | Archivos, sandbox de pagos y estado del test de navegador | El transcript dice que un servicio está activo después de que haya muerto |
| Progreso de la tarea | Plan, checks completados, aprobación pendiente y siguiente acción | La siguiente sesión repite trabajo 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 branch 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 para la siguiente sesión del model. Un checkpoint puede conservar ya el plan, los pasos completados, los resultados y el trabajo pendiente. Añade un handoff cuando esos detalles no estén presentes o no sean utilizables en el siguiente contexto, y verifica los archivos y los servicios en ejecución frente al entorno real.
Si la conversación antigua contiene suposiciones obsoletas, el harness puede iniciar una sesión nueva del model con ese handoff y el workspace actual. Sustituir un worker caído y restaurar sus procesos es una tarea independiente de recovery 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 si su estado guardado no conserva un progreso de tarea utilizable, porque la siguiente sesión del model 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 sobre diseño de harness 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 ninguno de esos costes al handoff en sí.
Utiliza traces para distinguir tres fallos
Las tres filas siguientes son esquemas ilustrativos de traces, no ejecuciones medidas ni salidas del lab complementario. Cada fila muestra un fallo distinto y, por tanto, una respuesta distinta del harness.
| Qué registra el trace | Qué ocurrió | Respuesta correcta |
|---|---|---|
El call de solo lectura get_order_status devuelve 503; no hay ningún call que cambie estado en curso | Falló una consulta transitoria | Reintentar la consulta con límite y backoff |
create_test_order termina por timeout y después una consulta de estado encuentra el pedido 123 bajo la key de idempotencia checkout-42 | El servicio creó el pedido, pero se perdió la respuesta | Devolver el pedido existente; no crear otro |
La edición y el test de unidad pasan, pero el trace no tiene resultado para tests/checkout_discount.spec.ts en la snapshot probada | Falta una evidencia de aceptación requerida | Mantener abierta la ejecución y despachar el test de aceptación en el navegador |
Un fallo que parece transitorio no hace que todos los calls sean seguros de reintentar. La primera fila es una consulta de solo lectura. La segunda es una petición que cambia estado, por lo que la key de idempotencia y el estado del servidor deciden si se permite otro intento de creación. La tercera no es un fallo de una tool; el harness todavía no ha recopilado las evidencias necesarias para aceptar el cambio de descuento.
Un transcript de chat registra lo que vio el model. No puede demostrar si el servicio de pedidos confirmó una petición antes de que desapareciera la respuesta. Un trace solo puede aportar esa evidencia si incluye el resultado relevante del servidor o la consulta de estado; un timeout del cliente por sí solo deja el resultado sin resolver. Los registros duraderos de operación y aceptación deben unir el call del cliente, la decisión de aprobación, la identidad de operación, el resultado del servidor o la consulta de estado, la snapshot probada y el resultado del test de aceptación. Los traces pueden exponer esos vínculos para depurar sin convertirse en el ledger de recovery. Esos campos indican al harness en cuál de las tres rutas se encuentra.
| Síntoma repetido | Pequeño cambio que probar | Qué medir |
|---|---|---|
| Las consultas de solo lectura fallan de forma transitoria | Retry acotado con backoff | Tasa de recuperación, calls adicionales y tiempo de pared |
| Las sesiones reanudadas repiten trabajo completado | Progress handoff estructurado | Acciones de tools duplicadas tras reanudar |
| Faltan tests requeridos al completar | Rechazar la finalización hasta que pase cada check requerido | Tareas aceptadas sin todos los checks requeridos |
| Los defectos visuales sobreviven a los checks deterministas | Evaluator con fresh context y una rúbrica | Defectos detectados, rechazos falsos y tiempo de revisión |
| El agent edita fuera de su ámbito | Permisos más restrictivos para las tools | Calls bloqueados y overrides manuales |
| La memoria recuperada desplaza la tarea actual | Limitar los datos recuperados; clasificarlos antes de inyectarlos | Tokens dedicados a recuperar información, tareas completadas y coste por tarea |
Para la asistencia opcional, como ayudas de planificación, resúmenes y evaluators adicionales, identifica el fallo y mide si el componente compensa su coste. La autorización, el aislamiento, los requisitos de privacidad y los acceptance checks obligatorios siguen vigentes aunque las tareas normales pasen sin ellos. Prueba esas restricciones con casos adversariales e invariantes explícitos; un benchmark pequeño de éxito no justifica eliminarlas.
Convertir esos fallos repetidos en una suite de regresión versionada es una tarea propia. La expliqué por separado en Evaluación de AI Agents en producción.
Mide un cambio cada vez
Una ablation mide si un componente del harness produce el efecto esperado cambiándolo o eliminándolo mientras el resto del experimento permanece fijo. Por ejemplo: ¿el linting del editor ayuda a este model en esta suite de tareas?
Utiliza el siguiente protocolo:
- Fija la versión del model, las instancias de tareas, el entorno, el grader y los prompts fuera del componente que se está probando.
- Da a ambas variantes el mismo presupuesto total de tokens, tiempo y dinero.
- Elige el número de trials o la regla de parada antes de ejecutar la comparación.
- Ejecuta las mismas instancias de tareas en ambas variantes. Como las salidas del model varían, repite cada tarea varias veces.
- Publica la media junto con la dispersión o el intervalo de confianza.
- Cuenta cada trial iniciado, incluidos los timeouts, las paradas por políticas, los crashes del harness y los fallos del evaluator.
La tasa de éxito por sí sola puede ocultar un componente caro. Como mínimo, registra las tareas rotas 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. Aumentar en dos puntos las tareas completadas es un mal intercambio si duplica tu cola de revisión.
Un experimento emparejado de la migración de pagos hace medible el progress handoff. Cada par control/tratamiento parte del mismo commit del repositorio y del mismo checkpoint inicializado, con el mismo model, tarea, grader y presupuesto total. El handoff es el único interruptor. La métrica principal cuenta las acciones de tools 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.
El artículo de SWE-agent fija GPT-4 Turbo en la división de 300 tareas de SWE-bench Lite e informa de un 18,0 % de tareas resueltas con su interfaz completa, frente al 11,0 % de un agent con solo shell al que se proporcionó una demostración guiada y el 7,3 % del mismo agent sin ella. La diferencia destacada de 10,7 puntos del artículo se mide frente a la baseline del 7,3 %; la parte 3 trabaja los mismos tres números desde el punto de vista del diseño de interfaces. El artículo también cambió features individuales de la interfaz:
| Cambio de interfaz | Resueltas |
|---|---|
| Interfaz completa de SWE-agent (referencia, sin cambios) | 18,0 % |
| Editor sin linting | 15,0 % |
| Archivo completo en lugar de un viewer de 100 líneas | 12,7 % |
| Historial completo de observaciones en lugar de las cinco últimas | 15,0 % |
Estas cifras corresponden a ese model, benchmark y límite de $4 por tarea. Las tres filas inferiores a la referencia son las pruebas útiles de una sola feature: cada una cambió una feature de la interfaz mientras el model y la configuración de evaluación permanecían fijos.
LangChain publicó una comparación más amplia con el model fijo para deepagents-cli. Informa de un aumento en Terminal-Bench 2.0 del 52,8 % al 66,5 % con gpt-5.2-codex fijo, mientras su equipo cambiaba el system prompt, las tools y el middleware. El post agrupa varios cambios y omite un intervalo de confianza, una comparación con presupuesto total fijo y una tabla de ablations por cambio. Ese resultado no puede identificar qué cambio ayudó. Los nombres de los modelos de esta sección son los que cada estudio fijó en el momento de ejecutarse; lo transferible es el protocolo, no la lista de modelos.
Una comparación más reciente muestra por qué la configuración de la API pertenece a la baseline congelada. En su informe de ARC-AGI-3 del 29 de julio de 2026, OpenAI informa de que la puntuación de GPT-5.6 Sol en el conjunto público subió del 13,3 % al 38,3 % cuando su harness conservó el reasoning y utilizó compaction en lugar de eliminar el reasoning y truncar el historial. La métrica es Relative Human Action Efficiency, no la fracción de tareas resueltas. Se trata de una comparación agrupada comunicada por el proveedor; no aísla las dos configuraciones ni establece un tamaño de efecto en producción. Para una actualización, registra la API, la conservación del reasoning, la política de compaction y los presupuestos junto al ID del model. De lo contrario, una aparente regresión del model podría ser una capacidad ausente en el adaptador.
Incluye la intervención del proveedor en la suite de fallos. Un
misalignment_policy_violation debe llegar a una ruta de parada y revisión incluso después de
haber emitido output en streaming; no es un caso de retry transitorio. La parte 4 cubre su ámbito dependiente de la API. Comprueba que el harness detiene el dispatch y registra los efectos ya completados.
El informe de Anthropic sobre aplicaciones de larga duración 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 del harness comprobó 27 criterios que cubrían su editor de niveles. El trabajo comenzó con modelos Opus anteriores y, cuando se lanzó Opus 4.6, el equipo eliminó componentes del harness uno a uno para comprobar cuáles había vuelto redundantes el nuevo model. Informa de 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 model. El ejemplo justifica volver a validar el scaffolding antiguo cuando cambia el model; no estima un tamaño de efecto general.
Mantén el harness editable después de justificarlo
La ablation mantiene pequeño el harness, pero su código puede sobrevivir al model para el que se ajustó. Una petición como «enmascara los secretos en cada ruta de captura» describe un comportamiento, no un archivo. En un harness de producción, ese comportamiento puede abarcar etapas de ejecución y estado compartido. Antes de poder cambiarlo con seguridad, tienes que encontrar todos los puntos de implementación; y también debe hacerlo el coding agent al que delegues la tarea.
Una opción en fase de investigación es un preprint de 2026 de Wang et al., el Harness Handbook, que denomina a esta búsqueda localización de comportamiento. El handbook construye un mapa centrado en el comportamiento a partir del codebase del harness. El análisis estático, que no necesita calls al model, extrae un grafo del programa y después un LLM organiza sus unidades en etapas de ejecución.
El maintainer o coding agent empieza con una visión general del sistema, abre la etapa de ejecución relevante y desciende hasta entradas basadas en el código fuente para una función o un archivo. Un registro de estado anota dónde se escribe y se lee el estado compartido entre etapas. Esta jerarquía mantiene pequeño el resumen y conserva el camino hasta el código fuente.
La frescura es una regla independiente. El mapa es una ayuda de navegación; el código fuente actual establece el comportamiento. Cada locator debe resolverse contra el repositorio actual. 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 actual antes de escribir el plan y cada diff aplicado vuelve a sincronizar el mapa.
La evaluación del Handbook compara arms emparejados en 30 peticiones por repositorio. No establece presupuestos totales iguales, trials estocásticos repetidos ni estimaciones de incertidumbre, y sus comparaciones publicadas excluyen outputs ausentes y errores del planner. Por tanto, ilustra una parte del protocolo anterior, no todo el protocolo. Cubre dos harnesses open source: Terminus-2 (seis archivos Python) y el monorepo de Codex (2.267 archivos Rust). En cada uno, un planner de solo lectura basado en DeepSeek-V4-Pro exploró el repositorio directamente o se enrutó mediante el handbook. Las peticiones, el repositorio, los permisos de las tools y el decoding eran idénticos en ambos arms. Tres jueces (GPT-5.5, Opus 4.8 y DeepSeek-V4-Pro) puntuaron cada plan de edición en localización, control del ámbito y reasoning; observa que uno de los jueces es el mismo model que produjo los planes. Una victoria significa que la puntuación de calidad de un arm, de 0 a 100, superó la del otro en al menos tres puntos; de lo contrario, esa comparación juez-petición era un empate. La tasa publicada es el número de victorias dividido por las comparaciones juez-petición válidas:
| Harness | Tasa de victorias de la baseline | Tasa de victorias con handbook | Tokens 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 handbook ganó con mayor frecuencia y utilizó menos tokens de planner en ambos repositorios. Las condiciones siguen siendo parte de ese resultado: tres jueces LLM puntuaron planes de edición producidos por un único model planner en dos harnesses. El estudio evaluó planes, no diffs ejecutados ni tasas de defectos en producción.
Prueba el método en el lab complementario
El proyecto harness-demo en el commit 517353f3 es un pequeño ejercicio 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 ficticio de la tienda.
Cada fixture de tarea declara una dificultad y cuatro condiciones booleanas: una tool
inestable, pérdida de progreso, una laguna de implementación no detectada y una
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 ejecuta ningún model ni servicio externo.
Los comandos responden a preguntas distintas:
make checkejecuta Ruff y siete tests de unidad, incluido el validador que rechaza cualquier par de ablation que cambie más de un componente.make runmuestra una matriz didáctica acumulada y después cinco comparaciones válidas dejando fuera un componente cada vez.make failuresindica la condición no gestionada para cada tarea fallida. El harness completo debe terminar conall 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
Para cada fila, el control es la configuración completa con un componente eliminado; el tratamiento restaura únicamente ese componente. La matriz acumulada anterior resulta útil para orientarse, pero algunas filas adyacentes añaden varios componentes a la vez y, por tanto, no pueden identificar una causa.
El lab valida cada par declarado antes de ejecutarlo. Sus tests de regresión también incluyen un par intencionadamente inválido que cambia simultáneamente la política de retry y el evaluator; el validador lo rechaza.
El lab compara los cinco campos de componentes al validar un par. Este fragmento ejecutable muestra la misma protección en un par válido 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 debes abrir cuando algo falla
La serie avanzaba desde el reasoning loop hacia fuera. Empieza por el primer fallo que observes y después investiga el componente responsable de ese trabajo. Una ejecución puede implicar más de un componente:
| Qué hizo la ejecución | Dónde vive la solución | Parte |
|---|---|---|
| Eligió un paso siguiente deficiente pese a tener delante la información correcta | Reasoning loop o model | 1 |
| Repitió trabajo o perdió una decisión tomada una hora antes | Ensamblado de contexto y handoffs | 2 |
| No pudo expresar la acción que necesitaba o interpretó mal un resultado devuelto | Contrato de tool | 3 |
| Hizo algo que nunca debería haber podido hacer | Reglas de permisos | 4 |
| Lo perdió todo cuando un worker murió a mitad de un call | Sesión, checkpoint, sandbox | 5 |
| Declaró que había terminado un trabajo que no estaba hecho | Acceptance checks y traces | 6 |
Cuatro filas apuntan al código del harness, mientras que la fila 5 apunta al runtime. Las instrucciones pueden influir en el comportamiento, pero no pueden sustituir a un check de permisos, un checkpoint duradero o un test de aceptación.
Empieza con un bucle y un acceptance check
Empezaría un harness para coding agents con un model capaz, instrucciones del repositorio, unas pocas tools estrechas, un sandbox y un test de aceptación explícito. Registraría los tool calls, los resultados, los costes y ese test final en un único trace, de modo que los primeros fallos útiles fueran visibles sin tener que reconstruirlos a partir de logs del terminal y transcripts de chat. Esta es una baseline propuesta, no una 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é test de regresión justificaría eliminarlo tras una actualización del model.
Seis meses después, alguien que vea progress_handoff=True debería poder encontrar los
traces fallidos que justificaron su inclusión y los casos de regresión que todavía lo
mantienen. Los traces explican por qué existe el componente; un mapa actual del
comportamiento 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:
- El loop elige el siguiente movimiento.
- La memoria proporciona contexto y un almacén de checkpoints real de Postgres lo conserva.
- Los contratos de tools definen las acciones y las formas de los resultados que pueden leer los checks posteriores.
- La seguridad añade el deny hook y el validador del stop-hook. Ambos siguen siendo esquemas en el ejemplo, pero señalan los puntos de control.
- El runtime mantiene vivo el proceso entre sesiones y fallos.
La serie también añadió una superficie de servidor MCP opcional y un nodo evaluator que comprueba el borrador del informe antes de que lo vea una persona. Encaminar el worker mediante un proxy que conserve las credenciales sigue siendo una extensión propuesta. Son piezas de código convencionales alrededor de un call al model. El router es código del harness por el mismo motivo: elige el patrón de reasoning antes de que comience el reasoning loop.
Para el siguiente componente opcional de asistencia, conserva juntos el trace fallido, la regla de aceptación y la comparación con el componente desactivado. Omítelo si no puedes identificar su beneficio. Las restricciones obligatorias de seguridad y aceptación no dependen de esa comparación.
Referencias
- OpenAI, Unrolling the Codex agent loop.
- OpenAI, Harness engineering: leveraging Codex in an agent-first world.
- Lopopolo, Harness engineering: anthology, field guide, and agent context bundle.
- Anthropic Engineering, Effective harnesses for long-running agents.
- Anthropic Engineering, Harness design for long-running application development.
- LangChain, Improving Deep Agents with harness engineering.
- Yang et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering.
- Wang et al., Harness Handbook: Making Evolving Agent Harnesses Readable, Navigable, and Editable, arXiv:2607.13285, 2026.
- AWS, Making retries safe with idempotent APIs.
- Model Context Protocol, Tools specification.
- Market Analyst Agent Repository
El código de Market Analyst Agent está en GitHub.