LLM and web APIs fail transiently with timeouts, rate limits and 503s. The standard fix is to retry with exponential backoff: wait 1s, then 2s, then 4s…
Implement a decorator factory retry(times=3, exceptions=(Exception,), base_delay=1.0, sleep=time.sleep):
times times in total.exceptions, call sleep(base_delay * 2 ** attempt) (attempt = 0, 1, 2…) and try again.exceptions propagate immediately, with no retry.functools.wraps).sleep is a parameter so tests can pass a fake one instead of actually waiting.
Example
@retry(times=3, exceptions=(TimeoutError,), base_delay=0.5)
def call_api(): ...
# on two timeouts then success: sleeps 0.5, then 1.0, then returns