API и SDKИнструкция
Первый запрос на Rust через async-openai: base URL, ключ, usage
Небольшая программа на Rust с tokio и async-openai: один запрос к CheapTokens, вывод ответа и числа токенов из usage.

Содержание
Чтобы вызвать CheapTokens из Rust через async-openai, соберите OpenAIConfig с адресом https:/ и своим ключом, а запрос отправьте методом create_byot с JSON-телом. Текст ответа и число токенов читаются из JSON, который вернулся. Это около 25 строк кода, и та же программа работает с любой моделью со страницы моделей CheapTokens — меняется одна строка.
По странице крейта на docs.rs (проверено 8 ноября 2026) последняя версия — 0.43.0, лицензия MIT. Гайд написан под неё.

Зачем create_byot вместо типизированных запросов#
Обычно async-openai даёт типизированный конструктор запроса: вы заполняете структуру и получаете структуру обратно. Это удобно, пока шлюз не вернёт поле, которого в структурах нет. Feature byot («bring your own types») добавляет методы *_byot: они принимают любое JSON-тело и возвращают любой тип, в который можно десериализовать, в том числе обычный serde_.
Для первого запроса это то, что нужно. Вы пишете тот же JSON, что и в curl, и читаете usage прямо из ответа, ничего не выискивая в типах.
Подготовьте проект#
Шаг за шагом
Создайте проект и задайте ключ
Добавьте крейты
В новом проекте (cargo new cheaptokens-) добавьте три зависимости. Для async-openai здесь нужны две feature: 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: базовый адрес заканчивается на /v1, а путь эндпоинта async-openai дописывает сам. with_api_key берёт значение, которое мы прочитали из окружения. А model — полный id deepseek-: короткие названия из таблиц цен API не принимает.
Если обратиться к Value по несуществующему ключу, вы получите null, а не панику. Опечатка в имени поля проявится как 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 выходных токенов на запрос. Цены за 1M токенов актуальны и меняются вместе с нашими тарифами; столбец OpenRouter показывает справочные цены для той же нагрузки.
Актуальные цены — на странице тарифов.
Как сменить модель#
Код при смене модели не меняется, меняется только строка в "model". Например, у zai- контекст 390K и ответ до 8 192 токенов. Чтобы вообще не править код, прочитайте id из второй переменной: std::env::var("CHEAPTOKENS_. Если не уверены, какие id видит ваш ключ, получите список моделей через GET /v1/models.
Если не работает#
environment variable not foundсразу при старте: ключ не экспортирован в этом терминале. Выполнитеexportещё раз в том же окне, где запускаетеcargo run.- Ошибка 401 от API: ключ неверный или вокруг него затесался пробел или кавычка.
- Ошибка 404: проверьте, что base URL заканчивается на
/v1, а id модели полный, с префиксомdeepseek-ai/. Разбор — в статье ошибка API 401 или 404: ключ, base URL, id модели. - Компилятор не находит
create_byot: не включена featurebyot. Повторите строкуcargo addиз подготовки проекта.
Если проблема с соединением другая, загляните в частые ошибки подключения.
Такой же первый запрос есть для других языков: Go и Ruby. Подробнее об API — в документации CheapTokens.



