Skip to content

[PROPOSAL] harbor-style retry + error classification for the API-eval path - #19

Open
penfever wants to merge 1 commit into
mainfrom
feuer/retry-error-classification-plan
Open

[PROPOSAL] harbor-style retry + error classification for the API-eval path#19
penfever wants to merge 1 commit into
mainfrom
feuer/retry-error-classification-plan

Conversation

@penfever

Copy link
Copy Markdown
Collaborator

Design proposal for review — no implementation yet. Greenlight before any code.

Brings harbor's retry + error-classification discipline into evalchemy's API-eval path (eval/robust_api.py over lm-eval's get_batched_requests/amodel_call, i.e. every eval.serve_eval endpoint eval). Today that path retries/fails uniformly, with no idea why a request failed.

Centerpiece — infra-vs-model taxonomy:

  • INFRA_TRANSIENT (conn reset, 5xx, timeouts, garbled body) / RATE_LIMIT (429) → retry with jittered exponential backoff; 429 honors Retry-After.
  • MODEL_CONTEXT (400 context-length) / MODEL_TRUNCATION (finish_reason=="length") → no retry, score as a miss — retrying never converges and wastes budget.
  • FATAL_CONFIG (401/403 auth, non-context 400) → fail loud instead of masking an endpoint-wide fault as a fabricated ~0.0 score. This is the key refinement over Resilient async batch + the :evalchemy-gpu image #18 (which converts every failure to a miss, so a broken run "completes" looking real).

Preserves #18's guarantee (one bad item never nukes the batch) while adding: don't waste budget on non-convergent items, and don't hide a broken run.

Mined from harbor (cited in the doc): lite_llm.py's retry_if_not_exception_type passthrough set (context/output/auth), daytona/utils.py's per-class retry/wait callbacks + transient string patterns, scienceagentbench's 429 jitter backoff, and trial/errors.py's benign-vs-not-scored split.

Doc: docs/retry_error_classification_plan.md — taxonomy table (error → class → policy → outcome), exact hooks in robust_api.py, concrete env-tunable backoff/politeness defaults, and a unit + integration (fault-injecting proxy over the mlx smoke) + flag-off-parity test plan. Entirely within robust_api.py: no lm-eval fork, no pyproject/uv.lock change.

Open questions for the reviewer are listed in §8 (FATAL default = abort vs flag; 429 budget/caps; adaptive cooldown phasing; truncation count-only vs retry-larger).

Design proposal (no code yet) to bring harbor's retry/error-classification
discipline into evalchemy's API-eval path (eval/robust_api.py over lm-eval's
get_batched_requests/amodel_call).

Centerpiece: an infra-vs-model taxonomy so requests are handled by WHY they
failed, not uniformly. INFRA_TRANSIENT/RATE_LIMIT -> retry with jittered
backoff (429 honors Retry-After); MODEL_CONTEXT/MODEL_TRUNCATION -> no retry,
score as a miss (never converges); FATAL_CONFIG (auth / bad payload) -> fail
loud instead of masking a broken run as a fake 0.0 (the anti-masking refinement
over #18). Mined from harbor: lite_llm.py retry_if_not_exception_type passthrough
set, daytona per-class retry/wait callbacks, the scienceagentbench 429 jitter
backoff, and the trial-level benign-vs-not-scored split.

Includes: taxonomy table (error -> class -> policy -> outcome), the exact hooks
in eval/robust_api.py, concrete backoff/politeness defaults (env-tunable), and a
unit + integration + flag-off-parity test plan. Entirely within robust_api.py;
no lm-eval fork, no pyproject/uv.lock change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant