Một quá trình di chuyển client OpenAI có thể trông như đã hoàn tất sau hai thay đổi cấu hình: thay API key và trỏ SDK sang một base URL mới. Yêu cầu đầu tiên thành công, dạng phản hồi trông quen thuộc, và pull request có vẻ đã sẵn sàng để merge.
Điều đó chứng minh khả năng tương thích ở mức giao diện. Nó không chứng minh được hành vi trong môi trường production.
Phần khó hơn của quá trình di chuyển client OpenAI là giữ nguyên những gì xảy ra khi lưu lượng trở nên không đều: request đến theo từng đợt, prompt dài hơn, luồng chạy lâu hơn dự kiến, nhà cung cấp trả về 429, hoặc một phản hồi bị timeout sau khi công việc có thể đã bắt đầu. Nếu SDK, ứng dụng của bạn và hàng đợi tác vụ đều tự động thử lại một cách độc lập, một lần gọi thất bại có thể biến thành nhiều lần thử gần như đồng thời.
Bài hướng dẫn này cho thấy cách di chuyển một tích hợp Python hoặc TypeScript kiểu OpenAI hiện có sang một gateway hợp nhất trong khi làm rõ hành vi giới hạn tốc độ và thử lại. Các ví dụ sử dụng base URL tương thích OpenAI của Flatkey, nhưng phương pháp rà soát áp dụng cho mọi quá trình di chuyển gateway.
Trả lời nhanh: điều gì cần thay đổi?
Đối với một quá trình di chuyển client OpenAI an toàn, hãy xem xét các thiết lập này cùng nhau thay vì coi base URL là toàn bộ thay đổi.
| Phạm vi di chuyển | Cần xem xét gì | Quyết định khởi đầu an toàn |
|---|---|---|
| API endpoint | Base URL và xác thực | Thay đổi qua biến môi trường, không rải rác các literal |
| Chọn model | Các định danh model chính xác và các tham số được hỗ trợ | Chốt một model đã biết cho canary |
| Retry của SDK | Số lần thử lại tự động và các mã trạng thái có thể retry | Chọn xem SDK hay ứng dụng của bạn sẽ sở hữu phần retry |
| Retry của ứng dụng | Backoff, jitter, giới hạn số lần thử và ngân sách retry | Chỉ giữ một chủ sở hữu retry và ghi log mọi lần thử |
| Kiểm soát RPM | Tốc độ request đến và kích thước burst | Thêm giới hạn đồng thời hoặc giới hạn hàng đợi trước khi chuyển đổi |
| Kiểm soát TPM | Prompt cộng với số token đầu ra dự kiến | Kiểm thử các prompt lớn thực tế, không chỉ một bài kiểm tra khói một dòng |
| Timeout | Thời gian kết nối, đọc và tổng thời lượng request | Đặt giá trị rõ ràng cho các cuộc gọi đồng bộ và streaming |
| Khả năng quan sát | ID request, số lần thử, token, độ trễ và kết quả cuối cùng | So sánh log của client với log sử dụng của gateway |
Nếu bạn cần phần giải thích ở cấp độ viết tắt trước, hãy đọc Giải thích giới hạn tốc độ LLM: RPM, TPM và retries. Hướng dẫn này bắt đầu từ nơi bài giải thích đó kết thúc: ở diff di chuyển và kế hoạch kiểm thử production.
Vì sao việc đổi base URL là cần thiết nhưng chưa đủ
Tài liệu quickstart của Flatkey mô tả thay đổi client tối thiểu: giữ nguyên mẫu request của OpenAI SDK và đặt base URL thành https://router.flatkey.ai/v1. Tài liệu cũng khuyến nghị kiểm tra Usage Logs sau request để bạn có thể xác minh model, số token, độ trễ và chi phí.
Đó là bài kiểm tra khói đúng. Một quá trình di chuyển client OpenAI trong production cần thêm bốn câu hỏi:
- SDK có tự động thử lại
429, lỗi timeout hoặc lỗi máy chủ không? - Có lớp nào khác cũng thử lại cùng một thao tác bị lỗi đó không?
- Concurrency có bị giới hạn bởi tốc độ request, tốc độ token hay cả hai?
- Bạn có thể phân biệt một thao tác logic với từng lần thử của nó không?
Tài liệu chính thức của OpenAI Python và Node SDK hiện nói rằng các lỗi được chọn sẽ được thử lại hai lần theo mặc định, bao gồm phản hồi 429, lỗi kết nối, timeout và một số lỗi máy chủ. Cả hai SDK đều cung cấp cấu hình retry và timeout. Mặc định đó rất tiện cho một tích hợp trực tiếp, nhưng nó có thể trở thành khuếch đại vô hình khi code của bạn đã tự triển khai backoff.
Mục tiêu của quá trình di chuyển không phải là “tắt mọi lần thử lại.” Mục tiêu là “biết lớp nào chịu trách nhiệm cho retry.”
Bước 1: kiểm kê mọi lớp retry trước khi thay đổi code
Bắt đầu bằng cách vẽ ra đường đi gọi thực tế.
user action or job
-> application retry wrapper
-> queue delivery retry
-> OpenAI SDK retry
-> gateway
-> provider
Với mỗi lớp, hãy ghi lại:
- Lỗi nào kích hoạt một lần thử khác.
- Số lần thử tối đa.
- Việc chờ có dùng sleep cố định, exponential backoff hay jitter.
- Giá trị
Retry-Afterdo server cung cấp có được tôn trọng hay không. - Cùng một định danh thao tác có được giữ nguyên qua các lần thử hay không.
- Liệu một request bị timeout có được coi là đã thất bại trước khi bất kỳ công việc nào xảy ra hay không.
Giả định cuối cùng là rủi ro. Một timeout ở client chỉ cho biết client đã ngừng chờ. Hệ thống phía trên vẫn có thể đã chấp nhận hoặc hoàn thành request. Vì vậy, với nội dung được tạo sinh, một lần retry có thể tạo ra thêm một kết quả nữa và thêm một request tính phí, ngay cả khi ứng dụng của bạn chỉ quan sát thấy một tác vụ logic duy nhất.
Ước tính mức khuếch đại tệ nhất
Giả sử một hàng đợi có thể chuyển một job ba lần, wrapper của ứng dụng cho phép ba lần thử, và SDK thực hiện lần gọi ban đầu cộng thêm hai lần retry. Trong trường hợp xấu nhất, một job logic có thể kích hoạt:
3 queue deliveries × 3 application attempts × 3 SDK attempts = 27 HTTP attempts
Bạn có thể sẽ không bao giờ chạm tới con số đầy đủ đó, nhưng phép nhân này giải thích vì sao một 429 ngắn ngủi có thể biến thành một cơn bão retry. Hãy ghi con số đó vào bản review di chuyển. Nó làm cho các mặc định ẩn trở nên hữu hình.
Bước 2: chuyển cài đặt endpoint vào cấu hình
Giữ cho diff của quá trình di chuyển có thể đảo ngược. Đừng thay thế chuỗi endpoint khắp codebase.
Python trước và sau
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["LLM_API_KEY"],
base_url=os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1"),
max_retries=0,
timeout=45.0,
)
Đối với canary Flatkey, cấu hình:
export LLM_API_KEY="$FLATKEY_API_KEY"
export LLM_BASE_URL="https://router.flatkey.ai/v1"
TypeScript trước và sau
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.LLM_API_KEY,
baseURL: process.env.LLM_BASE_URL ?? "https://api.openai.com/v1",
maxRetries: 0,
timeout: 45_000,
});
Các ví dụ này đặt số lần thử lại của SDK về 0 vì phần tiếp theo sẽ giao quyền thử lại một cách rõ ràng cho ứng dụng. Nếu ứng dụng của bạn không có lớp thử lại, bạn có thể giữ lại các lần thử lại của SDK ở mức giới hạn. Đừng vô tình giữ cả hai.
Để xem danh sách kiểm tra tương thích tổng quát hơn, hãy xem OpenAI Compatible API Gateway: Migration Checklist for Minimal Code Changes.
Step 3: giao quyền thử lại rõ ràng cho một lớp
Một chính sách thử lại hữu ích có năm phần:
- Một danh sách ngắn các lỗi có thể thử lại.
- Một giới hạn số lần thử nghiêm ngặt.
- Một thời gian thử lại tổng tối đa.
- Hồi quy số mũ với độ trễ ngẫu nhiên.
- Log có cấu trúc cho mỗi lần thử.
Đây là một bộ bọc Python nhỏ cho một lệnh gọi chat đồng bộ:
import random
import time
from openai import APITimeoutError, APIConnectionError, APIStatusError, RateLimitError
RETRYABLE_STATUS_CODES = {408, 409, 429, 500, 502, 503, 504}
def create_chat_with_retry(client, *, model, messages, max_attempts=4):
started_at = time.monotonic()
for attempt in range(1, max_attempts + 1):
try:
return client.chat.completions.create(
model=model,
messages=messages,
)
except (RateLimitError, APITimeoutError, APIConnectionError) as error:
retryable = True
caught_error = error
except APIStatusError as error:
retryable = error.status_code in RETRYABLE_STATUS_CODES
caught_error = error
if not retryable or attempt == max_attempts:
raise caught_error
exponential_delay = min(2 ** (attempt - 1), 16)
jitter = random.uniform(0, 0.5 * exponential_delay)
sleep_seconds = exponential_delay + jitter
print({
"event": "llm_retry",
"attempt": attempt,
"next_delay_seconds": round(sleep_seconds, 2),
"elapsed_seconds": round(time.monotonic() - started_at, 2),
"error_type": type(caught_error).__name__,
})
time.sleep(sleep_seconds)
raise RuntimeError("unreachable")
Hãy xem đây là điểm khởi đầu để rà soát, không phải là một chính sách phổ quát. Trong môi trường production, hãy phân tích và tôn trọng header phản hồi Retry-After hợp lệ trước khi quay lại độ trễ được tính toán cục bộ. Thêm ngân sách thời gian trôi qua tổng để các lần thử lại không vượt quá độ trễ mà sản phẩm của bạn có thể chấp nhận.
Không thử lại mọi lỗi
| Lỗi | Hành động mặc định | Tại sao |
|---|---|---|
400 yêu cầu không hợp lệ |
Không thử lại nếu không thay đổi | Payload phải thay đổi |
401 xác thực |
Không thử lại nếu không thay đổi | Khóa hoặc header phải thay đổi |
404 không tìm thấy model |
Không thử lại nếu không thay đổi | Định danh model hoặc quyền truy cập phải thay đổi |
429 giới hạn tốc độ |
Thử lại với độ trễ và độ ngẫu nhiên | Có thể sẽ có dung lượng khả dụng |
500 hoặc 503 |
Thử lại trong phạm vi ngân sách nhỏ | Lỗi có thể chỉ là tạm thời |
| Timeout của client | Thử lại thận trọng | Yêu cầu ở upstream có thể đã được thực thi rồi |
Hướng dẫn khởi đầu nhanh của Flatkey đưa ra cùng một chỉ dẫn cấp cao cho 429: thử lại với exponential backoff và jitter. Điểm bổ sung đặc thù của quá trình di chuyển là phải đảm bảo chỉ có một lớp thực hiện chính sách đó.
Step 4: size concurrency for both RPM and TPM
Di chuyển client OpenAI có thể giữ nguyên cú pháp request trong khi thay đổi “envelope” năng lực. RPM và TPM giới hạn các loại workload khác nhau:
- RPM trở thành nút thắt cổ chai khi bạn gửi nhiều request nhỏ.
- TPM trở thành nút thắt cổ chai khi prompt, output, hoặc các đánh giá song song có kích thước lớn.
Hãy dùng lưu lượng quan sát được thay vì chỉ một giá trị trung bình duy nhất. Thu thập ít nhất:
- Số request mỗi phút ở mức trung vị và mức đỉnh.
- Input token ở p50, p95, và tối đa.
- Output token ở p50 và p95.
- Thời lượng request ở mức trung vị và p95.
- Số luồng đồng thời.
Có thể ước tính một ngưỡng concurrency sơ bộ từ từng giới hạn:
Concurrency dựa trên RPM ≈ (RPM / 60) × số giây trung bình của request
Concurrency dựa trên TPM ≈ (TPM / số token trung bình mỗi request / 60)
× số giây trung bình của request
Hãy dùng kết quả thấp hơn làm ngưỡng ban đầu, sau đó chừa dư địa cho các đợt tăng đột biến và các lần thử lại.
Ví dụ: giả sử một route cho phép 600 RPM và 300,000 TPM, request trung bình dùng 1,500 token tổng cộng, và thời lượng trung bình là 3 giây.
Ngưỡng RPM: (600 / 60) × 3 = 30 request đồng thời
Ngưỡng TPM: (300,000 / 1,500 / 60) × 3 = 10 request đồng thời
TPM là ràng buộc chặt hơn trong ví dụ này. Bắt đầu ở 30 request đồng thời chỉ vì RPM có vẻ rộng rãi sẽ tạo ra các phản hồi 429 có thể tránh được.
Cách tính này chỉ mang tính định hướng, không phải cam kết từ nhà cung cấp. Nhà cung cấp có thể dùng các cửa sổ trượt, token bucket, giới hạn token đầu vào và đầu ra riêng, các pool theo model, hoặc cơ chế kiểm soát tốc độ tăng (acceleration controls). Kế hoạch kiểm thử phải xác minh hành vi thực tế cho model và tài khoản được chọn.
Step 5: test streaming and timeout behavior separately
Đừng coi một lời gọi không streaming thành công là bằng chứng cho thấy streaming an toàn.
Với các request streaming, hãy kiểm thử:
- Thời gian đến token đầu tiên.
- Khoảng im lặng tối đa giữa các chunk.
- Client read timeout.
- Hành vi khi consumer ngắt kết nối.
- Liệu wrapper retry của bạn có vô tình khởi tạo một stream thứ hai hay không.
- Liệu output một phần có được giữ lại, loại bỏ, hay hiển thị cho người dùng.
Một luồng stream thất bại sau khi đã có output một phần không tương đương với một request thất bại trước khi có bất kỳ output nào. Tự động thử lại nó có thể hiển thị văn bản bị lặp hoặc tạo ra một phần tiếp nối khác. Hãy quyết định xem sản phẩm nên thử lại, hỏi người dùng, hay hiển thị kết quả một phần.
Cũng hãy nhớ rằng timeout của SDK và timeout của hạ tầng có thể khác nhau. Một reverse proxy, nền tảng serverless, job worker, hoặc kết nối trình duyệt có thể kết thúc trước khi thư viện client chạm tới timeout của chính nó. Trong quá trình Di chuyển client OpenAI, hãy ghi lại timeout nhỏ nhất trong toàn bộ đường đi của request.
Step 6: run a canary matrix before broad traffic
Sử dụng một model được ghim và một tỷ lệ nhỏ lưu lượng. Canary đầu tiên nên trả lời liệu route mới có giữ nguyên hành vi hay không, chứ không phải liệu mọi model có hoạt động hay không.
| Trường hợp kiểm thử | Đầu vào | Bằng chứng mong đợi |
|---|---|---|
| Xác thực | Khóa hợp lệ và không hợp lệ | Thành công cùng một 401 không được thử lại |
| Kiểm tra mô hình | UUID mô hình hợp lệ và bị viết sai | Thành công cùng một lỗi mô hình không được thử lại |
| Burst yêu cầu nhỏ | Nhiều prompt ngắn | Xếp hàng có kiểm soát mà không tăng đột biến thử lại |
| Burst prompt lớn | Ít prompt có token cao | Áp lực TPM hiển thị rõ và được giới hạn |
Ép 429 |
Tạm thời vượt quá giới hạn canary | Một chủ sở hữu thử lại, độ trễ có jitter, số lần thử được giới hạn |
| Ép timeout | Đặt timeout client cố ý rất ngắn | Ghi log timeout mà không phát lại vô hạn |
| Gián đoạn streaming | Ngắt kết nối trong lúc stream | Hành vi đầu ra một phần được ghi rõ |
| Lỗi máy chủ | Chèn hoặc mô phỏng 503 |
Các lần thử lại được giới hạn và báo cáo lỗi cuối cùng |
| Rollback | Khôi phục base URL trước đó | Rollback chỉ bằng cấu hình thành công |
Với mỗi thao tác logic, hãy ghi:
operation_id
attempt_number
base_url_name
model_requested
http_status
input_tokens
output_tokens
latency_ms
retry_delay_ms
final_outcome
Sau đó so sánh log ứng dụng với Flatkey Usage Logs. Các số đếm phải phù hợp với nhau. Nếu một thao tác ứng dụng ánh xạ tới nhiều yêu cầu gateway, instrumentation retry của bạn nên giải thích lý do.
Step 7: define rollout and rollback thresholds
Một di chuyển client OpenAI nên có các điều kiện dừng bằng số trước khi canary đầu tiên bắt đầu.
Ví dụ ngưỡng:
- Rollback nếu tỷ lệ lỗi cuối cùng tăng nhiều hơn một mức phần trăm đã thỏa thuận.
- Tạm dừng nếu số lần thử trên mỗi thao tác vượt quá ngân sách retry kỳ vọng.
- Tạm dừng nếu độ trễ p95 vượt quá ngân sách timeout của sản phẩm.
- Tạm dừng nếu mức sử dụng token trên mỗi thao tác thành công thay đổi bất ngờ.
- Mở rộng lưu lượng chỉ sau khi cả đường dẫn streaming và non-streaming đều vượt qua.
Tránh chỉ so sánh số lượng 429 thô. Một hàng đợi tốt có thể giảm lỗi cuối cùng trong khi tạm thời tăng số yêu cầu bị trì hoãn. Theo dõi cả kết quả ở mức lần thử và ở mức thao tác.
Migration pull-request checklist
Sao chép checklist này vào PR triển khai.
- Base URL và key lấy từ biến môi trường.
- Canary sử dụng một mã định danh mô hình chính xác, đã được xác minh.
- Một lớp chịu trách nhiệm cho retry.
- Các mặc định retry của SDK được ghi trong PR.
- Hành vi
429, timeout và5xxcó số lần thử giới hạn. - Backoff có jitter và tôn trọng
Retry-Afterkhi có. - Ngưỡng RPM và TPM được ước tính từ lưu lượng quan sát được.
- Streaming có một bài kiểm thử lỗi riêng.
- Mỗi lần thử chia sẻ cùng một
operation_idlogic. - Log usage và log ứng dụng được so sánh.
- Các ngưỡng rollout và rollback được viết ra trước khi khởi chạy.
- Có thể khôi phục endpoint trước đó mà không cần thêm thay đổi code.
Lỗi di chuyển phổ biến
Giữ retry của SDK và retry của ứng dụng mà không tính tổng
Đây là phát hiện review quan trọng nhất. Các giá trị mặc định vẫn là hành vi, ngay cả khi chúng không hiển thị trong hàm cục bộ.
Chỉ kiểm tra một prompt rất nhỏ
Một yêu cầu một dòng chứng minh được thông tin xác thực và khả năng tương thích phản hồi. Nó hầu như không nói gì về áp lực TPM, giới hạn đầu ra, luồng dài hay độ trễ p95.
Thử lại các lỗi xác thực và kiểm tra hợp lệ
Backoff không thể sửa một khóa không hợp lệ, tham số không được hỗ trợ hoặc mô hình bị viết sai. Việc thử lại các payload không thay đổi sẽ lãng phí năng lực và che giấu lỗi thực sự.
Coi timeout là bằng chứng rằng không có yêu cầu nào chạy
Client có thể ngừng chờ sau khi upstream đã chấp nhận cuộc gọi. Hãy thiết kế cơ chế thử lại và hạch toán với sự mơ hồ đó trong đầu.
Thay đổi endpoint, mô hình, prompt và chính sách thử lại trong cùng một bản phát hành
Điều đó khiến việc quy trách nhiệm cho lỗi trở nên khó khăn. Hãy di chuyển trước một dạng yêu cầu đã biết, sau đó mở rộng lựa chọn mô hình khi tuyến đường đã quan sát được.
Định nghĩa an toàn hơn của “tương thích OpenAI”
Trong kế hoạch di chuyển, “tương thích OpenAI” nên có nghĩa là kiểu tương tác đủ quen thuộc để giảm thay đổi mã. Nó không nên được hiểu là lời hứa rằng mọi nhà cung cấp đều có hạn ngạch, cách đếm token, ngữ nghĩa lỗi, độ trễ, hành vi streaming hoặc hỗ trợ tham số giống hệt nhau.
Sự khác biệt đó giúp việc di chuyển client OpenAI dễ review hơn. Hãy giữ giao diện ổn định ở nơi nó hữu ích, nhưng kiểm tra hợp đồng vận hành ở những nơi nhà cung cấp và tuyến đường có thể khác nhau.
Flatkey tập trung quyền truy cập và thanh toán phía sau một base URL tương thích OpenAI duy nhất, điều này có thể đơn giản hóa diff của client và việc mở rộng mô hình sau này. Tuy nhiên, phần việc kỹ thuật vẫn là làm rõ retry, throughput và khả năng quan sát trước khi lưu lượng production chuyển sang.
Đó là tiêu chuẩn mà một di chuyển client OpenAI trong production cần đáp ứng: một thay đổi giao diện nhỏ được hỗ trợ bởi bằng chứng vận hành rõ ràng.
Xem trang giá của Flatkey khi chọn các mô hình cho canary của bạn, sau đó chỉ phê duyệt việc di chuyển sau khi checklist đã đạt trong review mã và hành vi của tuyến đường đã hiển thị trong log.
Câu hỏi thường gặp
Có nên tắt retry của OpenAI SDK trong quá trình di chuyển không?
Hãy tắt nếu ứng dụng hoặc hàng đợi của bạn đã tự xử lý retry. Nếu không có lớp nào khác retry, các retry có giới hạn của SDK có thể hợp lý. Quy tắc quan trọng là tránh nhiều chủ thể retry độc lập.
Sự khác nhau giữa RPM và TPM trong quá trình di chuyển là gì?
RPM giới hạn tần suất yêu cầu, còn TPM giới hạn thông lượng token. Các cuộc gọi nhỏ với tần suất cao có thể chạm RPM trước; ít prompt hoặc đầu ra lớn có thể chạm TPM trước. Hãy kiểm thử cả hai dạng tải.
Có nên luôn thử lại một 429 không?
Chỉ trong phạm vi ngân sách retry và độ trễ có giới hạn. Tôn trọng Retry-After khi có, nếu không thì dùng exponential backoff với jitter. Dừng lại nếu thao tác không còn khả năng đáp ứng mục tiêu độ trễ của sản phẩm.
Có thể an toàn khi thử lại một lần sinh đã timeout không?
Không thể chắc chắn. Yêu cầu upstream có thể đã được thực thi dù client đã timeout. Hãy coi lần thử lại như một yêu cầu trùng lặp có thể xảy ra và ghi log mối liên hệ giữa các lần thử.
Canary an toàn tối thiểu là gì?
Sử dụng một model được ghim, một dạng yêu cầu, quyền sở hữu retry rõ ràng, một giới hạn đồng thời, và các bài kiểm thử cho 429, timeout, gián đoạn streaming, và rollback. So sánh số lần thử ở phía client với nhật ký sử dụng của gateway trước khi mở rộng lưu lượng.



