Guías
Progreso y concurrencia
Una suite contra un modelo en vivo tarda minutos, y la mayor parte se pasa esperando al modelo. Esta página explica cuántas llamadas mantiene Oloproof en curso, qué muestra mientras se ejecutan y cómo averiguar cuánta ejecución adicional resolvería una regla que no llegó a decidir.
Concurrencia
concurrency: en oloproof.yaml limita cuántas llamadas hay en curso a la vez:
concurrency:
system: 4
judge: 4system limita las llamadas al sistema bajo prueba y vale 8 por defecto. judge limita las llamadas a los jueces LLM y vale 4 por defecto. Son independientes porque ambos suelen estar detrás de límites de tasa distintos.
Ciento veinte casos contra un sistema que tarda una décima de segundo por llamada:
| system: | Tiempo total |
|---|---|
| 1 | 13.4s |
| 16 | 1.7s |
| sin cambios, repetida | 0.4s |
La última fila es la caché, no la concurrencia: se reutilizaron todas las ejecuciones. La concurrencia no forma parte de la identidad de un sistema, así que cambiarla nunca invalida lo almacenado.
Cada caso es su propia llamada. Oloproof no agrupa casos en la API de lotes de un proveedor, así que el descuento por lotes de un proveedor no está disponible a través de él; lo que acelera una ejecución son la concurrencia y la caché.
Reintentos
Un proveedor de juez o un sistema HTTP que responde 429 o un 5xx, agota el tiempo de espera o corta la conexión se reintenta con backoff, hasta cuatro intentos, y nunca antes de lo que pida un encabezado Retry-After. Un sistema invocable lo activa lanzando TransientError de oloproof con retryable=True:
from oloproof import TransientError, system
@system(name="example-support-bot", version="1")
def answer(case):
...
raise TransientError("provider timed out", retryable=True)retryable vale False por defecto. Sin él, el error se registra en el caso, que queda faltante en lugar de reintentarse. Un sistema que lanzó así la excepción en la primera llamada de cada uno de treinta casos, y respondió en la segunda:
│ exact_label │ 100.0% │ [88.4%, 100.0%] │ 30 / 30 observed · 0 missing · 0 excluded │El mismo sistema sin retryable=True:
│ exact_label │ │ [0.0%, 100.0%] │ 0 / 0 observed · 30 missing · 0 excluded │Lo que muestra una ejecución mientras se ejecuta
En una terminal, oloproof run redibuja una vista en vivo en la salida de error estándar: casos terminados, aciertos de caché, errores y una estimación provisional para cada métrica binaria. Un fotograma:
56/120 cases · 0 cached · 0 errors
┏━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Metric ┃ Estimate ┃ Provisional interval ┃ Cases ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ exact_label │ 89.8% │ [78.2%, 95.6%] │ 49 observed · 0 missing │
└─────────────┴──────────┴──────────────────────┴─────────────────────────┘
Provisional Wilson estimates over finished cases; not a decision.La leyenda es la regla. Un intervalo provisional es un intervalo de Wilson sobre lo que haya terminado, algo útil de observar pero no algo sobre lo que decidir: se recalcula a medida que llegan casos, y un intervalo que se comprueba una y otra vez hasta que tiene buen aspecto ya no es un intervalo del 95%. Nada detiene antes de tiempo una ejecución por él. La decisión se toma una sola vez, sobre la evidencia terminada, con el método que nombra la política.
Fuera de una terminal, por ejemplo en CI, la vista en vivo no se dibuja y las tablas se imprimen una sola vez, al final.
El flujo de eventos
--json escribe el mismo progreso como un objeto JSON por línea en la salida estándar, y las tablas en la salida de error estándar:
oloproof run --jsonUna ejecución de 120 casos, guardada en run.ndjson y contada con jq -r '.type' run.ndjson | sort | uniq -c, emite:
120 case_executed
120 case_judged
11 provisional_metrics
1 run_finished
2 run_phase_changed
1 run_startedCada uno lleva el id de la ejecución y una marca de tiempo:
{"run_id":"run_01M3C3ZNXPVQJCDF31DJSBXBHC","timestamp":"2026-09-25T11:07:37.782628Z","type":"run_started","suite_digest":"sha256:c6ae32f25d38ddac175f688c15c40991c1e0ec5348f32bfabd9c493a3f688c28","cases":120}
{"run_id":"run_01M3C3ZNXPVQJCDF31DJSBXBHC","timestamp":"2026-09-25T11:07:37.885640Z","type":"case_executed","scenario_id":"q000","status":"OK","from_cache":false,"latency_ms":102.11420899941004}
{"run_id":"run_01M3C3ZNXPVQJCDF31DJSBXBHC","timestamp":"2026-09-25T11:07:37.885667Z","type":"case_judged","scenario_id":"q000","criterion":"exact_label","status":"OK","passed":true,"score":null,"from_cache":false}
{"run_id":"run_01M3C3ZNXPVQJCDF31DJSBXBHC","timestamp":"2026-09-25T11:07:41.362779Z","type":"run_finished","status":"DECIDED","completeness":"COMPLETE","exit_code":0}provisional_metrics lleva el intervalo de Wilson en curso para cada métrica binaria:
jq -c 'select(.type == "provisional_metrics") | [.cases_done, .metrics[0].estimate, .metrics[0].wilson_lower, .metrics[0].wilson_upper]' run.ndjson[1,1.0,0.20654931411298355,1.0]
[13,0.8461538461538461,0.5776536895684791,0.9567418216820717]
[25,0.88,0.7004420606159933,0.9583318285288502]
[37,0.8918918918918919,0.7529146844205937,0.9571481006263428]No cierre la tubería antes de tiempo. Un lector que se detiene tras las primeras líneas, como head, termina la ejecución antes de que almacene sus últimos casos, y la ejecución queda registrada como RUN_ERROR/PARTIAL.
Cuánto más haría falta para decidir
Una regla que da INSUFFICIENT_EVIDENCE no ha fallado; la suite era demasiado pequeña para separar el resultado del umbral. oloproof plan indica cuánto más grande tendría que ser, con el costo calculado a partir de lo que la ejecución ya gastó. Para el examples/support_bot/ de dieciocho casos:
oloproof plan RUN_ID --runRun run_01M3C3WS0SBTFAG55M7ECM1EZ4
observed 18 cases
exact-label-floor: about 1614 more cases would decide it, if the observed rate holds (1632 in total)
time <1s – 27s
tokens none reported by this run's providers
assuming the cases to come resemble the 18 already run
cases run one after another; concurrency divides the time and not the costDimensionar una regla de ejecución solo está admitido para tasas de aprobado/fallo. Sobre una media, el plan lo dice en lugar de adivinar:
Run run_01M3C3W5YWJY65X9YM6N02F3W4: no sample size can be computed for a rule that did not decide.
error-budget: sizing a run rule is admitted for binary rates only, and days_error is a MEAN metric: a run stores its summary, not the per-case values sizing one would needSi se le da un id de comparación en su lugar, planifica las reglas de la comparación y no necesita ningún flag.
Siguientes pasos
- Registrar lo que hizo un sistema cubre las cifras de latencia y de tokens a
partir de las que se calcula el costo de estas estimaciones.
- Ejecución en CI cubre cómo leer el flujo de eventos desde un script.