Назад в блог

API и SDKИнструкция

Первый запрос на Rust через async-openai: base URL, ключ, usage

Небольшая программа на Rust с tokio и async-openai: один запрос к CheapTokens, вывод ответа и числа токенов из usage.

Автор: CheapTokens TeamОпубликовано 4 мин чтения

Первый запрос на Rust: cargo add async-openai, экспорт ключа, cargo run
Содержание
  1. Зачем create_byot вместо типизированных запросов
  2. Подготовьте проект
  3. Программа
  4. Что приходит в ответ
  5. Сколько стоит один запрос
  6. Как сменить модель
  7. Если не работает

Чтобы вызвать CheapTokens из Rust через async-openai, соберите OpenAIConfig с адресом https://api.cheaptokens.dev/v1 и своим ключом, а запрос отправьте методом create_byot с JSON-телом. Текст ответа и число токенов читаются из JSON, который вернулся. Это около 25 строк кода, и та же программа работает с любой моделью со страницы моделей CheapTokens — меняется одна строка.

По странице крейта на docs.rs (проверено 8 ноября 2026) последняя версия — 0.43.0, лицензия MIT. Гайд написан под неё.

Схема программы: ключ из окружения, OpenAIConfig, create_byot, JSON Value
Что делает программа, шаг за шагом

Зачем create_byot вместо типизированных запросов#

Обычно async-openai даёт типизированный конструктор запроса: вы заполняете структуру и получаете структуру обратно. Это удобно, пока шлюз не вернёт поле, которого в структурах нет. Feature byot («bring your own types») добавляет методы *_byot: они принимают любое JSON-тело и возвращают любой тип, в который можно десериализовать, в том числе обычный serde_json::Value.

Для первого запроса это то, что нужно. Вы пишете тот же JSON, что и в curl, и читаете usage прямо из ответа, ничего не выискивая в типах.

Подготовьте проект#

Шаг за шагом

Создайте проект и задайте ключ

Добавьте крейты

В новом проекте (cargo new cheaptokens-rust) добавьте три зависимости. Для async-openai здесь нужны две feature: byot ради методов create_byot и chat-completion для раздела чата.

bash
cargo add async-openai --features byot,chat-completion
cargo add tokio --features macros,rt-multi-thread
cargo add serde_json

Положите ключ в переменную окружения

Создайте ключ в аккаунте CheapTokens и держите его вне исходников. Подробнее — в статье как безопасно хранить API-ключ.

bash
export CHEAPTOKENS_API_KEY="paste-your-key-here"

В Windows PowerShell та же строка выглядит так: $env:CHEAPTOKENS_API_KEY="paste-your-key-here".

Запустите программу

Вставьте код из следующего раздела в src/main.rs и запустите.

bash
cargo run

Программа#

rust
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-ai/DeepSeek-V4-Flash-0731: короткие названия из таблиц цен API не принимает.

Если обратиться к Value по несуществующему ключу, вы получите null, а не панику. Опечатка в имени поля проявится как null в выводе, а не как падение программы. Для разведки ответа это удобно.

Что приходит в ответ#

Шлюз говорит на формате OpenAI Chat Completions, поэтому ответ выглядит привычно (сокращённо, ... — пропущенные поля):

json
{
  "choices": [
    { "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 0, "completion_tokens": 0 }
}

Числа в usage — настоящие счётчики вашего запроса, при запуске нули заменятся ими. prompt_tokens — то, что вы отправили, completion_tokens — то, что написала модель. Они стоят по-разному, ради этого их и стоит печатать. Если разница для вас нова, статья про входные и выходные токены объясняет её за пять минут.

Попробуйте самиПопробуйте: поставьте "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.

Модель За запрос 1 000 запросов OpenRouter, 1 000 запросов
GLM-5.3-Flash $0.000014 $0.014 $0.0267
DeepSeek-V4-Flash $0.000025 $0.0245 $0.049
MiniMax-M2.7 $0.000045 $0.045 $0.54

300 входных и 200 выходных токенов на запрос. Цены за 1M токенов актуальны и меняются вместе с нашими тарифами; столбец OpenRouter показывает справочные цены для той же нагрузки.

Актуальные цены — на странице тарифов.

Как сменить модель#

Код при смене модели не меняется, меняется только строка в "model". Например, у zai-org/GLM-5.3-Flash контекст 390K и ответ до 8 192 токенов. Чтобы вообще не править код, прочитайте id из второй переменной: std::env::var("CHEAPTOKENS_MODEL"). Если не уверены, какие 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: не включена feature byot. Повторите строку cargo add из подготовки проекта.

Если проблема с соединением другая, загляните в частые ошибки подключения.

Такой же первый запрос есть для других языков: Go и Ruby. Подробнее об API — в документации CheapTokens.