تحسين التكلفةدليل
من اللغة الطبيعية إلى أمر shell عبر LLM API: JSON والتكلفة
سكربت Python يطلب من نموذج رخيص أمر shell واحدًا بصيغة JSON، ويرفض الطلبات أو يعلّمها كغير مؤكدة، ولا ينفّذ أي شيء أبدًا، ويسعّر 1,000 طلب.

في هذه الصفحة
اطلب من النموذج كائن JSON واحدًا بثلاثة حقول (type، command، explanation)، وحدّد الإجابة بمئتي توكن أو نحو ذلك، واطبع الأمر بدلًا من تنفيذه. من حيث التوكنات، فإن طلبًا كهذا يتكوّن في معظمه من الموجّه مع إجابة قصيرة يمكن التنبؤ بها: وفق الافتراضات أدناه، تكلّف 1,000 منها $0.012 على DeepSeek-V4-Flash.
لنفترض أنك تضيف مربع "صف ما تريده" إلى أداة سطر أوامر داخلية. يكتب أحدهم find files bigger than 100 MB in my home folder، وتريد سطرًا واحدًا يمكنه قراءته والتحقق منه ولصقه. يتبع ذلك سؤالان: كيف تمنع النموذج من التخمين أو فعل شيء خطير، وما تكلفة ذلك عندما يستخدمه مئة شخص طوال اليوم؟
مهمة ضيقة: لماذا الإجابة قصيرة#
في 9 نوفمبر 2026 أعادت قناة على Telegram سرد بطاقة النموذج dale-0.8b، وهو نموذج مفتوح يؤدي هذه المهمة الواحدة تحديدًا. وفقًا لـبطاقة النموذج على Hugging Face (تم التحقق منها في 10 نوفمبر 2026)، فإن dale-0.8b هو ضبط دقيق كامل لـ Qwen3.5-0.8B تحت Apache-2.0 يحوّل طلبًا بالإسبانية أو الإنجليزية إلى أمر Linux bash واحد. يذكر المؤلف، Manuel García، نسبة 79.4% (374 من 471 حالة) على مجموعة اختباره الخاصة، مقابل 62.8% لـ Qwen3.5-9B base ولـ Gemma 4 E4B-it دون ضبط دقيق. هذه أرقام مُبلَّغ عنها ذاتيًا على مجموعة اختبار لشخص واحد، لذا تعامل معها كنقطة بيانات لا كترتيب.
ما يفيدنا هو شكل المهمة، لا النموذج. تصف البطاقة موجّه نظام ثابتًا، وسطر سياق (نظام التشغيل، التوزيعة، مدير الحزم، الأدوات) بالإضافة إلى الطلب، مع إيقاف التفكير، وردّ محدود بـ 200 توكن. هذا الحد هو أحد رافعتَي التكلفة: عندما تكون الإجابة كائن JSON واحدًا قصيرًا، يكون جانب الإخراج قصيرًا ويمكن التنبؤ به، لأن الحد يقيّده. الرافعة الأخرى هي الموجّه. أي حصة يشكّلها كل جانب من الفاتورة، يوضحه الجدول أدناه؛ وهو يختلف من نموذج إلى آخر.
لا تحتاج إلى نموذج 0.8B لذلك. التنسيق نفسه يعمل على أي نموذج API، وهذا ما تبنيه بقية هذه المقالة.

صيغة الرد: أمر أو رفض أو عدم تأكد#
الحيلة هي أن يكون لدى النموذج دائمًا طريقة مشروعة لقول "لا". الرد هو كائن واحد:
{"type": "command | refuse | unsure", "command": "...", "explanation": "..."}command: أمر bash واحد، مع شرح من جملة واحدة لما يفعله.refuse: الطلب مدمّر أو لا علاقة له بالـ shell. لا أمر.unsure: الطلب غامض جدًا ("clean up my disk"). يحتوي الشرح على سؤال توضيحي.
بدون unsure، يفرض الطلب الغامض تخمينًا، وrm المخمَّن هو ما تتذكره. تحتوي صيغة البطاقة على الأنواع الثلاثة نفسها؛ نحن نعيد استخدام الفكرة، لا النموذج.
طابق الأزواج
طابق كل نوع رد مع ما يجب أن يفعله السكربت
اضغط على عنصر من اليسار، ثم على زوجه
- commandاعرض الأمر والشرح؛ ينسخه الشخص وينفّذه بنفسه
- refuseاطبع الشرح ولا تقدّم شيئًا للتنفيذ
- unsureاطبع السؤال ودع المستخدم يعيد الصياغة
السكربت#
ملف واحد، حزمة openai، والمفتاح في متغير بيئة. يأتي عنوان URL الأساسي ومعرّف النموذج الكامل من وثائق CheapTokens؛ لا تُقبل المعرّفات القصيرة، لذا استخدم deepseek-.
import json
import os
import sys
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'
SYSTEM = '''You turn a request into ONE Linux bash command.
Reply with a single JSON object and nothing else:
{"type": "command" | "refuse" | "unsure", "command": "<one command, or empty>", "explanation": "<one short sentence>"}
Use "refuse" when the request is destructive or not about the shell.
Use "unsure" when it is too vague, and put a clarifying question in "explanation".'''
CONTEXT = 'os: Ubuntu 24.04; package manager: apt; tools: git, curl, jq'
def parse(text):
start = text.find('{')
if start == -1:
return None
try:
obj, _ = json.JSONDecoder().raw_decode(text[start:])
except json.JSONDecodeError:
return None
if not isinstance(obj, dict) or obj.get('type') not in ('command', 'refuse', 'unsure'):
return None
return obj
def ask(request):
resp = client.chat.completions.create(
model=MODEL,
max_tokens=200,
temperature=0,
messages=[
{'role': 'system', 'content': SYSTEM},
{'role': 'user', 'content': f'Context: {CONTEXT}\nRequest: {request}'},
],
)
return parse(resp.choices[0].message.content), resp.usage
if __name__ == '__main__':
result, usage = ask(' '.join(sys.argv[1:]))
if result is None:
print('Could not read the reply as JSON. Try again.')
elif result['type'] == 'command':
print(result['explanation'])
print('\n ' + result['command'] + '\n')
print('Read it, then copy it yourself. This script never runs it.')
else:
print(f"[{result['type']}] {result['explanation']}")
print(f'tokens: {usage.prompt_tokens} in, {usage.completion_tokens} out')شغّله كـ python shellhelp.. ثلاثة خيارات مهمة هنا:
- لا
subprocessفي أي مكان. الأمر نص على الشاشة. تنفيذه قرارك، بعد أن تقرأه. max_tokens=200، مثل حد البطاقة. كائن JSON واحد يتّسع بسهولة؛ والإجابة المطوّلة تُقطع عند 200 توكن بدلًا من الاستمرار على حسابك. ينطبق الحد على الرد كاملًا، لذا إذا كتب نموذج استدلاله صراحةً فقد يستهلك الحد. إذا انتهى رد ما بقيمةfinish_reasonتساويlength، فارفع الحد قليلًا. المزيد عن ذلك في cutting output tokens with max_tokens.- تُطلب الصيغة في الموجّه، ثم تُحلَّل بحذر. يتجاوز
raw_decodeسياج شيفرة شاردًا أو جملة قبل{. إن أردت المضي أبعد، راجع valid JSON from an OpenAI-compatible API وإصلاح json.JSONDecodeError on a reply.
قبل أن تنفّذ أي شيء، تحقق من أن ترتيب الخطوات واضح:
رتّب بالترتيب
رتّب خطوات السكربت بالترتيب الصحيح
اسحب العناصر أو استخدم الأسهم
- ابنِ الموجّه: نص نظام ثابت، سطر سياق، الطلب
- استدعِ الـ API بـ max_tokens صغير
- حلّل JSON وتحقق من أن type أحد الأنواع الثلاثة
- اعرض الأمر وانتظر أن ينفّذه الشخص
تكلفة 1,000 طلب#
يطبع السطر الأخير من السكربت usage. هذا هو الرقم الحقيقي، وعليك قراءة رقمك الخاص. حتى تحصل عليه، اعمل بافتراض: يبلغ الموجّه نحو 400 توكن إدخال (الموجّه المجرّد في السكربت نحو 150 توكن بحسب تقدير تقريبي؛ والباقي مساحة لثلاثة أو أربعة أزواج أمثلة طلب-وردّ التي قد تضيفها على الأرجح)، وردّ JSON نحو 60 توكن إخراج.
لـ 1,000 طلب يعني ذلك 400 × 1,000 = 400,000 توكن إدخال و60 × 1,000 = 60,000 توكن إخراج. يسعّر الجدول ذلك بالضبط لكل نموذج في الكتالوج، مع عمود OpenRouter بجانبه؛ والأرقام مأخوذة من أسعار حية، لذا تبقى محدّثة.
| النموذج | الإدخال $/1M | الإخراج $/1M | لكل طلب | 1,000 طلبات | OpenRouter، 1,000 طلبات |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.00001 | $0.0104 | $0.0184 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.000012 | $0.012 | $0.0364 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000029 | $0.029 | $0.348 |
400 رمز إدخال و60 رمز إخراج لكل طلب. الأسعار لكل مليون رمز حالية وتتغير مع تعريفاتنا؛ يعرض عمود OpenRouter أسعارًا مرجعية لنفس حجم العمل.
إجمالًا، مع احتساب الإدخال والإخراج معًا، يخرج DeepSeek-V4-Flash أرخص من OpenRouter لهذا الحمل. من حيث التوكنات، الطلب كله إدخال تقريبًا والرد قصير، لكن يُفوتر الجانبان، لذا قلّص الموجّه والإجابة على حد سواء. الأسعار لكل نموذج على صفحة التسعير، والنموذج نفسه موصوف على صفحة DeepSeek: سياق 380K، وحتى 32,768 توكن إخراج، وسعر واحد في أي ساعة.
طريقة سريعة لاستشعار النسب:
فحص سريع
أي جزء من الطلب يقيّده max_tokens=200؟
إظهار الإجابة
الإجابة: الرد
يقيّد max_tokens الرد فقط؛ ويُفوتر الموجّه كما هو، لذا قلّصه بشكل منفصل.
تريد 100,000 طلب شهريًا؟ اضرب في 100: 40,000,000 إدخال و6,000,000 إخراج توكن. ضع هذين الرقمين في ::cost بالطريقة نفسها واقرأ الصف.
اختبره على طلباتك الخاصة#
لا تقول نسبة 79.4% في البطاقة شيئًا عن موجّهك أو نظام تشغيلك أو صياغة مستخدميك. اكتب 20 طلبًا حقيقيًا مع الأوامر التي ستقبلها وقارن، تمامًا كما في testing a prompt on a small eval set. أدرج بعض الطلبات التي يجب أن يرفضها السكربت أو يعلّمها كغير مؤكدة، مثل "delete everything" أو "make my computer faster".
عندما يحدث خطأ ما، تشير العَرَض عادةً إلى الإصلاح:
Could not read the reply as JSON: اطبع النص الخام مرة واحدة. تُعالَج البادئة مثل "Sure!"؛ أما الرد المقطوع بالحد فلا، لذا تحقق منfinish_reason.401أو404: مفتاح أو عنوان URL أساسي أو معرّف نموذج خاطئ. القائمة في API 401 or 404: key, base URL, model id.- أوامر تناسب نظامًا مختلفًا: سطر السياق هو السبب. أبقِه دقيقًا (نظام التشغيل، مدير الحزم، الأدوات)؛ يكلّف بضع عشرات من التوكنات ويوفّر
aptخاطئًا على جهاز Fedora.
المهمة نفسها بنموذج مختلف؟ استبدل MODEL بمعرّف GLM أو MiniMax من الوثائق، وأبقِ الموجّه، وقارن أعداد التوكنات التي يطبعها السكربت بالجدول أعلاه.



