· 7 phút · API

Xử lý giới hạn tốc độ và thử lại trên API LLM

Xử lý giới hạn tốc độ và thử lại trên API LLM

Vào lúc 09:12 một ngày thứ Ba, quy trình tóm tắt của chúng tôi có vẻ hoạt động tốt: 96 tiến trình xử lý đang chạy, độ trễ trung vị của mô hình khoảng 2.8 giây, tỷ lệ lỗi 5xx không tăng cao. Sau đó, một khách hàng tải lên lượng tồn đọng gồm 38,000 phiếu hỗ trợ.

Chỉ trong vòng bốn phút, quy trình đã “ngừng hoạt động” dù không có máy chủ nào ngừng chạy. Chúng tôi đồng thời chạm vào hai giới hạn khác nhau:

  • requests_per_minute: quá nhiều lệnh gọi API
  • tokens_per_minute: tổng lượng prompt và phản hồi quá lớn

Logic thử lại đơn giản khiến tình hình tệ hơn. Mọi tiến trình xử lý đều gặp 429, chờ một giây rồi cùng thử lại. Điều đó tạo ra một làn sóng thử lại, dẫn đến thêm nhiều 429, từ đó tạo ra một làn sóng khác. Hệ thống đã vô tình tạo ra một cuộc tấn công từ chối dịch vụ đồng bộ nhắm vào chính hạn ngạch của mình.

Xử lý giới hạn tốc độ của LLM không chỉ là “thêm cơ chế giãn thời gian chờ theo cấp số nhân”. Trong môi trường vận hành thực tế, bạn cần xem xét token, hàng đợi, mức độ đồng thời, các lần thử lại, tính lũy đẳng, nhà cung cấp dự phòng và cách tính phí như một hệ thống thống nhất.

Hai giới hạn quan trọng: RPM và TPM

Hầu hết API LLM áp dụng một tổ hợp các giới hạn sau:

  • RPM: số yêu cầu mỗi phút
  • TPM: số token mỗi phút
  • RPD / TPD: số yêu cầu hoặc token mỗi ngày
  • Giới hạn yêu cầu đồng thời: số lệnh gọi đang xử lý tối đa
  • Giới hạn riêng theo mô hình: giới hạn cao hơn cho các mô hình nhỏ hơn, giới hạn thấp hơn cho các mô hình tiên tiến nhất

Điểm quan trọng: RPM và TPM gây lỗi theo những cách khác nhau.

Nếu gửi nhiều prompt rất ngắn, bạn sẽ chạm giới hạn RPM trước. Nếu gửi ít prompt hơn nhưng mỗi prompt lại lớn, bạn sẽ chạm giới hạn TPM trước.

Ví dụ:

Limit:
- 600 requests/minute
- 300,000 tokens/minute

Workload A:
- 1,000 short classification calls/minute
- 200 tokens each
- 200,000 tokens/minute total

Result:
- TPM is fine
- RPM fails

Workload B:
- 100 long document analysis calls/minute
- 5,000 tokens each
- 500,000 tokens/minute total

Result:
- RPM is fine
- TPM fails

Một cạm bẫy thường gặp: nhà phát triển điều tiết số yêu cầu nhưng không điều tiết số token. Cách này hoạt động trong môi trường tiền sản xuất, nơi prompt ngắn. Nhưng khi người dùng thực tế dán nội dung PDF, lịch sử trò chuyện, nhật ký hoặc hợp đồng pháp lý, ngân sách token nhanh chóng cạn kiệt.

Trong thực tế, tôi coi mỗi lệnh gọi LLM là việc dành trước hai loại tài nguyên:

cost = {
  requests: 1,
  tokens: estimated_prompt_tokens + max_output_tokens
}

Ngay cả khi mô hình trả về ít token đầu ra hơn max_output_tokens, việc dành trước theo giới hạn trên vẫn giúp tránh cấp phát vượt mức.

Điều gì thực sự xảy ra khi bạn bỏ qua TPM

Giả sử bạn có:

TPM limit: 120,000
Average request: 4,000 input tokens + 1,000 max output tokens
Reserved cost: 5,000 tokens

Thông lượng tối đa thực tế của bạn không phải là “càng nhiều tiến trình xử lý càng tốt”. Nó là:

120,000 / 5,000 = 24 requests per minute

Tức là trung bình cứ 2.5 giây mới có một yêu cầu.

Nếu chạy 100 tiến trình xử lý, toàn bộ lô đầu tiên có thể khởi chạy thành công nếu nhà cung cấp cho phép tải tăng đột biến. Sau đó, tài khoản sẽ chạm giới hạn cứng. Mọi yêu cầu tiếp theo đều nhận được 429, và các lần thử lại dồn ứ.

Cách khắc phục không chỉ là giảm số tiến trình xử lý. Bạn cần một bộ lập lịch có tính đến việc dành trước token.

Bộ giới hạn tốc độ tối giản có tính đến token

Với một tiến trình duy nhất, thuật toán token bucket thường là đủ. Bạn bổ sung dung lượng theo thời gian và yêu cầu mỗi yêu cầu phải được cấp cả một suất yêu cầu lẫn một phần dung lượng token.

Dưới đây là một ví dụ Python đã được đơn giản hóa:

import asyncio
import time
from dataclasses import dataclass

@dataclass
class Bucket:
    capacity: float
    refill_per_second: float
    tokens: float
    updated_at: float

    def refill(self):
        now = time.monotonic()
        elapsed = now - self.updated_at
        self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_per_second)
        self.updated_at = now

    async def acquire(self, amount: float):
        while True:
            self.refill()
            if self.tokens >= amount:
                self.tokens -= amount
                return

            missing = amount - self.tokens
            sleep_for = missing / self.refill_per_second
            await asyncio.sleep(min(sleep_for, 1.0))


class LLMRateLimiter:
    def __init__(self, rpm: int, tpm: int):
        now = time.monotonic()
        self.request_bucket = Bucket(
            capacity=rpm,
            refill_per_second=rpm / 60,
            tokens=rpm,
            updated_at=now,
        )
        self.token_bucket = Bucket(
            capacity=tpm,
            refill_per_second=tpm / 60,
            tokens=tpm,
            updated_at=now,
        )
        self.lock = asyncio.Lock()

    async def acquire(self, estimated_tokens: int):
        async with self.lock:
            await self.request_bucket.acquire(1)
            await self.token_bucket.acquire(estimated_tokens)

Cách sử dụng:

estimated_tokens = prompt_tokens + max_output_tokens
await limiter.acquire(estimated_tokens)

response = await client.chat.completions.create(
    model="gpt-5.5",
    messages=messages,
    max_tokens=max_output_tokens,
)

Ví dụ này được chủ ý giữ đơn giản. Trong hệ thống phân tán, hãy sử dụng Redis, khóa tư vấn của Postgres hoặc hàng đợi có cơ chế điều phối tập trung. Nguyên tắc quan trọng vẫn như nhau: điều tiết cả số lượng yêu cầu lẫn ngân sách token trước khi gọi API.

Thử lại: giãn thời gian chờ là cần thiết nhưng chưa đủ

Thử lại hữu ích đối với:

  • Tạm thời 429 phản hồi
  • Hết thời gian chờ mạng
  • Tạm thời 500, 502, 503, hoặc 504 lỗi
  • Quá tải phía nhà cung cấp
  • Kết nối bị đặt lại

Thử lại có thể gây nguy hiểm đối với:

  • Lỗi kiểm tra tính hợp lệ
  • Lỗi độ dài ngữ cảnh
  • Lỗi xác thực
  • Yêu cầu bị từ chối theo chính sách an toàn
  • Prompt không hợp lệ luôn gây ra cùng một lỗi
  • Lệnh gọi công cụ không có tính lũy đẳng

Chính sách thử lại cần phân loại lỗi trước.

Loại lỗiThử lại?Hành động thường dùng
429 rate_limit_exceededCóGiãn thời gian chờ, tuân thủ các header hướng dẫn thử lại, giảm mức độ đồng thời
500/502/503/504CóGiãn thời gian chờ kèm độ lệch ngẫu nhiên, giới hạn số lần thử
Hết thời gian chờ trước khi nhận phần thân phản hồiCó thểThử lại với khóa lũy đẳng nếu được hỗ trợ
Vượt quá độ dài ngữ cảnhKhôngNén, chia nhỏ hoặc định tuyến đến mô hình có ngữ cảnh dài hơn
Khóa API không hợp lệKhôngVô hiệu hóa khóa, cảnh báo người vận hành
Bị từ chối do nội dung hoặc chính sách an toànKhôngTrả về lỗi có kiểm soát hoặc viết lại yêu cầu
Tác động phụ của công cụ đã được thực hiệnKhông/Có thểCần thiết kế bảo đảm tính lũy đẳng

Dạng cơ bản của cơ chế giãn thời gian chờ:

import random

def retry_delay(attempt: int, base=0.5, cap=30.0):
    exponential = min(cap, base * (2 ** attempt))
    return random.uniform(0, exponential)

Phần random.uniform(0, exponential) đó là độ lệch ngẫu nhiên. Đừng bỏ qua nó.

Không có độ lệch ngẫu nhiên:

100 workers fail
100 workers sleep 1s
100 workers retry
100 workers fail
100 workers sleep 2s
100 workers retry

Có độ lệch ngẫu nhiên:

100 workers fail
workers retry across a spread of 0-1s
then 0-2s
then 0-4s

Mẫu thứ hai tạo khoảng trống để nhà cung cấp và hàng đợi của bạn phục hồi.

Tuân thủ các header thử lại khi có

Nhiều API cung cấp gợi ý như:

Retry-After: 12

hoặc các header đặt lại giới hạn riêng của nhà cung cấp. Nếu API cung cấp thời gian chờ cụ thể, hãy dùng thời gian đó làm mức tối thiểu:

delay = max(header_retry_after_seconds, retry_delay(attempt))
await asyncio.sleep(delay)

Trong thực tế, tôi cũng giới hạn tổng thời gian thử lại. Một yêu cầu trò chuyện trực tiếp với người dùng không nên âm thầm thử lại suốt hai phút trong khi người dùng nhìn biểu tượng tải xoay. Một tác vụ xử lý hàng loạt chạy nền có thể chờ lâu hơn nhiều.

Ví dụ về chính sách:

{
  "interactive_chat": {
    "max_attempts": 3,
    "max_total_retry_seconds": 8
  },
  "batch_summarization": {
    "max_attempts": 8,
    "max_total_retry_seconds": 300
  }
}

Dùng hàng đợi hiệu quả hơn để các worker đồng loạt gửi yêu cầu

Nếu khối lượng công việc vượt quá hạn mức, không nên để tất cả worker trực tiếp gọi API LLM. Hãy đặt một hàng đợi ở phía trước.

Một kiến trúc thực tế:

App/API
  -> Job queue
      -> Rate-aware dispatcher
          -> Provider client
              -> Result store

Bộ điều phối chịu trách nhiệm về:

  • Theo dõi RPM
  • Theo dõi TPM
  • Lựa chọn mô hình
  • chính sách thử lại
  • chuyển sang nhà cung cấp dự phòng
  • giới hạn số tác vụ đồng thời
  • mức ưu tiên trong hàng đợi

Cách này giúp bạn thấy rõ tình trạng quá tải. Thay vì hàng nghìn tác vụ thất bại với 429, bạn sẽ thấy số tác vụ trong hàng đợi tăng lên và thời gian chờ ước tính dài hơn.

Với các hệ thống dùng Redis, tôi thích tách các tác vụ “sẵn sàng chạy” khỏi các tác vụ “chờ thử lại”:

llm:ready
llm:delayed
llm:dead_letter

Một tác vụ thất bại không lập tức quay lại ready. Tác vụ đó được gán mốc thời gian thử lại theo lịch. Một bộ lập lịch nhỏ chuyển các tác vụ đến hạn trở lại hàng đợi sẵn sàng.

{
  "job_id": "sum_7f13",
  "model": "claude-sonnet-4.6",
  "estimated_tokens": 6200,
  "attempt": 2,
  "not_before": "2026-02-03T09:14:22Z"
}

Phần not_before là trường giúp ngăn các đợt thử lại ồ ạt.

Kiểm soát số tác vụ đồng thời khác với giới hạn tốc độ

Giới hạn số tác vụ đồng thời khống chế lượng công việc đang xử lý. Giới hạn tốc độ khống chế lượng công việc trong mỗi khoảng thời gian.

Bạn cần cả hai.

Giả sử mỗi lệnh gọi mất 20 giây và RPM của bạn là 60. Một bộ giới hạn chỉ dựa trên RPM cho phép một yêu cầu mỗi giây. Sau 20 giây, bạn có khoảng 20 lệnh gọi đồng thời. Nếu độ trễ tăng lên 90 giây, cùng mức RPM đó sẽ tạo ra 90 lệnh gọi đồng thời. Điều này có thể vượt quá giới hạn của nhà cung cấp hoặc tài nguyên cục bộ.

Dùng semaphore để kiểm soát số tác vụ đồng thời:

provider_concurrency = asyncio.Semaphore(20)

async def call_model(job):
    async with provider_concurrency:
        await limiter.acquire(job.estimated_tokens)
        return await send_request(job)

Một lỗi dễ mắc: chiếm semaphore quá sớm khiến các worker không làm gì nhưng vẫn giữ những suất xử lý đồng thời khan hiếm trong lúc chờ token cấp phép từ bộ giới hạn tốc độ. Thông thường, hãy lấy quyền gửi yêu cầu theo giới hạn tốc độ trước, rồi chiếm suất xử lý đồng thời ngay trước khi gọi qua mạng. Nếu thời gian chờ bộ giới hạn có thể kéo dài, hãy tránh chiếm tài nguyên worker trong lúc chờ.

Giảm chất lượng có kiểm soát: Dành chất lượng cho những nơi quan trọng

Khi giới hạn tốc độ bắt đầu ảnh hưởng, bạn có những lựa chọn khác ngoài việc để yêu cầu thất bại.

Ví dụ, một trợ lý hỗ trợ khách hàng có thể giảm chất lượng theo các mức sau:

Mức áp lựcChiến lượcẢnh hưởng đến người dùng
Bình thườngDùng mô hình mạnh nhất đã cấu hìnhChất lượng tốt nhất
Áp lực TPM nhẹGiảm max_tokens, rút gọn ngữ cảnh đã truy xuấtCâu trả lời ngắn hơn một chút
Áp lực vừa phảiChuyển các tác vụ đơn giản sang mô hình nhỏ hơnẢnh hưởng tối thiểu nếu việc phân loại/định tuyến dễ dàng
Áp lực caoĐưa các tác vụ không khẩn cấp vào hàng đợiCông việc chạy nền bị trì hoãn
Áp lực nghiêm trọngTrả về câu trả lời đã lưu trong bộ nhớ đệm hoặc theo mẫuChất lượng thấp hơn nhưng vẫn phục vụ được

Ví dụ cụ thể:

  • Định tuyến tác vụ gắn nhãn phiếu hỗ trợ sang Haiku 4.5, Qwen hoặc một biến thể Llama nhỏ thay vì dùng mô hình tiên tiến hàng đầu.
  • Dùng Sonnet 4.6 cho suy luận thông thường và dành Opus 4.8 hoặc GPT-5.5 cho các luồng xử lý nâng cấp.
  • Chỉ chuyển tác vụ phân tích ngữ cảnh dài sang Fable 5 hoặc Gemini 3 khi prompt thực sự cần cửa sổ ngữ cảnh đó.
  • Với các tác vụ xử lý hàng loạt, hãy tạm dừng các tenant có mức ưu tiên thấp trước khi ảnh hưởng đến lưu lượng tương tác.

Đổi lại là độ phức tạp. Mọi luồng dự phòng đều cần kiểm thử, khả năng quan sát và sự chấp thuận từ phía sản phẩm. Trong một số lĩnh vực, câu trả lời kém hơn có thể gây thiệt hại lớn hơn câu trả lời đến muộn.

Dự phòng bằng nhiều khóa và nhiều nhà cung cấp

Định tuyến qua nhiều khóa và nhiều nhà cung cấp có thể cải thiện khả năng chống chịu, nhưng cũng rất dễ triển khai sai.

Có ba mẫu riêng biệt:

MẫuVấn đề được giải quyếtRủi ro
Nhiều khóa, cùng nhà cung cấp/tài khoảnCô lập vận hànhCó thể vi phạm điều khoản của nhà cung cấp nếu dùng để né giới hạn
Nhiều tài khoản/khu vựcCô lập sự cốTăng độ phức tạp trong thanh toán và quản trị
Nhiều nhà cung cấp/mô hìnhTính sẵn sàng và sự linh hoạt về chi phíĐầu ra khác biệt, prompt không tương thích

Đừng dùng nhiều khóa để lách giới hạn. Hãy dùng chúng để phân tách hợp lệ: tenant, môi trường, sản phẩm hoặc phạm vi thanh toán.

Một chính sách định tuyến rõ ràng có thể như sau:

{
  "task": "support_ticket_summary",
  "primary": {
    "provider": "anthropic",
    "model": "claude-sonnet-4.6"
  },
  "fallbacks": [
    {
      "provider": "openai",
      "model": "gpt-5.5",
      "when": ["provider_5xx", "rate_limit_after_retry_budget"]
    },
    {
      "provider": "google",
      "model": "gemini-3",
      "when": ["context_length_needed", "primary_unavailable"]
    }
  ],
  "degrade_to": {
    "provider": "open_model_cluster",
    "model": "qwen",
    "when": ["batch_low_priority"]
  }
}

Nếu bạn dùng một dịch vụ tổng hợp hoặc nền tảng như AI Prime Tech để truy cập nhiều mô hình, các nguyên tắc kỹ thuật tương tự vẫn áp dụng: theo dõi rõ ràng tính lũy đẳng, ngân sách, điều kiện chuyển sang phương án dự phòng và quy tắc tính phí cuối cùng.

Tránh bị tính phí hai lần khi chuyển sang phương án dự phòng

Điểm khó của phương án dự phòng là xác định liệu yêu cầu đầu tiên đã hoàn tất hay chưa.

Hãy xem xét chuỗi sự kiện này:

Client sends request to Provider A
Provider A processes it successfully
Network connection drops before client receives response
Client retries with Provider B
Both providers bill
Two completions may exist

Bạn không thể giải quyết hoàn toàn vấn đề này từ phía máy khách, trừ khi nhà cung cấp hỗ trợ khóa lũy đẳng hoặc tra cứu yêu cầu. Nhưng bạn có thể giảm thiệt hại.

Dùng khóa lũy đẳng khi được hỗ trợ

Tạo một khóa ổn định cho mỗi thao tác logic:

import hashlib
import json

def idempotency_key(task_name, tenant_id, input_payload):
    canonical = json.dumps(input_payload, sort_keys=True, separators=(",", ":"))
    digest = hashlib.sha256(canonical.encode()).hexdigest()
    return f"{tenant_id}:{task_name}:{digest}"

Lưu thao tác trước khi gửi:

{
  "operation_id": "acme:summarize:9d2a...",
  "status": "in_flight",
  "provider": "anthropic",
  "model": "claude-sonnet-4.6",
  "created_at": "2026-02-03T09:12:01Z"
}

Sau đó cập nhật khi hoàn tất:

{
  "operation_id": "acme:summarize:9d2a...",
  "status": "completed",
  "provider_request_id": "req_abc123",
  "usage": {
    "input_tokens": 4180,
    "output_tokens": 612
  }
}

Trước khi thử lại ở nơi khác, hãy kiểm tra bảng thao tác. Nếu một worker khác đã hoàn tất thao tác đó, hãy trả về kết quả đã lưu.

Phân biệt các loại hết thời gian chờ

Không phải mọi trường hợp hết thời gian chờ đều giống nhau:

  • Hết thời gian chờ kết nối: yêu cầu có thể chưa bao giờ đến được nhà cung cấp
  • Hết thời gian chờ đọc trước khi nhận header: không chắc chắn
  • Hết thời gian chờ trong khi truyền token theo luồng: gần như chắc chắn nhà cung cấp đã xử lý yêu cầu
  • Máy khách hủy yêu cầu: phụ thuộc vào việc lệnh hủy có được truyền đến bên xử lý hay không

Với những trường hợp không chắc chắn, tôi ưu tiên một chính sách thử lại thận trọng:

interactive:
- retry connect timeout
- do not cross-provider retry after partial stream
- show recoverable error if status unknown

batch:
- retry after reconciliation delay
- prefer same provider with idempotency key
- fallback only after retry budget expires

Truyền theo luồng một cách thận trọng

Truyền theo luồng cải thiện độ trễ mà người dùng cảm nhận, nhưng khiến việc thử lại phức tạp hơn. Khi bạn đã gửi một phần đầu ra cho người dùng, việc thử lại bằng mô hình khác có thể tạo ra phần tiếp theo khác biệt.

Với trò chuyện truyền theo luồng, tôi thường coi thời điểm “nhận được token đầu tiên” là mốc không thể thử lại ngầm nữa. Sau đó, lỗi sẽ được hiển thị cho người dùng:

"The response was interrupted. Retry?"

Cách này kém tinh tế hơn việc âm thầm phục hồi, nhưng tránh ghép các đầu ra không tương thích từ những mô hình khác nhau.

Khả năng quan sát: Những chỉ số thực sự hữu ích

Bạn cần nhiều hơn tỷ lệ thành công.

Ít nhất hãy theo dõi:

llm_requests_total{provider,model,status}
llm_tokens_reserved_total{provider,model}
llm_tokens_used_total{provider,model}
llm_retries_total{provider,model,error_type}
llm_queue_depth{priority,task_type}
llm_queue_wait_seconds{priority,task_type}
llm_rate_limit_hits_total{provider,model,limit_type}
llm_fallbacks_total{from_provider,to_provider,reason}
llm_duplicate_suppressed_total{task_type}

Trong các sự cố thực tế, ô thông tin hữu ích nhất trên bảng điều khiển thường không phải là độ trễ. Mà là:

queue_wait_seconds p50 / p95
rate_limit_hits by provider and model
tokens_reserved vs tokens_used
fallback rate by reason

Nếu tokens_reserved luôn cao hơn nhiều so với tokens_used, lượng token bạn dự trù quá dư dả. Nếu lượng này quá sát hoặc thấp hơn mức sử dụng thực tế, bạn đang phân bổ vượt hạn mức và sẽ bất ngờ chạm giới hạn TPM.

Một hàm bao thử lại thiết thực

Dưới đây là một mẫu gọn để chỉ thử lại những lỗi đủ điều kiện:

import asyncio
import random
import time

RETRYABLE_STATUS = {429, 500, 502, 503, 504}

class LLMError(Exception):
    def __init__(self, status, message="", retry_after=None):
        self.status = status
        self.retry_after = retry_after
        super().__init__(message)

def jittered_backoff(attempt, base=0.5, cap=20):
    return random.uniform(0, min(cap, base * (2 ** attempt)))

async def call_with_retries(fn, max_attempts=4, max_elapsed=20):
    started = time.monotonic()

    for attempt in range(max_attempts):
        try:
            return await fn()
        except LLMError as error:
            elapsed = time.monotonic() - started
            if error.status not in RETRYABLE_STATUS:
                raise
            if attempt == max_attempts - 1 or elapsed >= max_elapsed:
                raise

            delay = jittered_backoff(attempt)
            if error.retry_after is not None:
                delay = max(delay, error.retry_after)

            remaining = max_elapsed - elapsed
            await asyncio.sleep(min(delay, remaining))

Hàm bao này được cố ý giữ đơn giản. Phần phức tạp nên nằm ở việc phân loại, xếp hàng, bảo đảm tính lũy đẳng và định tuyến—chứ không phải trong một vòng lặp thử lại thần kỳ cứ chạy mãi.

Những điểm thực tiễn cần ghi nhớ

  • Mô hình hóa giới hạn tốc độ theo cả RPM và TPM. Điều tiết dựa trên lượng token giúp tránh những bất ngờ do prompt lớn gây ra.
  • Sử dụng giãn thời gian chờ theo cấp số nhân có thêm độ lệch ngẫu nhiên, và tuân thủ các header hướng dẫn thử lại khi nhà cung cấp trả về chúng.
  • Đặt một hàng đợi và bộ điều phối giữa ứng dụng của bạn và các nhà cung cấp LLM cho khối lượng công việc theo lô hoặc có lưu lượng lớn.
  • Biện pháp kiểm soát mức độ đồng thời riêng biệt với giới hạn tốc độ; nếu không, độ trễ tăng đột biến có thể khiến quá nhiều lời gọi đang xử lý cùng lúc.
  • Thiết kế giảm cấp dịch vụ một cách có kiểm soát một cách có chủ đích: mô hình nhỏ hơn, ngữ cảnh ngắn hơn, công việc nền được đưa vào hàng đợi hoặc phản hồi đã lưu trong bộ nhớ đệm.
  • Xem chuyển sang nhà cung cấp dự phòng như một tính năng bảo đảm độ tin cậy, chứ không phải quyền gửi tràn lan các yêu cầu trùng lặp.
  • Sử dụng khóa lũy đẳng và bản ghi thao tác để giảm việc tính phí hai lần và ngăn kết quả sinh trùng lặp.
  • Thông báo trung thực với người dùng khi phản hồi dạng luồng gặp lỗi sau khi đã phát ra token.
  • Xây dựng bảng theo dõi xoay quanh thời gian chờ trong hàng đợi, lượng token dự trù, số lần chạm giới hạn tốc độ, số lần thử lại và lý do chuyển sang phương án dự phòng.
  • Giữ logic thử lại đơn giản; công việc thực sự trong môi trường sản xuất là lập ngân sách, lập lịch và biết khi nào không nên thử lại.
A

AI Prime Tech xuất bản blog này. Các bài viết được soạn với sự hỗ trợ của AI; hãy đối chiếu những chi tiết phụ thuộc vào phiên bản như ID mô hình, giá và giới hạn với tài liệu chính thức trước khi dựa vào chúng.

Truy cập Claude API với chi phí thấp hơn

Một khóa API cho Claude Opus 5.5, Sonnet 5, Haiku 4.5 và Fable 5.1, cùng GPT-6 mô hình. Thanh toán theo mức sử dụng, không cần đăng ký thuê bao.

Nhận khóa API của bạn →
AI Prime Tech là cổng API bên thứ ba độc lập. Claude™ và Anthropic® là các nhãn hiệu của Anthropic, PBC. Không hàm ý có sự liên kết hay chứng thực.