การจำกัดอัตราและตรรกะการลองใหม่
การหน่วงเวลาทวีคูณ การจัดการรหัส 429 และการใช้ API อย่างเหมาะสม
การจำกัดอัตราและตรรกะการลองใหม่ เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
การจำกัดอัตราคืออะไร
การจำกัดอัตราคือวิธีที่ API ใช้ป้องกันไม่ให้ระบบของตนเองรับภาระมากเกินไป เมื่อเอเจนต์ของคุณส่งคำขอมากเกินไปในเวลาอันสั้น API จะส่งกลับ 429 Too Many Requests ข้อจำกัดทั่วไป ได้แก่ จำนวนคำขอต่อวินาที ต่อนาที หรือต่อวัน
การเพิกเฉยต่อข้อจำกัดอัตราจะทำให้เอเจนต์ถูกบล็อก คีย์ API ถูกเพิกถอน และมีค่าใช้จ่ายเพิ่มเติม
import requests
response = requests.get(
'https://api.example.com/data',
headers={'Authorization': 'Bearer YOUR_KEY'}
)
if response.status_code == 429:
print('Rate limit exceeded!')
# Check headers for limit details
limit = response.headers.get('X-RateLimit-Limit')
remaining = response.headers.get('X-RateLimit-Remaining')
reset = response.headers.get('X-RateLimit-Reset')
print(f'Limit: {limit}, Remaining: {remaining}, Reset: {reset}')ส่วนหัว Retry-After
เมื่อ API ส่งกลับ 429 มักจะมีส่วนหัว Retry-After ซึ่งระบุจำนวนวินาทีที่ต้องรอก่อนลองใหม่อย่างชัดเจน โปรดเคารพส่วนหัวนี้เสมอ — หากเพิกเฉยและลองใหม่ทันที คุณจะได้รับ 429 อีกครั้ง
import requests
import time
def request_with_retry_after(url, headers):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f'Rate limited. Waiting {retry_after} seconds...')
time.sleep(retry_after)
# Retry once after waiting
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()การหน่วงเวลาแบบทวีคูณ
การหน่วงเวลาแบบทวีคูณคือกลยุทธ์การลองใหม่มาตรฐาน โดยรอนานขึ้นหลังจากแต่ละครั้งที่ล้มเหลว หากครั้งที่ 1 รอ 2 วินาที ครั้งที่ 2 รอ 4 วินาที ครั้งที่ 3 รอ 8 วินาที และเพิ่มขึ้นเช่นนี้ วิธีนี้จะค่อย ๆ ลดภาระของเซิร์ฟเวอร์และเปิดโอกาสให้เซิร์ฟเวอร์กู้คืน
สูตร: wait = 2 ** attempt
import requests
import time
def get_with_exponential_backoff(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers, timeout=(5, 30))
if response.status_code == 200:
return response.json()
if response.status_code in (429, 500, 502, 503):
wait = 2 ** attempt # 1, 2, 4, 8, 16 seconds
print(f'Attempt {attempt+1} failed ({response.status_code}). '
f'Waiting {wait}s before retry...')
time.sleep(wait)
else:
response.raise_for_status() # non-retryable error
raise Exception(f'Failed after {max_retries} retries')การเพิ่มการหน่วงเวลาแบบสุ่ม
หากเอเจนต์จำนวนมากลองใหม่พร้อมกัน ซึ่งเป็นสถานการณ์ที่พบบ่อยหลังระบบขัดข้องชั่วครู่ เอเจนต์ทั้งหมดจะตื่นขึ้นพร้อมกันและสร้างการแห่เข้ามาพร้อมกันจนถูกจำกัดอัตราอีกครั้งทันที การเพิ่มการหน่วงเวลาแบบสุ่มจะกระจายเวลาการลองใหม่ออกไปและลดภาระของเซิร์ฟเวอร์
import requests
import time
import random
def get_with_jittered_backoff(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers, timeout=(5, 30))
if response.status_code == 200:
return response.json()
if response.status_code in (429, 500, 502, 503):
base_wait = 2 ** attempt
# Add random jitter: actual wait is 50%-100% of base
jitter = random.uniform(0.5, 1.0)
wait = base_wait * jitter
print(f'Waiting {wait:.1f}s (attempt {attempt+1})')
time.sleep(wait)
else:
response.raise_for_status()
raise Exception(f'Failed after {max_retries} retries')ไลบรารี tenacity
tenacityเป็นไลบรารี Python ที่ได้รับความนิยมมากที่สุดสำหรับตรรกะการลองใหม่ ไลบรารีนี้จัดการการหน่วงเวลาแบบทวีคูณ การหน่วงเวลาแบบสุ่ม จำนวนครั้งลองใหม่สูงสุด และเงื่อนไขหยุดแบบกำหนดเองด้วยไวยากรณ์ตัวตกแต่งที่สะอาดและอ่านง่าย มีความน่าเชื่อถือมากกว่าวงรอบการลองใหม่ที่เขียนเอง
from tenacity import (
retry, stop_after_attempt, wait_exponential,
retry_if_exception_type, before_sleep_log
)
import requests
import logging
logger = logging.getLogger(__name__)
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=2, max=60),
retry=retry_if_exception_type(requests.exceptions.HTTPError),
before_sleep=before_sleep_log(logger, logging.WARNING)
)
def fetch_data(url, headers):
response = requests.get(url, headers=headers, timeout=(5, 30))
if response.status_code == 429:
response.raise_for_status() # triggers retry
response.raise_for_status()
return response.json()tenacity กับเงื่อนไขการลองใหม่แบบกำหนดเอง
คุณสามารถสอน tenacity ให้ลองใหม่เฉพาะเมื่อพบรหัสสถานะบางรายการ เช่น 429 และ 5xx และหยุดทันทีเมื่อพบข้อผิดพลาดฝั่งไคลเอ็นต์ (4xx) ซึ่งไม่ได้ประโยชน์จากการลองใหม่ ให้ใช้ retry_if_result หรือฟังก์ชันที่เรียกใช้ได้แบบกำหนดเองเพื่อตรวจสอบการตอบกลับ
from tenacity import (
retry, stop_after_attempt, wait_exponential,
retry_if_result
)
import requests
def is_retryable_response(response):
return response.status_code in (429, 500, 502, 503, 504)
@retry(
stop=stop_after_attempt(4),
wait=wait_exponential(multiplier=2, min=2, max=30),
retry=retry_if_result(is_retryable_response)
)
def resilient_get(url, headers):
response = requests.get(url, headers=headers, timeout=(5, 30))
return response # retry logic inspects the response object
# Usage
response = resilient_get(
'https://api.example.com/data',
{'Authorization': 'Bearer YOUR_KEY'}
)
data = response.json()การจัดการการจำกัดอัตราเชิงรุก
กลยุทธ์ที่ดีที่สุดคือหลีกเลี่ยงการชนขีดจำกัดอัตราตั้งแต่แรก ตรวจสอบส่วนหัวการจำกัดอัตราในการตอบกลับทุกครั้ง และลดความเร็วลงเมื่อใกล้ถึงขีดจำกัด API จำนวนมากมีส่วนหัว X-RateLimit-Remaining และ X-RateLimit-Reset
import requests
import time
class RateLimitAwareClient:
def __init__(self, base_url, api_key):
self.base_url = base_url
self.headers = {'Authorization': f'Bearer {api_key}'}
self.remaining = 1000 # assume generous limit
def get(self, path):
# Proactively slow down if nearly exhausted
if self.remaining < 10:
print('Rate limit nearly exhausted, sleeping 5s...')
time.sleep(5)
response = requests.get(
f'{self.base_url}{path}', headers=self.headers
)
# Update remaining from response headers
remaining_str = response.headers.get('X-RateLimit-Remaining')
if remaining_str:
self.remaining = int(remaining_str)
response.raise_for_status()
return response.json()จำนวนครั้งลองใหม่สูงสุดและการยอมแพ้
ตรรกะการลองใหม่ต้องมีขีดจำกัดเสมอ การลองใหม่ไม่สิ้นสุดอาจทำให้เกิดความล้มเหลวต่อเนื่อง โดยเอเจนต์ทั้งหมดติดอยู่ในวงรอบการลองใหม่ หลังจาก max_retries ให้ยกข้อยกเว้นสุดท้ายพร้อมบริบทเกี่ยวกับสิ่งที่ล้มเหลว เพื่อให้เอเจนต์บันทึกข้อมูลและไปทำงานอื่นต่อได้
import requests
import time
class MaxRetriesExceeded(Exception):
def __init__(self, url, attempts, last_status):
self.url = url
self.attempts = attempts
self.last_status = last_status
super().__init__(
f'Failed {url} after {attempts} attempts '
f'(last status: {last_status})'
)
def fetch_with_limit(url, headers, max_retries=3):
last_response = None
for attempt in range(max_retries):
last_response = requests.get(url, headers=headers)
if last_response.status_code == 200:
return last_response.json()
time.sleep(2 ** attempt)
raise MaxRetriesExceeded(url, max_retries, last_response.status_code)รูปแบบตัวตัดวงจร
รูปแบบตัวตัดวงจรป้องกันไม่ให้เอเจนต์ส่งคำขอซ้ำ ๆ ไปยังบริการที่ล้มเหลว หลังจากเกิดความล้มเหลวถึงเกณฑ์ที่กำหนด วงจรจะ "เปิด" และคำขอทั้งหมดจะล้มเหลวทันทีโดยไม่ติดต่อเครือข่าย หลังจากระยะพัก ระบบจะลองส่งคำขอหนึ่งครั้ง หากสำเร็จ วงจรจะปิดและกลับมาทำงานตามปกติ
import time
class CircuitBreaker:
CLOSED, OPEN, HALF_OPEN = 'closed', 'open', 'half_open'
def __init__(self, failure_threshold=5, recovery_timeout=60):
self.state = self.CLOSED
self.failures = 0
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.opened_at = None
def call(self, func, *args, **kwargs):
if self.state == self.OPEN:
if time.time() - self.opened_at > self.recovery_timeout:
self.state = self.HALF_OPEN
else:
raise Exception('Circuit OPEN — service unavailable')
try:
result = func(*args, **kwargs)
self.failures = 0
self.state = self.CLOSED
return result
except Exception as e:
self.failures += 1
if self.failures >= self.failure_threshold:
self.state = self.OPEN
self.opened_at = time.time()
print(f'Circuit OPENED after {self.failures} failures')
raise
# --- demo ---
def flaky():
raise ValueError('upstream 500')
def works():
return 'ok'
cb = CircuitBreaker(failure_threshold=3, recovery_timeout=60)
for i in range(3):
try:
cb.call(flaky)
except Exception as e:
print(f'call {i+1} failed: {e}')
print(f'Breaker state after 3 failures: {cb.state}')
try:
cb.call(flaky)
except Exception as e:
print(f'Rejected without calling flaky(): {e}')
การจัดคิวคำขอให้อยู่ภายในขีดจำกัด
สำหรับเอเจนต์ที่ทำการเรียกจำนวนมากเป็นชุด ให้ใช้ถังโทเค็นหรือตัวควบคุมอัตราแบบหน่วงเวลาอย่างง่ายเพื่อให้อยู่ภายในขีดจำกัด คำนวณช่วงเวลาที่ปลอดภัยระหว่างการเรียกตามขีดจำกัดอัตราของ API เช่น 60 ครั้งต่อนาที = 1 ครั้งต่อวินาที
import requests
import time
def batch_requests(urls, headers, calls_per_minute=60):
interval = 60.0 / calls_per_minute # seconds between calls
results = []
for i, url in enumerate(urls):
start = time.time()
response = requests.get(url, headers=headers, timeout=(5, 30))
response.raise_for_status()
results.append(response.json())
print(f'Processed {i+1}/{len(urls)}')
# Sleep for remaining time in the interval
elapsed = time.time() - start
sleep_time = interval - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
return resultsการผสานตรรกะการลองใหม่กับส่วนหัวการหน่วงเวลา
รูปแบบที่รัดกุมที่สุดคือการผสานเวลารอที่เซิร์ฟเวอร์กำหนด (Retry-After) เข้ากับการหน่วงเวลาแบบทวีคูณเป็นทางเลือกสำรอง โปรดให้ความสำคัญกับคำแนะนำของเซิร์ฟเวอร์เสมอเมื่อมีข้อมูล เพราะเซิร์ฟเวอร์ทราบอย่างชัดเจนว่าคุณจะลองใหม่ได้เมื่อใด
import requests
import time
import random
def smart_retry(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers, timeout=(5, 30))
if response.status_code == 200:
return response.json()
if response.status_code == 429:
# Use Retry-After if provided, else exponential backoff
retry_after = response.headers.get('Retry-After')
if retry_after:
wait = int(retry_after)
else:
wait = (2 ** attempt) + random.uniform(0, 1)
print(f'429 rate limit. Waiting {wait:.1f}s...')
time.sleep(wait)
elif response.status_code >= 500:
wait = (2 ** attempt) + random.uniform(0, 1)
print(f'Server error {response.status_code}. Waiting {wait:.1f}s...')
time.sleep(wait)
else:
response.raise_for_status() # non-retryable
raise Exception(f'Gave up after {max_retries} attempts')ตรวจสอบความเข้าใจอย่างรวดเร็ว: การหน่วงเวลาแบบทวีคูณ
ทดสอบความเข้าใจเกี่ยวกับกลยุทธ์การลองใหม่
สรุปการจำกัดอัตราและการลองใหม่
ตอนนี้เอเจนต์ของคุณสามารถจัดการข้อจำกัดอัตราได้อย่างเหมาะสมแล้ว:
- 429 Too Many Requests — เคารพส่วนหัว
Retry-Afterและรอก่อนลองใหม่ - การหน่วงเวลาแบบทวีคูณ —
wait = 2^attemptเพิ่มเวลารอเป็นสองเท่าในการลองใหม่แต่ละครั้ง - การหน่วงเวลาแบบสุ่ม — เพิ่มความสุ่มเพื่อกระจายการลองใหม่ระหว่างเอเจนต์หลายอินสแตนซ์
- tenacity — จัดการตรรกะการลองใหม่ทั้งหมดด้วยตัวตกแต่งและการกำหนดค่าที่อ่านง่าย
- ตัวตัดวงจร — หยุดการส่งคำขอซ้ำ ๆ ไปยังบริการที่ล้มเหลวหลังจากถึงเกณฑ์ที่กำหนด
- การควบคุมอัตราเชิงรุก — ตรวจสอบ
X-RateLimit-Remainingและลดความเร็วก่อนถึงขีดจำกัด
คำถามที่พบบ่อย
บทเรียน “การจำกัดอัตราและตรรกะการลองใหม่” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การจำกัดอัตราและตรรกะการลองใหม่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจำกัดอัตราและตรรกะการลองใหม่”
การหน่วงเวลาทวีคูณ การจัดการรหัส 429 และการใช้ API อย่างเหมาะสม คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การจำกัดอัตราและตรรกะการลองใหม่” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน REST API สำหรับนักพัฒนาตัวแทน
- การยืนยันตัวตน: คีย์ API และ OAuth
- การจัดการการตอบกลับและข้อผิดพลาดของ API
- การจำกัดอัตราและตรรกะการลองใหม่