Xử lý lỗi
Yêu cầu thất bại trả về một mã trạng thái HTTP và nội dung JSON gồm loại lỗi và thông báo. Trang này liệt kê mọi trạng thái, cho thấy nội dung lỗi của từng định dạng API và nói rõ những lỗi nào đáng gửi lại.
Các SDK ném ra một đối tượng lỗi mang mã trạng thái và các trường của nội dung. Yêu cầu này nêu một model không tồn tại:
import openai
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1",
)
try:
client.chat.completions.create(
model="no-such-model",
messages=[{"role": "user", "content": "Hello"}],
)
except openai.APIStatusError as error:
print(error.status_code) # 400
print(error.type) # invalid_request_error
print(error.body["message"]) # unknown model: no-such-model
print(error.response.headers.get("x-request-id")) # the id of this request import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.shannon-ai.com/v1",
});
try {
await client.chat.completions.create({
model: "no-such-model",
messages: [{ role: "user", content: "Hello" }],
});
} catch (error) {
if (!(error instanceof OpenAI.APIError)) throw error;
console.log(error.status); // 400
console.log(error.type); // invalid_request_error
console.log(error.error.message); // unknown model: no-such-model
} curl -i https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "no-such-model",
"messages": [{"role": "user", "content": "Hello"}]
}' Nó trả về trạng thái 400 và nội dung này:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} Nội dung lỗi
Có hai dạng nội dung. /v1/messages trả lời theo định dạng Anthropic; mọi endpoint khác trả lời theo định dạng OpenAI. Ở cả hai, chi tiết nằm trong error.type và error.message, nên một bộ đọc phục vụ được mọi endpoint.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
} | Trường | Loại | Mô tả |
|---|---|---|
error.type | string | Loại lỗi. Xem Các loại lỗi bên dưới. |
error.message | string | Một câu dành cho con người. Văn bản trong các bảng bên dưới ổn định trừ các phần biến đổi, được thể hiện bằng <id>, <n> hoặc …. |
error.code | string | null | Có ở một số lỗi của định dạng OpenAI: invalid_api_key với 401, request_too_large với 413, context_length_exceeded khi cuộc hội thoại quá dài, còn lại là null hoặc không có. Hãy quyết định dựa trên trạng thái và error.type trước, và coi code là thông tin bổ sung. |
error.param | null | Có ở cùng các lỗi như code. Luôn là null. |
type | string | Chỉ có ở định dạng Anthropic. Luôn là error. |
Các loại lỗi
| Loại | Trạng thái | Mô tả |
|---|---|---|
invalid_request_error | 400, 413, 415, 422 | Bản thân yêu cầu sai: một trường, nội dung, model id hoặc một đầu vào mà model không nhận. Hãy thay đổi yêu cầu trước khi gửi lại. |
authentication_error | 401 | API key bị thiếu, không xác định hoặc đã bị thu hồi. |
not_found_error | 404 | Đường dẫn không tồn tại. |
rate_limit_error | 429 | Số dư không đủ cho yêu cầu, flood protection đã chặn nó, hoặc model đang bận. Thông báo cho biết là trường hợp nào. |
api_error | 500, 502, 503, 504 | Yêu cầu không có vấn đề và lỗi nằm ở phía chúng tôi. Hãy gửi lại. |
server_error | 500 | Yêu cầu không có vấn đề và lỗi nằm ở phía chúng tôi. Hãy gửi lại. |
Mã trạng thái
| Trạng thái | Loại | Thông báo | Khi nào |
|---|---|---|---|
400 | invalid_request_error | Failed to parse the request body as JSON: … | Nội dung không phải là JSON hợp lệ. |
400 | invalid_request_error | unknown model: <id> | model không phải là id đã công bố. Trên /v1/responses, cũng xảy ra khi thiếu model. |
400 | invalid_request_error | No user message provided | Các bậc Shannon: yêu cầu không chứa văn bản người dùng. |
400 | invalid_request_error | <id> does not accept image input | Một hình ảnh đã được gửi tới model open-weight hosted không hỗ trợ đầu vào hình ảnh. |
400 | invalid_request_error | audio and video input are not supported by any hosted model | Một phần âm thanh hoặc video đã được gửi tới model open-weight hosted. |
400 | invalid_request_error | <id> does not accept response_format | Đầu ra có cấu trúc được yêu cầu từ một model open-weight hosted không hỗ trợ. |
400 | invalid_request_error | <id> does not accept response_format json_schema; use json_object | Một JSON schema đã được gửi tới model open-weight hosted chỉ nhận json_object. |
400 | invalid_request_error | unknown reasoning effort '<value>'; expected off, low, medium or high | Mức độ suy luận không thuộc các giá trị được liệt kê. Các model open-weight hosted. |
400 | invalid_request_error | count_tokens is available for the hosted open models; unknown model: <id> | Việc đếm token được yêu cầu cho một model nằm ngoài các model open-weight hosted. |
401 | authentication_error | Missing authentication | Không có API key nào được gửi. |
401 | authentication_error | Invalid API key | Key không xác định, đã bị key mới hơn thay thế, hoặc đã bị thu hồi. |
404 | not_found_error | Not Found | Đường dẫn không tồn tại, ví dụ /v1/embeddings. |
405 | api_error | Method Not Allowed | Đường dẫn tồn tại nhưng không với phương thức HTTP này. |
413 | invalid_request_error | Failed to buffer the request body: … | Nội dung yêu cầu lớn hơn 32 MiB. |
415 | invalid_request_error | Expected request with `Content-Type: application/json` | Header Content-Type bị thiếu hoặc không phải là application/json. |
422 | invalid_request_error | Failed to deserialize the JSON body into the target type: … | Thiếu một trường bắt buộc, như messages, hoặc một trường có kiểu JSON sai. |
429 | rate_limit_error | Quota exceeded. Upgrade your plan at shannon-ai.com/plan | Giới hạn đầu ra của yêu cầu lớn hơn phần còn lại trong số dư của bạn. |
429 | rate_limit_error | Too many requests. Retry in <n>s. | Flood protection: hơn 120 yêu cầu trong một phút trên tài khoản của bạn. <n> là số giây cho đến khi hết phút. |
429 | rate_limit_error | Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan | shannon-coder-1 trên /v1/chat/completions và /v1/messages: các lượt gọi Shannon Coder của gói bạn trong khung 4 giờ hiện tại đã dùng hết. |
429 | rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model đang bận vào lúc này. |
500 | server_error | The model backend failed to answer. Please retry. | Model không tạo ra phản hồi. |
500 | server_error | An internal error occurred. Please retry. | Một lỗi nội bộ trong lúc chuẩn bị yêu cầu. |
502 | api_error | The model backend failed to answer. Please retry. | Model không tạo ra phản hồi. Dòng Shannon 3 và các model open-weight hosted. |
503 | api_error | Could not verify your quota right now. Please retry. | Không thể đọc số dư của bạn vào lúc này. |
503 | api_error | token counting is temporarily unavailable for this model | Việc đếm token hiện không khả dụng cho model này. |
504 | api_error | upstream timed out | Một model open-weight hosted mất nhiều thời gian hơn giới hạn thời gian của yêu cầu không streaming. |
Các bước kiểm tra chạy theo thứ tự này: API key, nội dung yêu cầu, model id, flood protection, số dư. Vì vậy yêu cầu có key sai và nội dung sai trả về 401. Yêu cầu bị từ chối với trạng thái 4xx không bị tính phí.
Số dư và flood protection
Mọi yêu cầu được phục vụ như nhau: không có bậc giới hạn tốc độ và không có hạn ngạch API riêng. Hai điều vẫn có thể trả lời 429, cả hai đều với loại rate_limit_error. Thông báo cho biết đó là điều nào.
Số dư
Số dư của bạn là hạn mức gói của hôm nay, được đặt lại lúc 00:00 UTC, và sau đó là tín dụng đã mua. Chat và API lấy từ cùng một số dư.
Mỗi yêu cầu trước hết giữ lại giới hạn đầu ra của nó: max_tokens, hoặc max_output_tokens trên /v1/responses, là 4,096 khi bạn không gửi cái nào. Khi phản hồi hoàn tất, lượng đã giữ được thay bằng lượng yêu cầu thực dùng. Nếu lượng đó không vừa với số dư còn lại, yêu cầu trả về Quota exceeded trước khi model bắt đầu.
Các yêu cầu chạy cùng lúc mỗi yêu cầu giữ lại lượng riêng của nó. Vì vậy nhiều yêu cầu song song với max_tokens cao có thể tạm thời dùng hết số dư, ngay cả khi mỗi phản hồi ngắn. max_tokens thấp hơn giữ lại ít hơn.
Flood protection
Flood protection cho phép 120 yêu cầu mỗi phút cho mỗi tài khoản. Nó đếm theo tài khoản, không theo key, gộp chung /v1/chat/completions, /v1/responses và /v1/messages. Phút bắt đầu từ yêu cầu đầu tiên của bạn.
Yêu cầu thứ 121 trong phút đó trả về Too many requests. Retry in <n>s. và không tốn gì. Các yêu cầu bị từ chối cũng được đếm, nên client gửi lại mà không chờ sẽ tiếp tục bị từ chối cho đến hết phút. Hãy chờ <n> giây theo thông báo.
Các yêu cầu gửi song song không bị từ chối chỉ vì song song. Chúng xếp hàng chờ và được trả lời lần lượt.
GET /v1/models và các endpoint đếm token không được tính.
Thêm về giới hạn và số dư, và nơi xem số dư và mức sử dụng của chính bạn: Giới hạn và số dư Keys & usage
Nên thử lại khi nào
Chỉ gửi lại một yêu cầu khi chính yêu cầu đó có thể thành công. OpenAI SDK và Anthropic SDK đã tự thử lại hai lần với phản hồi 429 và 5xx; đặt max_retries (maxRetries trong JavaScript) để thay đổi điều đó.
| Lỗi | Gửi lại? | Cách làm |
|---|---|---|
400, 404, 405, 413, 415, 422 | Không. Hãy sửa yêu cầu trước. | Thông báo nêu tên trường, model hoặc đầu vào bị sai. |
401 | Không. Hãy dùng key hợp lệ. | Tạo hoặc thay key ở trang Keys & usage. |
429 Too many requests | Có, sau khi chờ. | Chờ số giây ghi trong thông báo, rồi gửi lại cùng yêu cầu. |
429 Quota exceeded | Không nếu để nguyên. | Giảm max_tokens, chờ đặt lại hàng ngày lúc 00:00 UTC, hoặc nạp thêm tín dụng. |
429 Shannon Coder call quota reached | Có, ở khung tiếp theo. | Các khung bắt đầu mỗi 4 giờ kể từ 00:00 UTC. Một model khác trả lời ngay. |
429 … temporarily busy | Có. | Chờ vài giây, rồi chờ lâu hơn ở mỗi lần thử tiếp theo. |
500, 502, 503 | Có. | Chờ 1 giây, rồi 2, 4 và 8. Dừng sau vài lần thử và báo cáo request id. |
504 | Có. | Gửi với stream đặt là true: giới hạn thời gian áp dụng cho các phản hồi không streaming. |
Một vòng lặp thử lại theo bảng này:
import re
import time
import openai
from openai import OpenAI
# max_retries=0: this loop does the retrying, the SDK does not add its own.
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1", max_retries=0)
def create_with_retry(attempts=5, **request):
for attempt in range(attempts):
try:
return client.chat.completions.create(**request)
except openai.RateLimitError as error:
text = str(error)
flood = re.search(r"Retry in (\d+)s", text)
if flood:
time.sleep(int(flood.group(1))) # flood protection: wait out the minute
elif "temporarily busy" in text:
time.sleep(2 ** attempt)
else:
raise # balance: a wait of seconds does not help
except (openai.InternalServerError, openai.APIConnectionError):
time.sleep(2 ** attempt) # 1, 2, 4, 8 seconds
raise RuntimeError("the request failed after all attempts")
response = create_with_retry(
model="shannon-3",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content) import OpenAI from "openai";
// maxRetries: 0 — this loop does the retrying, the SDK does not add its own.
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1", maxRetries: 0 });
const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));
async function createWithRetry(request, attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return await client.chat.completions.create(request);
} catch (error) {
const text = String(error.message);
const flood = text.match(/Retry in (\d+)s/);
if (error.status === 429 && flood) {
await sleep(Number(flood[1])); // flood protection: wait out the minute
} else if (error.status === 429 && text.includes("temporarily busy")) {
await sleep(2 ** attempt);
} else if (error.status >= 500 || error instanceof OpenAI.APIConnectionError) {
await sleep(2 ** attempt); // 1, 2, 4, 8 seconds
} else {
throw error; // wrong request, wrong key or balance
}
}
}
throw new Error("the request failed after all attempts");
}
const response = await createWithRetry({
model: "shannon-3",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content); Lỗi bên trong stream
Stream có trạng thái 200 từ byte đầu tiên. Lỗi xảy ra sau đó đến dưới dạng một sự kiện bên trong stream: một chunk có thành phần error trên /v1/chat/completions, một sự kiện error trên /v1/messages, một sự kiện response.failed hoặc error trên /v1/responses. Các sự kiện kết thúc của stream vẫn theo sau. Hãy coi phản hồi như vậy là thất bại và gửi lại yêu cầu, như với trạng thái 5xx.
Cuộc hội thoại dài hơn cửa sổ ngữ cảnh của model được báo theo cách này, với loại invalid_request_error và mã context_length_exceeded. Hãy rút ngắn cuộc hội thoại trước khi gửi lại.
Các frame chính xác được mô tả trong phần streaming. Truyền phát
Request id
Mọi phản hồi, kể cả lỗi, đều có header x-request-id. Đó là giá trị bạn gửi trong header x-request-id của riêng bạn, hoặc 12 ký tự thập lục phân khi bạn không gửi. Hãy ghi log nó, và dẫn nó khi bạn nhờ trợ giúp về một yêu cầu.