الذكاء الاصطناعي للمبتدئيندليل
حدّد سقف تكلفة دفعة LLM في Python: سجل وميزانية صارمة
سجّل رموز وتكلفة كل استدعاء API في ملف JSONL، وأوقف الدفعة عند ميزانية، وقدّر الفاتورة قبل تشغيلها. كود Python مضمّن.

في هذه الصفحة
يتكرر سكربتك على 200 مُدخل، وتُغلق غطاء الحاسوب المحمول، وفي الصباح تكتشف كم كلّفتك الليلة. عادتان صغيرتان تُصلحان ذلك. بعد كل استدعاء API، أضِف سطرًا واحدًا يحتوي على الرموز والتكلفة إلى ملف سجل. قبل كل استدعاء، قارن الإجمالي الجاري بميزانية وتوقّف إذا بلغتها. هذا أقل من 50 سطرًا من Python، وتجربة تشغيل من 5 مُدخلات تُخبرك بالفاتورة قبل أن تبدأ التشغيل الفعلي.
ما يفعله تشغيل Clocktower ويمكنك نسخه#
شغّل Dwarkesh Patel، مضيف Dwarkesh Podcast، 11 نموذجًا ضد بعضها في Blood on the Clocktower، 386 لعبة وفقًا لملف README، ونشر الكود والسجلات والتقييمات (github.com/dwarkeshsp/clocktower، تم التحقق في 8 نوفمبر 2026). تفصيلان من المستودع يستحقان السرقة. يحتفظ كل مجلد لعبة بسجل لكل استدعاء يحتوي على الرموز والتكلفة، ويذهب الإنفاق إلى games/. راية --budget تحدّ من إجمالي الإنفاق؛ القيمة الافتراضية 1,000 دولار. يضيف موقع المعيار حارسًا ثالثًا: يحصل كل نموذج على السقف نفسه البالغ 8,000 رمز لكل دور (clocktowerbench.com).
إذن: سقف على كل استدعاء، وسجل لكل استدعاء، وحد أقصى للإجمالي. تحتاج البطولة إلى الثلاثة، وكذلك يحتاج تشغيلك الليلي، لكن أصغر.
فكّر في السجل كلفافة الإيصالات في صندوق متجر. كل عملية بيع تطبع سطرًا؛ ويمكن للمدير جمع اللفافة في أي لحظة ويعرف متى نفدت نقدية اليوم.
السجل: ملف واحد، سطر واحد لكل استدعاء#
إليك الأمر كله. يستخدم حزمة openai موجّهة إلى CheapTokens (https:/، راجع المستندات للمفتاح ومعرّفات النماذج).
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.contentيمر كل استدعاء عبر الخطوات الأربع نفسها:

ثلاثة خيارات هناك متعمّدة.
- كائن JSON واحد لكل سطر (JSONL)، يُفتح في وضع الإضافة. إذا تعطّل السكربت عند الاستدعاء 130، فإن الاستدعاءات من 1 إلى 129 موجودة بالفعل على القرص.
- الإجمالي يأتي من الملف، لا من متغيّر. أعد تشغيل السكربت ويظل الحد الأقصى ساريًا، لأن السجل يتذكّر ما أنفقه التشغيل السابق.
- يُسجَّل
finish_reasonبجانب الرموز. صف يقولlengthيعني أن الإجابة بلغتmax_tokensوقُطعت. ستحتاج معرفة ذلك لاحقًا.
ثابتا PRICE_ عنصران نائبان. خُذ الأرقام الحالية من جدول الأسعار. بالنسبة إلى DeepSeek-V4-Flash وقت قراءتك لهذا، هذا $0.015 لكل مليون رمز إدخال و$0.10 لكل مليون رمز إخراج. غيّر MODEL إلى zai- أو MiniMaxAI/ والثابتين، ويعمل السجل نفسه معهما.
حلقة الدفعة: تخطَّ ما أُنجز، توقّف عند الحد الأقصى#
الحلقة قصيرة. لنفترض أن مُدخلاتك في قاموس مفتاحه معرّف وحدة، اسم قطعة عمل واحدة، مثل 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)شغّله، اضغط Ctrl+C في المنتصف، شغّله مرة أخرى: تُتخطّى الوحدات المنجزة، فيعمل السجل كملف تقدّمك أيضًا. دع الميزانية تنفد وستحصل على سطر واحد بدلًا من مفاجأة، شيء مثل stopped before doc-.
لاحظ كلمة قبل. يحدث التحقق قبل كل استدعاء، لذا يمكن للاستدعاء الأخير أن يدفع الإجمالي قليلًا فوق الميزانية. مقدار التجاوز محدود: لا يمكن لاستدعاء واحد أن يكلّف أكثر من أطول مُدخل لديك زائد max_tokens. بالنسبة إلى مُدخل من 1,500 رمز وmax_tokens=400، هذا على الأكثر $0.000063. لهذا لكل استدعاء في الغلاف max_tokens: يحوّل خطرًا مفتوحًا إلى رقم يمكنك التخطيط حوله.

قدّر الفاتورة قبل أن تضغط تشغيل#
الآن النصف الآخر: معرفة التكلفة قبل الإطلاق. شغّل أول خمسة مُدخلات عبر ask() بميزانية صغيرة واقرأ السجل. لنفترض أن الصفوف الخمسة متوسطها 1,500 رمز إدخال و400 رمز إخراج. هذه أرقامك للدفعة كلها.
بالنسبة إلى 200 مُدخل، هذا 200 × 1,500 = 300,000 رمز إدخال و200 × 400 = 80,000 رمز إخراج. إليك هذا الحمل على الأسعار الحية:
| النموذج | الإدخال $/1M | الإخراج $/1M | لكل طلب | 200 طلبات | OpenRouter، 200 طلبات |
|---|---|---|---|---|---|
| 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 رمز إدخال و400 رمز إخراج لكل طلب. الأسعار لكل مليون رمز حالية وتتغير مع تعريفاتنا؛ يعرض عمود OpenRouter أسعارًا مرجعية لنفس حجم العمل.
يحتوي الجدول على عمود OpenRouter أيضًا. مع احتساب الإدخال والإخراج معًا، يخرج DeepSeek-V4-Flash أرخص من OpenRouter لهذا الحمل، وهذا المجموع هو ما تدفعه الدفعة فعليًا.
تختلف المُدخلات في الطول، لذا خمس عينات تخمين لا وعد. استخدم الأطول من الخمس عندما تريد جانبًا أعلى آمنًا، ثم دع سقف الميزانية يلتقط الباقي. تريد مقارنة نموذجين على المُدخلات الـ200 نفسها؟ أعطِ كل نموذج ملف سجله الخاص، مثل Ledger(f'ledger-، ويظهر الإجماليان جنبًا إلى جنب بعد ذلك.
جرّب دفعتك هنا: اضبط الرموز لكل طلب من عينتك وعدد الطلبات التي تخطط لها.
حاسبة التكلفة
دفعتك: رموز من عينتك المكوّنة من 5 مُدخلات
رموز الإدخال لكل طلب: 1,500 · رموز الإخراج لكل طلب: 400 · الطلبات يوميًا: 200
| النموذج | يوميًا | شهريًا |
|---|---|---|
| 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 |
لمزيد من المعلومات حول عدّ الرموز قبل الإرسال، راجع عدّ الرموز باستخدام tiktoken.
عندما تكون الفاتورة أكبر من المتوقع: اقرأ السجل#
سيناريو القارئ الثالث هو السيئ. يسير تشغيل وكيل بشكل خاطئ ويتكرر، وتعرض لوحة المعلومات إجماليًا فقط. يُظهر السجل أين ذهب. رتّب الصفوف حسب التكلفة:
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'])بالنسبة إلى وكيل، سمِّ الوحدة على اسم الخطوة (step-17) حتى ترى شكل التشغيل. تظهر أنماط قليلة مرارًا وتكرارًا؛ طابِق كل واحد مع سببه المعتاد:
طابق الأزواج
طابِق كل نمط سجل مع سببه المعتاد
اضغط على عنصر من اليسار، ثم على زوجه
- ينمو prompt_tokens قليلًا في كل صفتعيد الحلقة إرسال التاريخ كله في كل خطوة
- completion_tokens يساوي max_tokens وfinish_reason هو lengthتُقطع الإجابات عند سقفك، وتدفع مقابل النص المقطوع
- تظهر الوحدة نفسها مرات كثيرة على التواليحلقة إعادة محاولة، أو وكيل يكرر خطوة واحدة
- صف واحد يكلّف أكثر بكثير من كل الصفوف الأخرىإدخال واحد مفرط الحجم، مثل ملف كامل ملصق في المُدخل
كل نمط مرئي في السجل قبل الفاتورة بوقت طويل. الأول مُغطّى في لماذا يعيد الوكيل قراءة تاريخه.
إذا أردت أيضًا الإنفاق لكل مشروع وتنبيهات خارج السكربت، هذا الدليل إلى تنبيهات الميزانية لكل مشروع يغطي ذلك الجانب. السجل هنا هو الجزء الذي يعيش في كودك ويمكنه أن يقول توقّف.
قبل أن تُطلق#
قائمة التحقق
قبل التشغيل الفعلي الأول
حجم السياق وحد الإجابة في DeepSeek-V4-Flash، مفيدان عند اختيار max_tokens، موجودان في صفحته: DeepSeek-V4-Flash على CheapTokens.



