AI cho người mớiHướng dẫn
Giới hạn chi phí một batch LLM bằng Python: sổ cái và ngân sách cứng
Ghi log token và chi phí của mỗi lần gọi API vào tệp JSONL, dừng batch ở một ngân sách, và ước tính hóa đơn trước khi chạy. Kèm mã Python.

Trên trang này
Script của bạn lặp qua 200 prompt, bạn gập nắp laptop, và sáng hôm sau bạn biết đêm đó tốn bao nhiêu. Hai thói quen nhỏ khắc phục điều đó. Sau mỗi lần gọi API, ghi thêm một dòng chứa token và chi phí vào một tệp sổ cái. Trước mỗi lần gọi, so sánh tổng đang chạy với ngân sách và dừng nếu đã đạt. Đó là chưa đến 50 dòng Python, và một lần chạy thử 5 prompt cho bạn biết hóa đơn trước khi lần chạy thật bắt đầu.
Bản chạy Clocktower làm gì mà bạn có thể bắt chước#
Dwarkesh Patel, người dẫn Dwarkesh Podcast, đã cho 11 mô hình đấu với nhau trong Blood on the Clocktower, 386 ván theo README, và công bố mã, log cùng bảng xếp hạng (github.com/dwarkeshsp/clocktower, kiểm tra ngày 8 tháng 11 năm 2026). Hai chi tiết trong repo đáng để học theo. Mỗi thư mục ván giữ một log theo từng lần gọi với token và chi phí, và chi tiêu được ghi vào games/. Một cờ --budget giới hạn tổng chi tiêu; mặc định là $1.000. Trang benchmark thêm lớp bảo vệ thứ ba: mỗi mô hình có cùng mức trần 8.000 token mỗi lượt (clocktowerbench.com).
Vậy: một mức trần cho mỗi lần gọi, một log cho mỗi lần gọi, một giới hạn cho tổng. Một giải đấu cần cả ba, và lần chạy qua đêm của bạn cũng vậy, chỉ nhỏ hơn.
Hãy nghĩ sổ cái như cuộn hóa đơn trong máy tính tiền của cửa hàng. Mỗi lần bán in một dòng; người quản lý có thể cộng cuộn giấy bất cứ lúc nào và biết khi nào tiền lẻ trong ngày hết.
Sổ cái: một tệp, một dòng mỗi lần gọi#
Đây là toàn bộ. Nó dùng gói openai trỏ tới CheapTokens (https:/, xem tài liệu để biết key và các id mô hình).
import json
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
PRICE_IN, PRICE_OUT = 1.00, 2.00 # USD per 1M tokens: example, substitute current ones
class BudgetExceeded(Exception):
pass
class Ledger:
def __init__(self, path, budget_usd):
self.path = Path(path)
self.budget = budget_usd
self.rows = []
if self.path.exists():
with self.path.open() as f:
self.rows = [json.loads(line) for line in f if line.strip()]
@property
def spent(self):
return sum(r['cost_usd'] for r in self.rows)
def done(self):
return {r['unit'] for r in self.rows}
def check(self, unit):
if self.spent >= self.budget:
raise BudgetExceeded(
f'stopped before {unit}: spent {self.spent:.4f} of {self.budget} USD'
)
def add(self, unit, usage, finish_reason):
cost = (usage.prompt_tokens * PRICE_IN
+ usage.completion_tokens * PRICE_OUT) / 1_000_000
row = {
'unit': unit,
'model': MODEL,
'prompt_tokens': usage.prompt_tokens,
'completion_tokens': usage.completion_tokens,
'finish_reason': finish_reason,
'cost_usd': round(cost, 6),
}
self.rows.append(row)
with self.path.open('a') as f:
f.write(json.dumps(row) + '\n')
def ask(ledger, unit, prompt, max_tokens=400):
ledger.check(unit)
resp = client.chat.completions.create(
model=MODEL,
messages=[{'role': 'user', 'content': prompt}],
max_tokens=max_tokens,
)
ledger.add(unit, resp.usage, resp.choices[0].finish_reason)
return resp.choices[0].message.contentMỗi lần gọi đi qua cùng bốn bước:

Ba lựa chọn trong đó là có chủ đích.
- Một đối tượng JSON mỗi dòng (JSONL), mở ở chế độ append. Nếu script crash ở lần gọi thứ 130, các lần gọi 1 đến 129 đã nằm trên đĩa.
- Tổng lấy từ tệp, không từ biến. Khởi động lại script và giới hạn vẫn giữ, vì sổ cái nhớ lần chạy trước đã tiêu bao nhiêu.
finish_reasonđược ghi log cạnh token. Một dòng ghilengthnghĩa là câu trả lời chạmmax_tokensvà bị cắt. Bạn sẽ muốn biết điều đó sau này.
Hai hằng số PRICE_ là chỗ giữ chỗ. Lấy số hiện tại từ bảng giá. Với DeepSeek-V4-Flash tại thời điểm bạn đọc bài này, đó là $0.015 mỗi 1M token đầu vào và $0.10 mỗi 1M token đầu ra. Đổi MODEL thành zai- hoặc MiniMaxAI/ cùng hai hằng số, và sổ cái tương tự hoạt động cho chúng.
Vòng lặp batch: bỏ qua cái đã xong, dừng ở giới hạn#
Vòng lặp ngắn. Giả sử các prompt của bạn nằm trong một dict khóa theo unit id, tên của một đơn vị công việc, chẳng hạn doc-001:
prompts = {
'doc-001': 'Summarize this ticket in one sentence: ...',
'doc-002': 'Summarize this ticket in one sentence: ...',
# ... your 200 prompts
}
ledger = Ledger('ledger.jsonl', budget_usd=0.50)
already = ledger.done()
for unit, prompt in prompts.items():
if unit in already:
continue
try:
answer = ask(ledger, unit, prompt)
except BudgetExceeded as e:
print(e)
break
Path(f'out-{unit}.txt').write_text(answer)Chạy nó, nhấn Ctrl+C giữa chừng, chạy lại: các unit đã xong được bỏ qua, nên sổ cái vừa là tệp tiến độ của bạn. Để ngân sách cạn và bạn nhận một dòng thay vì bất ngờ, đại loại như stopped before doc-.
Chú ý từ trước. Việc kiểm tra diễn ra trước mỗi lần gọi, nên lần gọi cuối có thể đẩy tổng vượt ngân sách một chút. Mức vượt có giới hạn: một lần gọi không thể tốn hơn prompt dài nhất của bạn cộng max_tokens. Với prompt 1.500 token và max_tokens=400 thì tối đa là $0.000063. Đó là lý do mỗi lần gọi trong wrapper có max_tokens: nó biến một rủi ro không giới hạn thành một con số bạn có thể lập kế hoạch.

Ước tính hóa đơn trước khi nhấn chạy#
Giờ đến nửa còn lại: biết chi phí trước khi khởi chạy. Chạy năm prompt đầu qua ask() với ngân sách nhỏ và đọc sổ cái. Giả sử năm dòng trung bình 1.500 token đầu vào và 400 token đầu ra. Đó là con số của bạn cho cả batch.
Với 200 prompt thì đó là 200 × 1.500 = 300.000 token đầu vào và 200 × 400 = 80.000 token đầu ra. Đây là khối lượng đó theo giá hiện hành:
| Mô hình | Đầu vào $/1M | Đầu ra $/1M | Mỗi yêu cầu | 200 yêu cầu | OpenRouter, 200 yêu cầu |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000046 | $0.0092 | $0.0167 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.000063 | $0.0125 | $0.0322 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.00014 | $0.027 | $0.324 |
1.500 token đầu vào và 400 token đầu ra mỗi yêu cầu. Giá trên 1 triệu token là giá hiện hành và thay đổi cùng với biểu phí của chúng tôi; cột OpenRouter hiển thị giá tham chiếu cho cùng khối lượng công việc.
Bảng cũng có cột OpenRouter. Khi tính gộp đầu vào và đầu ra, DeepSeek-V4-Flash rẻ hơn OpenRouter cho tải này, và tổng đó là cái batch thực sự trả.
Các prompt khác nhau về độ dài, nên năm mẫu là phỏng đoán, không phải lời hứa. Dùng mẫu dài nhất trong năm khi bạn muốn một cận trên an toàn, rồi để giới hạn ngân sách bắt phần còn lại. Muốn so sánh hai mô hình trên cùng 200 prompt? Cho mỗi mô hình một tệp sổ cái riêng, ví dụ Ledger(f'ledger-, và hai tổng nằm cạnh nhau sau đó.
Thử batch của riêng bạn ở đây: đặt token mỗi yêu cầu từ mẫu của bạn và số yêu cầu bạn dự định.
Máy tính chi phí
Batch của bạn: token từ mẫu 5 prompt của bạn
Token đầu vào mỗi yêu cầu: 1.500 · Token đầu ra mỗi yêu cầu: 400 · Số yêu cầu mỗi ngày: 200
| Mô hình | Mỗi ngày | Mỗi tháng |
|---|---|---|
| GLM-5.3-Flash$0.02$0.04 | $0.0092 | $0.276 |
| DeepSeek-V4-Flash$0.015$0.10 | $0.0125 | $0.375 |
| MiniMax-M2.7$0.05$0.15 | $0.027 | $0.81 |
Để biết thêm về đếm token trước khi gửi, xem đếm token với tiktoken.
Khi hóa đơn lớn hơn dự kiến: đọc sổ cái#
Kịch bản người đọc thứ ba là cái khó chịu. Một lần chạy agent bị lỗi và lặp, và dashboard chỉ hiện một tổng. Sổ cái cho thấy nó đi đâu. Sắp xếp các dòng theo chi phí:
rows = [json.loads(line) for line in open('ledger.jsonl')]
for r in sorted(rows, key=lambda r: r['cost_usd'], reverse=True)[:5]:
print(r['unit'], r['prompt_tokens'], r['completion_tokens'], r['finish_reason'])Với một agent, đặt tên unit theo bước (step-17) để bạn thấy hình dạng của lần chạy. Vài mẫu xuất hiện lặp đi lặp lại; ghép mỗi mẫu với nguyên nhân thường gặp của nó:
Ghép cặp
Ghép mỗi mẫu sổ cái với nguyên nhân thường gặp
Nhấn vào một mục bên trái, rồi đến cặp của nó
- prompt_tokens tăng dần ở mỗi dòngVòng lặp gửi lại toàn bộ lịch sử ở mỗi bước
- completion_tokens bằng max_tokens và finish_reason là lengthCâu trả lời bị cắt ở giới hạn của bạn, và bạn trả tiền cho phần văn bản bị cắt
- Cùng một unit xuất hiện nhiều lần liên tiếpMột vòng lặp thử lại, hoặc agent lặp lại một bước
- Một dòng tốn hơn hẳn tất cả các dòng khácMột đầu vào quá lớn, chẳng hạn cả một tệp được dán vào prompt
Mỗi mẫu đều hiện rõ trong sổ cái rất lâu trước hóa đơn. Mẫu đầu tiên được đề cập trong vì sao một agent đọc lại lịch sử của nó.
Nếu bạn cũng muốn chi tiêu theo dự án và cảnh báo ngoài script, hướng dẫn về cảnh báo ngân sách theo dự án bao quát phần đó. Sổ cái ở đây là phần nằm trong mã của bạn và có thể nói dừng.
Trước khi khởi chạy#
Danh sách kiểm tra
Trước lần chạy thật đầu tiên
Kích thước ngữ cảnh và giới hạn câu trả lời của DeepSeek-V4-Flash, hữu ích khi bạn chọn max_tokens, nằm trên trang của nó: DeepSeek-V4-Flash trên CheapTokens.



