API وSDKدليل
أول طلب في Rust باستخدام async-openai: عنوان URL الأساسي، المفتاح، الاستخدام
برنامج Rust صغير باستخدام tokio وasync-openai يرسل إكمال محادثة واحدًا إلى CheapTokens ويطبع الرد وأعداد الرموز.

في هذه الصفحة
لاستدعاء CheapTokens من Rust باستخدام async-openai، أنشئ OpenAIConfig بعنوان URL الأساسي https:/ ومفتاحك، ثم أرسل الطلب باستخدام create_byot وجسم JSON. يخرج نص الرد وأعداد الرموز من JSON الذي يعود. هذا نحو 25 سطرًا من الشيفرة، ويعمل البرنامج نفسه مع أي نموذج على صفحة نماذج CheapTokens بمجرد تغيير سلسلة واحدة.
تسرد صفحة docs.rs الخاصة بالحزمة (تم التحقق منها في 8 نوفمبر 2026) الإصدار 0.43.0 تحت رخصة MIT، وهذا هو الإصدار الذي يتبعه هذا الدليل.

لماذا create_byot بدلًا من الطلبات المكتوبة الأنواع#
عادةً ما يمنحك async-openai مُنشئ طلبات مكتوب الأنواع: تملأ بنية، فيعيد لك بنية. هذا مريح حتى يعيد البوابة حقلًا لا تعرفه البنيات. تضيف ميزة byot ("أحضر أنواعك الخاصة") دوال *_byot التي تقبل أي جسم JSON وتعيد أي نوع يمكنك إلغاء تسلسله إليه، بما في ذلك serde_ العادي.
بالنسبة لأول طلب، هذا بالضبط ما تريده. تكتب نفس JSON التي كنت ستضعها في استدعاء curl، وتقرأ usage مباشرة من الاستجابة، دون نوع تبحث عنه.
إعداد المشروع#
خطوة بخطوة
أنشئ المشروع واضبط المفتاح
أضف الحزم
في مشروع جديد (cargo new cheaptokens-)، أضف ثلاث تبعيات. يحتاج async-openai إلى ميزتين هنا: byot لدوال create_byot وchat-completion لقسم المحادثة.
cargo add async-openai --features byot,chat-completion
cargo add tokio --features macros,rt-multi-thread
cargo add serde_jsonضع المفتاح في متغير بيئة
أنشئ المفتاح في حسابك على CheapTokens وأبقه خارج الشيفرة المصدرية. إذا أردت النسخة الطويلة، راجع كيفية تخزين مفتاح API بأمان.
export CHEAPTOKENS_API_KEY="paste-your-key-here"في Windows PowerShell يكون السطر نفسه $env:CHEAPTOKENS_.
شغّل البرنامج
الصق الشيفرة من القسم التالي في src/main.rs وابدأ تشغيله.
cargo runالبرنامج#
use async_openai::{config::OpenAIConfig, Client};
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = std::env::var("CHEAPTOKENS_API_KEY")?;
let config = OpenAIConfig::new()
.with_api_key(key)
.with_api_base("https://api.cheaptokens.dev/v1");
let client = Client::with_config(config);
let response: Value = client
.chat()
.create_byot(json!({
"model": "deepseek-ai/DeepSeek-V4-Flash-0731",
"messages": [
{"role": "user", "content": "Explain what a token is in one sentence."}
],
"max_tokens": 100
}))
.await?;
let choice = &response["choices"][0];
println!("{}", choice["message"]["content"].as_str().unwrap_or("(no text)"));
println!("finish_reason: {}", choice["finish_reason"]);
println!("input tokens: {}", response["usage"]["prompt_tokens"]);
println!("output tokens: {}", response["usage"]["completion_tokens"]);
Ok(())
}ثلاثة أسطر تحمل الفكرة كلها. with_api_base هو حيث يدخل CheapTokens: ينتهي عنوان URL الأساسي بـ /v1، ويضيف async-openai مسار نقطة النهاية بنفسه. with_api_key يأخذ القيمة التي قرأناها من متغير البيئة. وmodel هو المعرّف الكامل deepseek- — الأسماء القصيرة من جداول الأسعار لا يقبلها API.
فهرسة Value بمفتاح مفقود تعطي null بدلًا من panic، لذا يظهر خطأ مطبعي في اسم حقل كـ null في المخرجات بدلًا من انهيار. هذا مفيد عند استكشاف استجابة.
ما يعود#
تتحدث البوابة صيغة OpenAI Chat Completions، لذا يكون للاستجابة الشكل المعتاد (مقتطعة هنا، علامات ... تشير إلى حقول نتخطاها):
{
"choices": [
{ "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0 }
}الأرقام في usage هي أعداد حقيقية لطلبك، لذا تحل محل الأصفار عند تشغيله. prompt_tokens هو ما أرسلته، وcompletion_ هو ما كتبه النموذج. يُفوتران بأسعار مختلفة، وهذا هو الهدف من طباعتهما. إذا كانت الفروق جديدة عليك، فإن رموز الإدخال مقابل الإخراج تشرحها في خمس دقائق.
جرّب بنفسكجرّب: اضبط "max_tokens" على 5 وشغّل مرة أخرى. ماذا يقول finish_reason؟إظهار الإجابة
في صيغة OpenAI Chat Completions يقول length. وصل النموذج إلى الحد الذي وضعته وانقطعت الجملة في منتصفها. مع إجابة عادية يقول stop. إذا رأيت length في مهمة حقيقية، فارفع max_tokens — هذا المقال يغطي الحل.
تكلفة طلب واحد#
لنفترض أنك تشغّل هذا الاستدعاء في حلقة، سؤال صغير داخل وإجابة قصيرة خارج: 300 رمز إدخال و200 رمز إخراج في كل مرة. على DeepSeek-V4-Flash هذا $0.000025 لكل طلب، من السعر الحالي $0.015 لكل 1M رمز إدخال و$0.10 لكل 1M رمز إخراج. محسوبين معًا، الإدخال والإخراج، هذا أرخص من OpenRouter، ويحتفظ النموذج بسياق 380K ويجيب حتى 32,768 رمزًا.
يوضح الجدول أدناه الطلب نفسه على كل نموذج، مضروبًا في 1,000.
| النموذج | الإدخال $/1M | الإخراج $/1M | لكل طلب | 1,000 طلبات | OpenRouter، 1,000 طلبات |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000014 | $0.014 | $0.0267 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.000025 | $0.0245 | $0.049 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000045 | $0.045 | $0.54 |
300 رمز إدخال و200 رمز إخراج لكل طلب. الأسعار لكل مليون رمز حالية وتتغير مع تعريفاتنا؛ يعرض عمود OpenRouter أسعارًا مرجعية لنفس حجم العمل.
الأسعار موجودة على صفحة التسعير.
تبديل النموذج#
لا تتغير الشيفرة عندما يتغير النموذج؛ فقط السلسلة في "model" تتغير. على سبيل المثال، zai- لديه سياق 390K ويجيب حتى 8,192 رمزًا. لتجنب تعديل الشيفرة تمامًا، اقرأ المعرّف من متغير ثانٍ باستخدام std::env::var("CHEAPTOKENS_. إذا لم تكن متأكدًا من المعرّفات التي يراها مفتاحك، فـاسرد النماذج باستخدام GET /v1/models.
إذا لم يعمل#
environment variable not foundفي البداية تمامًا: المفتاح غير مُصدَّر في هذا الطرفية. صدّره مرة أخرى في النافذة نفسها التي تشغّل فيهاcargo run.- خطأ 401 من API: المفتاح خاطئ أو حوله مسافة أو علامة اقتباس شاذة.
- خطأ 404: تحقق من أن عنوان URL الأساسي ينتهي بـ
/v1وأن معرّف النموذج هو الكامل، مع بادئةdeepseek-ai/. API 401 أو 404: المفتاح، عنوان URL الأساسي، معرّف النموذج يشرح ذلك خطوة بخطوة. - لا يجد المترجم
create_byot: ميزةbyotغير مفعّلة. شغّل سطرcargo addمن الإعداد مرة أخرى.
لمشكلة اتصال ليست أيًا من هذه، راجع أخطاء الاتصال الشائعة.
الطلب الأول نفسه موجود للغات أخرى: Go وRuby. لمزيد عن API نفسه، افتح وثائق CheapTokens.



