Đo và dự phóng chi phí khi gọi API AI bên thứ ba
Vì sao hóa đơn API luôn đến muộn hơn bạn nghĩ
Bài trước bạn đã dựng hàng rào: rate limit theo IP và theo user, quota, captcha, validate input sớm. Hàng rào đó chặn được số lượng request. Nhưng nó không nói cho bạn biết mỗi request tốn bao nhiêu tiền, và cũng không nói tháng này bạn sẽ trả bao nhiêu. Tôi từng mở cửa cho feature tóm tắt nội dung chạy tự do, ba tuần sau nhận hóa đơn lớn hơn tiền thuê văn phòng. Từ đó tôi có một nguyên tắc: đặt giới hạn trước khi mở cửa, và đo trước khi đặt giới hạn.
Sau bài này bạn sẽ:
- Tính được chi phí của một request theo input token và output token.
- Dựng được công thức dự phóng từ dữ liệu vài ngày ra hóa đơn cuối tháng.
- Thiết kế được bảng theo dõi chi phí theo user, theo tính năng và theo ngày.
- Viết được vài query đầu tiên để trả lời "ai đang đốt tiền của tôi".
Token: đơn vị tiền thật của mỗi request
API AI không tính tiền theo request, nó tính theo token. Token là đơn vị nhỏ hơn từ, tiếng Việt thường tốn nhiều token hơn tiếng Anh cho cùng một câu.
Mỗi lần gọi bạn trả tiền cho hai phần:
| Loại | Là gì | Ghi chú |
|---|---|---|
| Input token | Prompt bạn gửi lên (câu hỏi, tài liệu, lịch sử chat) | Rẻ hơn |
| Output token | Phần model sinh ra | Thường đắt hơn input 3 đến 5 lần |
Giá luôn được niêm yết theo 1 triệu token, và thay đổi theo model. Đừng học thuộc con số, hãy học cách tính. Ví dụ minh họa dưới đây dùng giá giả định 3 USD / 1 triệu input token và 15 USD / 1 triệu output token:
const PRICE_IN = 3 / 1_000_000; // USD mỗi input token
const PRICE_OUT = 15 / 1_000_000; // USD mỗi output token
function costOf(inputTokens, outputTokens) {
return inputTokens * PRICE_IN + outputTokens * PRICE_OUT;
}
costOf(1200, 400); // 0.0096 USD, chưa tới 1 cent
Một request chưa tới 1 cent nghe rất vô hại. Nhân với 10.000 request mỗi ngày là 96 USD/ngày, tức khoảng 2.880 USD/tháng. Output token thường là phần đắt nhất và cũng là phần bạn kiểm soát ít nhất, vì model tự quyết định viết dài hay ngắn.
Bài tập 1 (project): Tính năng "tóm tắt email" của bạn tốn 1.500 input token và 500 output token mỗi request, chạy 5.000 request/ngày. Tính chi phí một request và chi phí tháng.
Xem đáp án
Một request: 1.500 × 3/1e6 = 0.0045 USD, cộng 500 × 15/1e6 = 0.0075 USD, tổng 0.012 USD. Một ngày: 5.000 × 0.012 = 60 USD. Một tháng: khoảng 1.800 USD. Ghi chú: chỉ cần đặt max_tokens cho output ở mức hợp lý là bạn đã chặn được phần lớn rủi ro.
Dự phóng: từ một request ra hóa đơn cuối tháng
Đừng chờ đến cuối tháng mới biết. Lấy dữ liệu 7 ngày, tính chi phí trung bình mỗi ngày, rồi nhân ra:
$$ \text{Chi phí tháng} \approx \text{chi phí/ngày} \times 30 $$
Nhưng chỉ dùng số trung bình là tự lừa mình. Hãy dự phóng thành một dải: mức trung bình, và mức cao điểm (p95, tức ngày bận thứ 95 trong 100 ngày). Ngày cao điểm thường gấp 1,5 đến 2 lần ngày thường, và đó chính là ngày làm vỡ ngân sách của bạn.
Có ba thứ dễ bị bỏ sót khi dự phóng:
- Retry: mỗi lần gọi lại là một lần tính token mới, kể cả khi lần trước lỗi.
- Lịch sử chat: nếu bạn gửi kèm toàn bộ hội thoại, input token tăng dần theo từng lượt. Lượt thứ 10 đắt hơn lượt thứ 1 rất nhiều.
- Feature ẩn: job tóm tắt chạy nền, cron job làm sạch dữ liệu, tất cả đều gọi API.
Bài tập 2 (project): Log của bạn cho thấy 8.000 request/ngày với chi phí 0.012 USD/request, nhưng ngày cao điểm lên 12.000 request. Dự phóng dải chi phí tháng.
Xem đáp án
Mức thường: 8.000 × 0.012 = 96 USD/ngày, khoảng 2.880 USD/tháng. Mức cao điểm: 12.000 × 0.012 = 144 USD/ngày. Nếu có 5 ngày cao điểm mỗi tháng: 25 × 96 + 5 × 144 = 3.120 USD. Con số dải này là đầu vào để đặt ngân sách ở bài sau.
Bảng theo dõi chi phí theo user, tính năng và ngày
Một con số tổng cuối tháng không giúp bạn sửa gì cả. Bạn cần biết ai tốn tiền, tính năng nào tốn tiền, và ngày nào bất thường. Ba chiều đó gói gọn trong một bảng nhỏ:
CREATE TABLE ai_usage (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
feature TEXT NOT NULL,
day DATE NOT NULL,
requests INT NOT NULL,
input_tokens BIGINT NOT NULL,
output_tokens BIGINT NOT NULL,
cost_usd NUMERIC(12,6) NOT NULL,
UNIQUE (user_id, feature, day)
);
Hai nguyên tắc khi ghi bảng này:
- Ghi
cost_usdngay lúc ghi log, đừng để đến cuối tháng mới nhân lại. Giá thay đổi theo model và theo thời điểm; nhân lại sau sẽ ra số sai. - Ghi cả input và output token riêng biệt. Gộp chúng lại là mất khả năng biết phần nào đang phình ra.
Số liệu token lấy từ chính response của API, thường nằm trong trường usage (prompt_tokens, completion_tokens). Đừng tự đếm bằng cách chia độ dài chuỗi, sai số rất lớn.
Bài tập 3 (project): Viết hai query: top 3 user tốn tiền nhất 7 ngày qua, và tính năng nào có chi phí mỗi request cao nhất.
Xem đáp án
SELECT user_id, SUM(cost_usd) AS total
FROM ai_usage
WHERE day >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY user_id
ORDER BY total DESC
LIMIT 3;
SELECT feature,
SUM(cost_usd) / SUM(requests) AS cost_per_request,
SUM(cost_usd) AS total
FROM ai_usage
WHERE day >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY feature
ORDER BY cost_per_request DESC;
Query thứ hai thường gây bất ngờ: một tính năng ít dùng nhưng prompt dài có thể đắt hơn tính năng chạy hàng nghìn lần.
Năm điều nếu quên là tính sai tiền
Mỗi request API AI được tính tiền theo _____, không theo số request. Phần model sinh ra gọi là _____ và thường đắt hơn input từ 3 đến 5 lần. Chi phí một request bằng input token nhân giá input _____ output token nhân giá output. Bảng theo dõi chi phí cần tối thiểu ba chiều: user, _____ và ngày. Số liệu token chuẩn để ghi log nằm trong trường _____ của response.
Ba cái bẫy khiến con số chi phí nói dối
- Tính bằng số request thay vì token. Prompt dài gấp 10 lần là chi phí gấp 10 lần, dù số request không đổi.
- Bỏ qua retry và job chạy nền. Chúng không xuất hiện trong log request của user nhưng vẫn trừ tiền. Hãy log chúng với
user_id = 0hoặc mộtfeatureriêng. - Chỉ nhìn trung bình. Hãy xem thêm p95 và giá trị lớn nhất mỗi ngày. Một ngày lỗi vòng lặp gọi API có thể bằng cả tháng bình thường.
- Quy tắc của tôi: nếu một tính năng mới chưa có dòng nào trong
ai_usage, nó chưa được phép mở cho user thật.
Mang gì về dự án, và bài sau
Ba thứ bạn mang về: một hàm costOf để tính tiền mỗi request, một công thức dự phóng thành dải (trung bình và p95), và một bảng ai_usage đủ ba chiều user, feature, day. Có ba thứ này, mọi con số về sau đều kiểm chứng được.
Bài tiếp theo chúng ta lấy chính dải dự phóng này để đặt ngân sách, chia hạn mức và bắn cảnh báo trước khi hóa đơn chạm trần.
Front: API AI tính tiền theo đơn vị nào? Back: Theo token, không theo số request.
Front: Input token là gì? Back: Phần prompt bạn gửi lên: câu hỏi, tài liệu, lịch sử chat.
Front: Output token là gì? Back: Phần model sinh ra, thường đắt hơn input 3 đến 5 lần.
Front: Công thức chi phí một request? Back: input token × giá input + output token × giá output.
Front: Vì sao phải ghi input và output token riêng biệt? Back: Vì hai loại có giá khác nhau, gộp lại là tính sai tiền.
Front: Ba chiều tối thiểu của bảng theo dõi chi phí? Back: user, tính năng (feature) và ngày.
Front: Vì sao ghi cost_usd ngay lúc log thay vì tính lại sau? Back: Vì giá thay đổi theo model và thời điểm, tính lại sẽ sai.
Front: Lấy số token từ đâu cho chính xác? Back: Từ trường usage trong response (prompt_tokens, completion_tokens).
Front: Dự phóng chi phí tháng từ dữ liệu ngày như thế nào? Back: Chi phí trung bình mỗi ngày nhân với số ngày trong tháng.
Front: Vì sao dự phóng nên dùng p95 chứ không chỉ trung bình? Back: Vì vài ngày cao điểm có thể làm vỡ ngân sách.
Front: Retry có tốn tiền không? Back: Có, mỗi lần gọi lại là một lần tính token mới.
Front: Vì sao gửi kèm lịch sử chat làm chi phí tăng dần? Back: Vì input token tăng theo từng lượt, lượt sau đắt hơn lượt trước.
Front: max_tokens giúp gì cho kiểm soát chi phí? Back: Chặn trần output token của mỗi request.
Front: Query nào cho biết tính năng nào đắt nhất mỗi request? Back: SUM(cost_usd) / SUM(requests) group by feature.