Guide
Avanzamento e concorrenza
Una suite su un modello reale richiede minuti, e la maggior parte di essi viene spesa ad aspettare il modello. Questa pagina spiega quante chiamate Oloproof tiene in corso contemporaneamente, che cosa ti mostra mentre sono in esecuzione e come scoprire quanto altro lavoro servirebbe per risolvere una regola che non ha deciso.
Concorrenza
concurrency: in oloproof.yaml limita quante chiamate sono in corso contemporaneamente:
concurrency:
system: 4
judge: 4system limita le chiamate al sistema sotto test e vale 8 per impostazione predefinita. judge limita le chiamate ai giudici LLM e vale 4 per impostazione predefinita. Sono separati perché i due di solito sono soggetti a limiti di frequenza diversi.
Centoventi casi su un sistema che impiega un decimo di secondo per chiamata:
| system: | Tempo reale |
|---|---|
| 1 | 13,4 s |
| 16 | 1,7 s |
| invariato, rieseguito | 0,4 s |
L'ultima riga è la cache, non la concorrenza: ogni esecuzione è stata riutilizzata. La concorrenza non fa parte dell'identità di un sistema, quindi modificarla non invalida mai ciò che è memorizzato.
Ogni caso è una chiamata a sé. Oloproof non raggruppa i casi nell'API batch di un provider, quindi lo sconto batch di un provider non è disponibile tramite Oloproof; sono la concorrenza e la cache a rendere più veloce un'esecuzione.
Nuovi tentativi
Un provider di giudici o un sistema HTTP che risponde 429 o un 5xx, va in timeout o interrompe la connessione viene ritentato con backoff, fino a quattro tentativi, e mai prima di quanto chieda un'intestazione Retry-After. Un sistema richiamabile aderisce sollevando TransientError da 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 per impostazione predefinita. Senza di esso l'errore viene registrato sul caso, che risulta quindi mancante anziché ritentato. Un sistema che ha sollevato l'errore in quel modo alla prima chiamata per ciascuno di trenta casi, e ha risposto alla seconda:
│ exact_label │ 100.0% │ [88.4%, 100.0%] │ 30 / 30 observed · 0 missing · 0 excluded │Lo stesso sistema senza retryable=True:
│ exact_label │ │ [0.0%, 100.0%] │ 0 / 0 observed · 30 missing · 0 excluded │Che cosa mostra un'esecuzione mentre è in corso
In un terminale, oloproof run ridisegna una vista in tempo reale sullo standard error: casi completati, hit della cache, errori e una stima provvisoria per ogni metrica binaria. Un fotogramma:
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 didascalia è la regola. Un intervallo provvisorio è un intervallo di Wilson su ciò che è terminato finora: è utile da osservare e non è qualcosa su cui decidere. Viene ricalcolato man mano che arrivano i casi, e un intervallo controllato ripetutamente finché non sembra buono non è più un intervallo al 95%. Nulla interrompe anticipatamente un'esecuzione sulla sua base. La decisione viene presa una sola volta, sull'evidenza completa, con il metodo indicato dalla policy.
Fuori da un terminale, ad esempio in CI, la vista in tempo reale non viene disegnata e le tabelle vengono stampate una sola volta, alla fine.
Il flusso di eventi
--json scrive lo stesso avanzamento come un oggetto JSON per riga sullo standard output, e le tabelle sullo standard error:
oloproof run --jsonUn'esecuzione di 120 casi, salvata in run.ndjson e contata con jq -r '.type' run.ndjson | sort | uniq -c, emette:
120 case_executed
120 case_judged
11 provisional_metrics
1 run_finished
2 run_phase_changed
1 run_startedCiascuno riporta l'id dell'esecuzione e un timestamp:
{"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 riporta l'intervallo di Wilson corrente per ogni metrica 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]Non chiudere la pipe in anticipo. Un lettore che si ferma dopo le prime righe, come head, termina l'esecuzione prima che memorizzi i suoi ultimi casi, e l'esecuzione viene registrata come RUN_ERROR/PARTIAL.
Quanto servirebbe ancora per decidere
Una regola che riporta INSUFFICIENT_EVIDENCE non è fallita; la suite era troppo piccola per distinguere il risultato dalla soglia. oloproof plan dice di quanto dovrebbe essere più grande, con una stima basata su ciò che l'esecuzione ha già speso. Per examples/support_bot/, con diciotto casi:
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 costIl dimensionamento di una regola su un'esecuzione è ammesso solo per i tassi pass/fail. Su una media, il piano lo dice anziché tirare a indovinare:
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 needSe riceve invece l'id di un confronto, pianifica le regole del confronto e non richiede alcun flag.
Dove andare dopo
- Registrare ciò che un sistema ha fatto tratta i dati di latenza e di token su
cui si basano queste stime.
- Esecuzione in CI spiega come leggere il flusso di eventi da uno script.