Khi hoàn thành hướng dẫn này, bạn sẽ biết cách gọi Batch API của OpenAI để chạy hàng nghìn yêu cầu mô hình dưới dạng một tác vụ bất đồng bộ, nhận kết quả trong một tệp đầu ra và tiết kiệm 50% chi phí token. Quy trình gồm: tạo tệp JSONL, tải tệp lên, tạo batch, thăm dò trạng thái, tải kết quả và kiểm tra từng bước trong Apidog trước khi đưa vào production. Nếu use case của bạn cần phản hồi tức thì, hãy dùng API đồng bộ và tham khảo cách kiểm tra ChatGPT API bằng Apidog.
Batch API là gì và khi nào nên dùng?
Batch API là endpoint bất đồng bộ cho các workload lớn nhưng không yêu cầu phản hồi ngay. Thay vì gửi từng HTTP request cho từng prompt, bạn gom nhiều request vào một tệp JSONL, upload tệp đó, tạo một batch job và thăm dò cho đến khi job hoàn tất.
Batch API phù hợp khi bạn có dữ liệu lớn cần xử lý offline:
- Phân loại hoặc gắn thẻ dữ liệu tồn đọng
- Tạo embeddings cho toàn bộ dataset
- Tạo nội dung hàng loạt như mô tả sản phẩm, tóm tắt, bản dịch
- Chạy bộ đánh giá hoặc so sánh model trên nhiều mẫu
- Backfill dữ liệu bằng LLM
Đổi lại, bạn phải chấp nhận độ trễ. OpenAI cam kết batch hoàn thành trong vòng 24 giờ. Nhiều job có thể xong sớm hơn, nhưng hệ thống của bạn nên thiết kế theo giới hạn 24 giờ.
Không dùng Batch API cho các luồng mà người dùng đang chờ phản hồi, ví dụ:
- Chat UI
- Autocomplete
- Agent tương tác trực tiếp
- API request nằm trên critical path của sản phẩm
Nếu bạn đang tạo nhiều cấu hình model hoặc agent cùng lúc, batch là lựa chọn phù hợp. Bạn có thể xem thêm hướng dẫn tạo hơn 100 cấu hình tác nhân bằng xử lý hàng loạt.
Tổng quan quy trình
Batch API thường đi qua 4 bước chính với hai nhóm endpoint: /v1/files và /v1/batches.
| Bước | Endpoint | Mục đích |
|---|---|---|
| 1. Upload | POST /v1/files |
Upload tệp .jsonl với purpose: "batch" và nhận file_id
|
| 2. Tạo batch | POST /v1/batches |
Tạo batch job từ input_file_id
|
| 3. Thăm dò | GET /v1/batches/{id} |
Kiểm tra status cho đến khi completed
|
| 4. Tải kết quả | GET /v1/files/{id}/content |
Tải output bằng output_file_id
|
Bạn cần chuẩn bị:
- OpenAI API key, export dưới biến môi trường
OPENAI_API_KEY - Một tệp JSONL chứa các request
- Công cụ để gửi request và kiểm tra response, ví dụ Apidog hoặc
curl
Bước 1: Tạo tệp JSONL cho batch
Đầu vào của Batch API là tệp JSONL. Mỗi dòng là một request độc lập.
Mỗi dòng cần có 4 trường:
-
custom_id: ID do bạn tự đặt để map kết quả về input gốc -
method: thường làPOST -
url: endpoint đích, ví dụ/v1/chat/completions -
body: payload thực tế gửi đến model
Ví dụ requests.jsonl:
{"custom_id": "req-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'shipping was slow but the product is great'"}]}}
{"custom_id": "req-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'returned it the same day'"}]}}
custom_id phải là duy nhất trong tệp. Output không đảm bảo giữ nguyên thứ tự dòng input, nên bạn phải dùng custom_id để ghép kết quả về bản ghi ban đầu.
Một batch có thể chứa tối đa 50.000 request và tệp input có thể lên tới 200 MB.
Kiểm tra nhanh JSONL trước khi upload
Trước khi gửi lên OpenAI, nên validate từng dòng để tránh batch fail ở bước xác thực.
Ví dụ kiểm tra JSONL bằng Node.js:
import fs from "node:fs";
import readline from "node:readline";
const file = readline.createInterface({
input: fs.createReadStream("requests.jsonl"),
crlfDelay: Infinity,
});
const ids = new Set();
let lineNumber = 0;
for await (const line of file) {
lineNumber++;
let item;
try {
item = JSON.parse(line);
} catch {
throw new Error(`Dòng ${lineNumber} không phải JSON hợp lệ`);
}
for (const field of ["custom_id", "method", "url", "body"]) {
if (!item[field]) {
throw new Error(`Dòng ${lineNumber} thiếu trường ${field}`);
}
}
if (ids.has(item.custom_id)) {
throw new Error(`custom_id bị trùng: ${item.custom_id}`);
}
ids.add(item.custom_id);
if (item.method !== "POST") {
throw new Error(`Dòng ${lineNumber}: method phải là POST`);
}
}
console.log(`JSONL hợp lệ. Tổng số dòng: ${lineNumber}`);
Bước 2: Upload tệp JSONL
Upload tệp qua Files API với purpose="batch":
curl https://api.openai.com/v1/files \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F purpose="batch" \
-F file="@requests.jsonl"
Response sẽ có dạng:
{
"id": "file-abc123",
"object": "file",
"purpose": "batch",
"filename": "requests.jsonl"
}
Lưu lại id. Đây là input_file_id dùng để tạo batch ở bước tiếp theo.
Bước 3: Tạo batch job
Gửi input_file_id, endpoint đích và completion_window.
Hiện tại completion_window nhận giá trị "24h".
curl https://api.openai.com/v1/batches \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "file-abc123",
"endpoint": "/v1/chat/completions",
"completion_window": "24h",
"metadata": {
"job": "sentiment-backfill"
}
}'
Lưu ý: endpoint trong request tạo batch phải khớp với trường url trong từng dòng JSONL.
Các endpoint được hỗ trợ gồm:
/v1/chat/completions/v1/responses/v1/embeddings/v1/completions/v1/moderations- Và các endpoint khác được OpenAI hỗ trợ theo thời gian
Response trả về một batch object:
{
"id": "batch_abc123",
"object": "batch",
"endpoint": "/v1/chat/completions",
"input_file_id": "file-abc123",
"completion_window": "24h",
"status": "validating",
"output_file_id": null,
"error_file_id": null,
"request_counts": {
"total": 0,
"completed": 0,
"failed": 0
},
"created_at": 1733452800,
"metadata": {
"job": "sentiment-backfill"
}
}
Các trường quan trọng cần lưu:
-
id: batch ID để thăm dò -
status: trạng thái hiện tại -
output_file_id: file kết quả khi batch hoàn tất -
error_file_id: file lỗi nếu có request thất bại -
request_counts: tiến độ xử lý
Bước 4: Thăm dò trạng thái batch
Gọi endpoint sau để kiểm tra trạng thái:
curl https://api.openai.com/v1/batches/batch_abc123 \
-H "Authorization: Bearer $OPENAI_API_KEY"
Các trạng thái phổ biến:
| Trạng thái | Ý nghĩa |
|---|---|
validating |
File input đang được kiểm tra |
in_progress |
Các request đang được xử lý |
finalizing |
Batch đã chạy xong, output file đang được chuẩn bị |
completed |
Hoàn tất, có thể tải kết quả |
failed |
Xác thực thất bại, không request nào được chạy |
expired |
Quá 24 giờ trước khi hoàn tất toàn bộ |
cancelling / cancelled
|
Batch đang được hủy hoặc đã hủy |
Không có webhook cho luồng này, vì vậy bạn cần polling. Không nên polling mỗi giây. Với workload batch, khoảng vài phút/lần thường hợp lý hơn.
Ví dụ script polling đơn giản bằng Bash:
BATCH_ID="batch_abc123"
while true; do
RESPONSE=$(curl -s https://api.openai.com/v1/batches/$BATCH_ID \
-H "Authorization: Bearer $OPENAI_API_KEY")
STATUS=$(echo "$RESPONSE" | jq -r '.status')
echo "Batch status: $STATUS"
if [ "$STATUS" = "completed" ]; then
echo "$RESPONSE" | jq .
break
fi
if [ "$STATUS" = "failed" ] || [ "$STATUS" = "expired" ] || [ "$STATUS" = "cancelled" ]; then
echo "$RESPONSE" | jq .
exit 1
fi
sleep 180
done
Nếu gửi nhầm batch, bạn có thể hủy:
curl -X POST https://api.openai.com/v1/batches/batch_abc123/cancel \
-H "Authorization: Bearer $OPENAI_API_KEY"
Bước 5: Tải output file
Khi status là completed, batch object sẽ có output_file_id.
Ví dụ:
{
"status": "completed",
"output_file_id": "file-output456",
"error_file_id": "file-error789"
}
Tải output:
curl https://api.openai.com/v1/files/file-output456/content \
-H "Authorization: Bearer $OPENAI_API_KEY" > results.jsonl
Output cũng là JSONL, mỗi dòng tương ứng với một request đã xử lý. Mỗi dòng chứa custom_id và response.
Ví dụ:
{"custom_id":"req-1","response":{"status_code":200,"body":{"choices":[{"message":{"content":"mixed positive"}}]}}}
{"custom_id":"req-2","response":{"status_code":200,"body":{"choices":[{"message":{"content":"negative"}}]}}}
Nếu có error_file_id, hãy tải cả file lỗi:
curl https://api.openai.com/v1/files/file-error789/content \
-H "Authorization: Bearer $OPENAI_API_KEY" > errors.jsonl
Luôn ghép kết quả bằng custom_id, không dựa vào thứ tự dòng.
Ví dụ parse kết quả bằng Node.js
Sau khi tải results.jsonl, bạn có thể parse và map kết quả về input ban đầu:
import fs from "node:fs";
import readline from "node:readline";
const results = new Map();
const file = readline.createInterface({
input: fs.createReadStream("results.jsonl"),
crlfDelay: Infinity,
});
for await (const line of file) {
const item = JSON.parse(line);
results.set(item.custom_id, {
statusCode: item.response?.status_code,
body: item.response?.body,
});
}
console.log(results.get("req-1"));
Nếu bạn cần merge với dữ liệu input gốc, hãy lưu custom_id cùng ID bản ghi trong database trước khi tạo JSONL.
Ví dụ:
{
"custom_id": "product-9832",
"record_id": 9832
}
Sau khi có output, dùng custom_id để update đúng bản ghi.
Lưu ý về chi phí và thời gian xử lý
Batch API có đánh đổi rõ ràng:
- Bạn tiết kiệm 50% chi phí token đầu vào và đầu ra.
- Bạn chấp nhận thời gian xử lý tối đa 24 giờ.
- Batch dùng nhóm giới hạn tốc độ riêng, không cạnh tranh trực tiếp với traffic đồng bộ.
- Nếu batch
expired, các request đã hoàn thành vẫn được trả về và tính phí; phần còn lại thì không.
Vì vậy, Batch API phù hợp cho:
- Job chạy ban đêm
- Backfill dữ liệu
- Xử lý dataset định kỳ
- Tác vụ không cần phản hồi real-time
Không phù hợp cho:
- API request đang chờ trả response cho user
- Tính năng tương tác trong UI
- Luồng cần retry hoặc điều phối tức thì
Nếu bạn đang gặp giới hạn tốc độ với API đồng bộ, xem thêm hướng dẫn về giới hạn tốc độ GPT API và cách kiểm tra chúng.
Để phân bổ chi phí theo feature hoặc job, hãy dùng metadata khi tạo batch:
{
"metadata": {
"feature": "product-description",
"env": "production",
"run": "2025-01-nightly"
}
}
Bạn cũng có thể tham khảo hướng dẫn phân bổ chi phí cho chi tiêu OpenAI.
Cách kiểm tra Batch API trong Apidog
Batch API dễ lỗi hơn một request chat đơn lẻ vì lỗi có thể nằm ở nhiều lớp:
- JSONL sai format
- Thiếu trường trong từng dòng
-
endpointkhông khớp vớiurl - File upload sai
purpose - Batch fail ở bước
validating - Output đến sau nên logic tải kết quả khó kiểm tra ngay
Bạn nên kiểm tra thủ công toàn bộ lifecycle trước khi tự động hóa.
1. Tạo request upload file
Trong Apidog, tạo request:
POST https://api.openai.com/v1/files
Headers:
Authorization: Bearer {{OPENAI_API_KEY}}
Body dạng multipart/form-data:
| Key | Value |
|---|---|
purpose |
batch |
file |
requests.jsonl |
Sau khi gửi, lưu id trả về vào environment variable, ví dụ:
INPUT_FILE_ID=file-abc123
2. Tạo request tạo batch
Tạo request:
POST https://api.openai.com/v1/batches
Headers:
Authorization: Bearer {{OPENAI_API_KEY}}
Content-Type: application/json
Body:
{
"input_file_id": "{{INPUT_FILE_ID}}",
"endpoint": "/v1/chat/completions",
"completion_window": "24h",
"metadata": {
"job": "sentiment-backfill"
}
}
Kiểm tra response:
-
statusphải làvalidating -
endpointphải khớp/v1/chat/completions -
input_file_idphải đúng file vừa upload
Lưu id của batch vào biến:
BATCH_ID=batch_abc123
3. Tạo request thăm dò batch
Tạo request:
GET https://api.openai.com/v1/batches/{{BATCH_ID}}
Theo dõi các trường:
statusrequest_counts.totalrequest_counts.completedrequest_counts.failedoutput_file_iderror_file_id
Khi status là completed, lưu output_file_id.
4. Tải output file
Tạo request:
GET https://api.openai.com/v1/files/{{OUTPUT_FILE_ID}}/content
Response là JSONL. Tải về và parse theo custom_id.
5. Kiểm tra đường lỗi và hủy batch
Đừng chỉ test happy path. Nên tạo một file JSONL cố tình sai, ví dụ thiếu body, để xác nhận batch trả về failed.
Bạn cũng nên test endpoint hủy:
POST https://api.openai.com/v1/batches/{{BATCH_ID}}/cancel
Việc này giúp code xử lý lỗi của bạn dựa trên response thật, không phải giả định.
Vì output có thể đến sau nhiều giờ, bạn có thể dựng API giả trả về một batch object mẫu ở trạng thái completed và một file kết quả dựng sẵn. Cách này giúp bạn kiểm tra logic tải và parse output mà không cần chờ job thật hoặc tốn token trong giai đoạn phát triển.
Nếu nhóm của bạn làm việc theo hướng specification-first, bạn cũng có thể tạo bộ sưu tập kiểm tra trực tiếp từ đặc tả OpenAPI để đưa các endpoint batch vào CI.
FAQ
Một batch mất bao lâu?
OpenAI cam kết hoàn thành trong vòng 24 giờ. Nhiều batch có thể xong sớm hơn, nhưng hệ thống của bạn nên xử lý theo giới hạn 24 giờ. Nếu quá thời gian, batch chuyển sang expired; các request đã hoàn thành vẫn được trả về và tính phí.
Batch API giảm giá bao nhiêu?
Batch API giảm 50% so với endpoint đồng bộ cho cả input token và output token. Nếu cần phân bổ chi phí theo feature hoặc job, hãy dùng metadata và tham khảo hướng dẫn phân bổ chi phí.
Có thể chạy endpoint nào trong batch?
Bạn đặt endpoint trong cả url của từng dòng JSONL và trường endpoint khi tạo batch. Hai giá trị này phải khớp nhau.
Các endpoint được hỗ trợ gồm /v1/chat/completions, /v1/responses, /v1/embeddings, /v1/completions, /v1/moderations, cùng các endpoint hình ảnh và video được OpenAI hỗ trợ. Hãy kiểm tra tài liệu OpenAI hiện tại để có danh sách đầy đủ.
Vì sao output không theo thứ tự input?
Output JSONL không đảm bảo giữ thứ tự dòng như input. Đây là lý do mỗi request cần một custom_id duy nhất. Khi xử lý kết quả, luôn join bằng custom_id, không join bằng số dòng.
Kết luận
Batch API phù hợp cho các workload OpenAI lớn, offline và có thể chờ tới 24 giờ. Quy trình triển khai gồm: tạo JSONL, upload file, tạo batch, polling trạng thái, tải output và xử lý kết quả theo custom_id.
Trước khi tự động hóa, hãy chạy thủ công toàn bộ lifecycle để bắt lỗi sớm ở JSONL, upload, tạo batch, polling, hủy và tải output. Tải xuống Apidog để kiểm tra các endpoint này, xác nhận response object và tránh mất một vòng chờ 24 giờ chỉ vì một dòng JSONL sai định dạng.
Top comments (0)