Add retry mechanism for transient LLM failures and completeness tracking - #77
Merged
Conversation
Resolve all ruff, black, and mypy issues: add type annotation for _call_with_retry, fix import sorting, modernize type hints in conftest, add tz-aware datetime calls, and clean up pre-existing lint warnings surfaced by the changed file set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
generate()wraps_do_generate()with retry logic). Transient errors (408, 429, 5xx, connection/timeout) are retried up to 4 times with 30s base delay and 5 min cap. Non-transient errors (400, 401, 403, 404, ValueError) propagate immediately.runner.run(),get_completeness_report()returns expected/present/skipped/failed counts. Transient failures (retries exhausted) are distinguished from legitimate skips (e.g. distractor metric on true/false questions). Acompleteness.jsonis written to the run bundle, and the process exits non-zero when transient failures remain.Motivation
A real benchmark run (8 models, 4 quizzes, 9 metrics, 288 expected cells) produced only 279 results. One cell vanished due to a 503 queue timeout —
_evaluate_questioncaught it, logged it, returnedNone, and the row silently disappeared. The upcoming research sweep (~63,500 calls) cannot tolerate silent data loss.Configuration
Retry parameters are configurable per evaluator in YAML:
retry_max_attemptsretry_base_delayretry_max_delayTest plan
test_transient_503_is_retried— 503 triggers retry, succeeds on second attempttest_non_transient_400_not_retried— 400 propagates immediately, no sleeptest_transient_failure_reports_incomplete—TransientLLMError→complete: falsetest_skipped_error_does_not_fail_completeness—ValueError→ skip,complete: true🤖 Generated with Claude Code