⚙️ Simulador del Harness

Cada paso desde que enviás tu mensaje hasta que recibís la respuesta — system prompt, agentic loop, context window y el recorrido real de los datos por el modelo. Tres hilos conductores: ① el loop request por request, ② los contratos con Pydantic y ③ 13 escenarios simulados, más labs interactivos, concepto clave, payload real, quiz, sandbox y progreso.

Los términos técnicos en inglés tienen subrayado punteado: pasá el mouse (o tocá) para ver su explicación.

🧭 Ruta de aprendizaje

Recorrido sugerido de lo simple a lo complejo. Cada parada abre el escenario en ③ Escenarios y arranca la simulación desde cero. El ✓ marca lo que ya viste. Si es tu primera vez, empezá por y .

Configuración de ③ Escenarios

Qué simular
Reglas del harness
Regla en código, independiente del prompt.
Modelo, ventana y caché
Cambiar el modelo (no borra la simulación) re-liquida la cuenta completa retroactivamente: útil para comparar facturas.
Breakpoint cache_control al final del prefijo estable: se lee a 0,1×, lo nuevo se escribe a 1,25×, mínimo 1.024 tok y expira a los 5 min. Si cambia el prefijo, se invalida desde ahí.
En Anthropic: thinking: {type:"enabled", budget_tokens:N} y bloque thinking antes del texto. En OpenCode se controla con los variants (#high, etc.).
Cómo leer la traza
En los pasos clave te pregunta qué hace el harness y recién después muestra el payload. Lleva score.
Se expande dentro de cada llamada al LLM.
Paso—
Llamadas al LLM0
Tokens enviados / recibidos0 / 0
Costo estimado$0,0000
Cache read (0,1×)0 tok · 0%
Cache write (1,25×)0 tok
Descartado / truncado0 tok
⏱ TTFB (última llamada)—
⏱ Tiempo total Σ0 s
📖 Glosario (58 términos) — buscá uno
Token
Unidad mínima que procesa el modelo (~4 caracteres en inglés). El español suele gastar 20-30% más tokens por el mismo texto.
Ventana de contexto
Máximo de tokens (input + salida reservada) que el modelo puede ver en una llamada. No es memoria: es todo lo que viaja en ese request.
System prompt
Instrucciones de mayor prioridad. En OpenCode lo arma el harness; un system custom lo reemplaza, pero AGENTS.md y skills se siguen agregando.
AGENTS.md
Instrucciones de proyecto que el harness descubre y concatena al system. No las escribe el modelo.
Prefill
Fase en que el proveedor procesa todo el input antes de generar el primer token. Es la parte que acelera la caché.
TTFT / TTFB
Tiempo hasta el primer token (o byte). Incluye red + cola + prefill; no incluye la generación completa.
Decode
Generación autoregresiva, token a token, después del prefill. Su duración depende de los tokens de salida y de tok/s.
Caché de prompt / KV cache
Reutiliza el cómputo del prefijo estable (system + historial viejo). Se cobra más barato y reduce el prefill. Si cambia el prefijo, se invalida desde ahí.
max_tokens
Tope de tokens de salida que reserva el request. Parte de la ventana queda reservada aunque el modelo no la use.
stop_reason
Por qué terminó la generación: end_turn, tool_use, max_tokens, stop_sequence.
tool_use / tool_result
El modelo pide una acción con argumentos estructurados; el harness la ejecuta y devuelve el resultado. El resultado se matchea por id.
tool_choice
Control de uso de herramientas: auto, any/required, una tool forzada, o none.
tool_call_id / tool_use_id
Identificador que correlaciona una llamada con su resultado. En Anthropic: tool_use.id → tool_result.tool_use_id; en OpenAI: tool_calls[].id → tool_call_id. Nunca se empareja por orden.
parameters / arguments
parameters/input_schema es el schema declarado en el request; arguments/input son los datos de una llamada concreta. OpenAI manda arguments como string JSON; Anthropic, input como objeto.
Parallel tool calling
Varias llamadas independientes en un mismo mensaje del assistant. El harness las ejecuta en paralelo y devuelve todos los resultados juntos, emparejados por id.
Pydantic
Librería de Python para modelos tipados y validación. Genera JSON Schema con model_json_schema() y valida con model_validate() o model_validate_json().
max_iterations
Guarda del harness: corta el agentic loop tras N vueltas para evitar bucles infinitos y costos descontrolados.
HITL
Human-in-the-loop: el harness congela el loop y pide aprobación (y/n o TUI con diff) antes de una acción sensible.
Compactación
Reemplazar historial viejo por un resumen para liberar ventana. Cuesta una llamada extra al LLM e invalida la caché desde el resumen.
Truncado
Recortar el contenido de un tool result antes de agregarlo al historial (se avisa con [truncated]). No es lo mismo que compactar.
Subagente
Sesión hija con contexto fresco y su propio loop. El padre solo recibe el informe final: es un cortafuegos de contexto.
JSON mode / structured outputs
Decoding restringido por gramática: garantiza JSON válido según el schema, no que el contenido sea verdadero.
Máscara de logits
En decoding restringido, los tokens inválidos reciben probabilidad 0 antes del sampling. Es lo que hace cumplir el formato.
Caché: escritura y TTL
Crear una entrada de caché suele costar más que un token normal (ej. 1,25×) y tiene vencimiento (ej. 5 min). Leerla es más barato (ej. 10%).
previous_response_id
Estilo Responses API: el proveedor guarda el historial server-side y el cliente manda solo el ID. El modelo sigue siendo stateless.
Streaming / SSE
El proveedor envía deltas por Server-Sent Events. Mejora el tiempo percibido, no el tiempo total ni el costo.
message_start / message_delta
Eventos que abren y cierran el mensaje en el stream. El primero trae usage.input_tokens; el segundo, stop_reason y el usage.output_tokens definitivo.
input_json_delta
Fragmento del JSON de argumentos de un tool_use en streaming. Solo se puede parsear cuando cierra el bloque (content_block_stop).
Usage / tokens facturados
Conteo final que devuelve el proveedor. En streaming, el input se conoce al inicio y el output recién al cerrar: los deltas intermedios no son la factura.
Turno
Una interacción completa: tu mensaje → todas las iteraciones del loop → respuesta final. Un turno puede contener N llamadas al LLM.
Rol (role)
Quién habla en un mensaje: system, user, assistant o tool. El modelo no tiene "memoria": interpreta roles dentro del payload.
Stateless vs stateful
El modelo es stateless (cada forward pass parte del payload). El cliente puede ser stateless (reenvía todo) o usar una API stateful (previous_response_id) que guarda el hilo del lado del proveedor.
Function calling
Capacidad del modelo de emitir una llamada estructurada a una función declarada por el cliente. El modelo propone; el harness valida y ejecuta.
Tool use
Nombre genérico del ciclo anterior cuando la función es una herramienta del agente (leer, editar, buscar, ejecutar). Incluye tools locales, built-in y MCP.
JSON Schema
Contrato legible por máquina que describe nombre, tipo, propiedades y campos requeridos de los argumentos. Se declara en el payload; no vive en el prompt.
Validación de argumentos
Chequeo del harness contra el JSON Schema antes de ejecutar. Un JSON sintácticamente válido puede ser inválido semánticamente (falta un campo, tipo erróneo).
MCP
Model Context Protocol: estándar abierto (JSON-RPC) para que un harness descubra tools, resources y prompts de servidores externos. Para el modelo, una tool MCP se ve igual que una local.
JSON-RPC
Protocolo de mensajes con jsonrpc, method, params e id. Es el transporte que usa MCP sobre stdio o HTTP.
Servidor MCP
Proceso que expone capacidades. Puede ser local (stdio, corre en tu máquina) o remoto (HTTP+SSE). El harness actúa como cliente MCP.
Namespacing de tools
Prefijo que agrega el harness al importar tools externas (mcp__github__create_issue) para evitar colisiones entre servidores.
Trust boundary
Frontera entre datos e instrucciones. El contenido de un archivo, una web o un tool result es dato no confiable; solo el system y el usuario deberían dar órdenes.
Prompt injection
Texto malicioso embebido en un dato (issue, web, README) que intenta que el modelo ejecute acciones no pedidas. Se mitiga con permisos, sandbox y separación de canales.
Tool poisoning
Variante de inyección donde el atacante controla la descripción o el resultado de una tool para sesgar al modelo. La descripción de una tool también es superficie de ataque.
Sandbox / allowlist
Controles del harness: comandos permitidos, directorios accesibles, red bloqueada, timeouts. Son la defensa real; el prompt no es un mecanismo de seguridad.
Idempotencia
Propiedad de una acción que puede repetirse sin efecto adicional. Importa al reintentar: un read es idempotente; un POST o un shell puede no serlo.
Backoff / jitter
Espera creciente entre reintentos (1 s, 2 s, 4 s…) con una variación aleatoria para evitar que muchos clientes reintenten a la vez.
Context rot
Degradación de la calidad cuando el contexto crece con información irrelevante o vieja. Más ventana no siempre es mejor: compactar y subagentes existen por esto.
Lost in the middle
Sesgo por el que el modelo atiende mejor el principio y el final del contexto que lo del medio. Ordenar la evidencia importa.
ReAct
Patrón Reason → Act → Observe (Yao et al., 2022). El loop moderno lo implementa con texto + tool_use + tool_result en vez de parsear texto libre.
Thought / Action / Observation
Nombres de ReAct para las tres fases de una iteración. Mapean a text, tool_use y tool_result.
Hidden agent
Agente interno que el harness ejecuta sin mostrarlo (título de sesión, compactación, resumen). Consume llamadas y tokens reales.
Sesión / snapshot
La sesión persiste el historial entre turnos. El snapshot guarda el estado del repo antes de un cambio para poder deshacer.
Tokenizer / BPE
El tokenizador parte el texto en subpalabras con un vocabulario fijo. En español suele generar más tokens que en inglés para el mismo contenido.
Temperature / top_p
Parámetros de sampling: temperature aplana o agudiza la distribución; top_p recorta la cola. No cambian el contexto ni el esquema de tools.
Stop sequence
Cadena que, si el modelo la genera, corta la respuesta. Distinto de stop_reason, que es el motivo que devuelve el proveedor.
Memoria vs contexto
La memoria es información persistida fuera de la ventana (archivo, DB, AGENTS.md). El contexto es lo que viaja en este request. "Recordar" implica volver a inyectarlo.
Skills / hooks
Skills: instrucciones y recursos que el harness carga bajo demanda. Hooks: código que corre en eventos del ciclo (pre-tool, post-tool) y no pasa por el modelo.
Evals
Conjunto de casos con salida esperada para medir un agente. Sin evals, "mejorar el prompt" es intuición; con evals, es una comparación reproducible.

🔁 El agentic loop, request por request agent.py · Pydantic 2

Seguí un solo mensaje desde que lo escribís hasta que vuelve la respuesta. En cada paso ves qué se agrega a messages, qué viaja en el request, qué vuelve en el response, qué contrato de Pydantic valida esa frontera y qué línea de agent.py se está ejecutando. Tocá un nodo del diagrama para saltar a ese momento.
🔑 Un paso clave: después de llamar al modelo, la respuesta del assistant se agrega a messages antes de ejecutar las tools. El tool_result que viene después la referencia por id: sin ella en el historial, la API rechaza el request.
teclado: ← →
messages[]
REQUEST

              
la línea que se ejecuta en este pasoagent.py

          
🗺 Mismo loop, distintos nombres — el diagrama completo y sus equivalencias
el diagrama completo
[tu entrada]
    │
    ▼
[agregar a messages]        role:"user"
    │
    ▼
[llamar al modelo] ◀────────────────────┐  system + tools + TODO messages
    │                                   │
    ▼                                   │
[agregar la respuesta]                  │  role:"assistant" (texto + tool_use)
    │                                   │
    ▼                                   │
[¿hay tool_use?] ──no──▶ [imprimir texto, volver al REPL]
    │                                   │
   sí                                   │
    ▼                                   │
[validar (Pydantic) → permisos          │  ValidationError → tool_result is_error
 → ejecutar cada herramienta]           │
    │                                   │
    ▼                                   │
[agregar tool_results] ─────────────────┘  role:"user" con bloques tool_result
                                           (OpenAI: un role:"tool" por llamada)
equivalencias entre las vistas del simulador
nodo del diagramaagent.py5 etapasReActmicro-pasos (escenario 3)contrato
tu entradainput()Perceive—antes del loopUserMessage
agregar a messagesmessages.append(user)Perceive—antes del loopmodel_dump()
llamar al modeloclient.messages.createReason (+ Plan)Thought0–5model_json_schema() · Message
agregar la respuestamessages.append(assistant)ActAction (registrada)6ToolUseBlock · id
¿hay tool_use?resp.stop_reasonAct—11 (decisión)StopReason
validar y ejecutarmodel_validate → RUNNERSActAction7–8ReadArgs
agregar tool_resultsmessages.append(results)ObserveObservation9–10ToolResult
imprimir, volver al REPLprint · break— (fin del turno)respuesta finalpost-loopstructured outputs (opcional)
el mismo loop en pseudocódigo (como lo implementa un harness)

        

🧭 Vista conceptual: el loop en 5 etapas iteración 1

Perceive entra el input Reason el modelo decide Plan parte el objetivo Act tool_use / respuesta Observe tool_result
etapa 1 de 5 · entrada del turno
Perceive
harness + modelo
Entra el input: tu prompt, una respuesta del proveedor o un error. El harness lo normaliza y lo agrega al historial. Es el único punto de entrada del turno.
entrada → user message / tool_result / error
Percibir no es "leer todo": el modelo solo ve lo que viaja en la ventana de contexto.
En tareas simples, Plan se saltea: el ciclo es Reason → Act → Observe. Perceive solo ocurre al inicio del turno o cuando llega un input nuevo. Cada paso del recorrido de arriba indica su etapa: tocá el chip etapa para verla acá.
📦 Ejemplo de request / response tool_use
REQUEST lo que se envía

            
RESPONSE lo que vuelve

            

Ventana de contexto (lo que se envía al LLM)

Sin mensajes todavía.
0
system instrucciones historial user assistant tool results tools salida reservada compactado tool error descartado
La ventana es la suma de system + instrucciones + todos los mensajes + salida reservada. Cuando se llena, el harness compacta el historial antes de la próxima llamada.

🗑️ Descartado / truncado (NO viaja en el payload)

Nada descartado en esta simulación.