Lời gọi LLM hỏng vì nhiều lý do khác nhau, và mỗi loại lỗi cần cách xử lý khác nhau — đây mới là phần chính, không phải đoạn code retry.
| Lỗi | Xử lý |
|---|---|
429 quá hạn mức | chờ đúng theo header Retry-After provider trả về |
500 / 503 phía server | lùi theo cấp số nhân |
400 / 401 / 403 | không retry — request sai thì thử lại bao nhiêu lần cũng sai |
| timeout | retry nhưng giới hạn số lần |
from tenacity import retry, wait_exponential_jitter, stop_after_attempt, retry_if_exception_type
@retry(
wait=wait_exponential_jitter(initial=1, max=60), # 1s, 2s, 4s... kèm jitter
stop=stop_after_attempt(5),
retry=retry_if_exception_type((RateLimitError, APITimeoutError)),
)
def call_llm(prompt: str) -> str:
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
timeout=30,
).choices[0].message.contentKhông cần tự viết vòng lặp: tenacity đủ dùng cho Python, và SDK của các provider hiện có sẵn tham số max_retries.
Bốn điểm hay bị bỏ sót:
- Jitter là bắt buộc, không phải tuỳ chọn. Không có jitter thì mọi client cùng gặp
429sẽ cùng chờ đúng 1 giây rồi cùng thử lại — sóng retry đập vào provider đúng lúc nó đang quá tải. Cộng thêm một lượng ngẫu nhiên là tản được sóng đó. - Làm theo
Retry-After. Provider nói chờ 30 giây thì lùi theo cấp số nhân từ 1 giây là vô ích, chỉ tốn thêm lượt gọi hỏng. - Giới hạn tổng thời gian, không chỉ giới hạn số lần. Với request người dùng đang chờ, tổng thời gian có trần (ví dụ 10 giây). Sắp chạm trần thì phải bỏ retry và trả lời, dù còn lượt — retry lần thứ tư về sau khi người dùng đã bỏ đi là vô nghĩa.
- Idempotency key cho các thao tác có tính phí, tránh bị tính tiền hai lần khi retry sau timeout.
Ở tầng cao hơn retry:
- Circuit breaker — provider hỏng kéo dài thì ngắt hẳn một lúc thay vì để mọi request đều chờ hết số lần retry rồi mới lỗi; như vậy hệ fail fast và giữ được tài nguyên.
- Chuyển sang model dự phòng khi model chính không phục vụ được.
- Theo dõi tỉ lệ retry — tỉ lệ tăng đột ngột là tín hiệu sớm của sự cố phía provider, thường thấy trước cả khi lỗi lộ ra ngoài.
Nếu đã có gateway (LiteLLM, Portkey) thì retry, fallback và circuit breaker nằm sẵn ở đó, không cần lặp lại trong từng service.