API & SDKHướng dẫn
Yêu cầu đầu tiên trong Rust với async-openai: base URL, key, usage
Một chương trình Rust nhỏ với tokio và async-openai gửi một chat completion đến CheapTokens và in câu trả lời cùng số token.

Trên trang này
Để gọi CheapTokens từ Rust với async-openai, hãy tạo một OpenAIConfig với base URL https:/ và key của bạn, sau đó gửi yêu cầu bằng create_byot và một body JSON. Văn bản trả lời và số token được lấy ra từ JSON trả về. Chỉ khoảng 25 dòng code, và cùng một chương trình hoạt động với bất kỳ model nào trên trang model của CheapTokens sau khi bạn đổi một chuỗi.
Trang docs.rs của crate (kiểm tra ngày 8 tháng 11 năm 2026) liệt kê phiên bản 0.43.0 theo giấy phép MIT, và đây là phiên bản mà hướng dẫn này tuân theo.

Tại sao dùng create_byot thay vì request có kiểu#
async-openai thường cung cấp cho bạn một builder request có kiểu: bạn điền vào một struct, nó trả lại một struct. Điều đó thoải mái cho đến khi một gateway trả về một trường mà các struct không biết. Tính năng byot ("bring your own types") thêm các phương thức *_byot nhận bất kỳ body JSON nào và trả về bất kỳ kiểu nào bạn có thể deserialize, bao gồm cả serde_ thuần.
Với yêu cầu đầu tiên, đó chính xác là điều bạn muốn. Bạn viết cùng JSON mà bạn sẽ đặt trong một lệnh curl, và bạn đọc usage trực tiếp từ response, không cần tra cứu kiểu.
Thiết lập dự án#
Từng bước một
Tạo dự án và đặt key
Thêm các crate
Trong một dự án mới (cargo new cheaptokens-), thêm ba dependency. async-openai cần hai feature ở đây: byot cho các phương thức create_byot và chat-completion cho phần chat.
cargo add async-openai --features byot,chat-completion
cargo add tokio --features macros,rt-multi-thread
cargo add serde_jsonĐặt key trong biến môi trường
Tạo key trong tài khoản CheapTokens của bạn và giữ nó ngoài mã nguồn. Nếu bạn muốn phiên bản dài, xem cách lưu trữ API key an toàn.
export CHEAPTOKENS_API_KEY="paste-your-key-here"Trên Windows PowerShell, dòng tương tự là $env:CHEAPTOKENS_.
Chạy chương trình
Dán code từ phần tiếp theo vào src/main.rs và khởi chạy nó.
cargo runChương trình#
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(())
}Ba dòng chứa toàn bộ ý tưởng. with_api_base là nơi CheapTokens được đưa vào: base URL kết thúc bằng /v1, và async-openai tự thêm đường dẫn endpoint. with_api_key lấy giá trị chúng ta đọc từ môi trường. Và model là id đầy đủ deepseek- — các tên ngắn từ bảng giá không được API chấp nhận.
Truy cập một Value với key bị thiếu sẽ cho null thay vì panic, vì vậy một lỗi đánh máy trong tên trường sẽ hiện ra dưới dạng null trong output thay vì crash. Điều đó tiện khi bạn đang khám phá một response.
Những gì trả về#
Gateway nói định dạng OpenAI Chat Completions, vì vậy response có hình dạng thông thường (được cắt gọn ở đây, các dấu ... đánh dấu các trường chúng ta bỏ qua):
{
"choices": [
{ "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0 }
}Các con số trong usage là số đếm thực cho yêu cầu của bạn, vì vậy chúng thay thế các số không khi bạn chạy nó. prompt_tokens là những gì bạn đã gửi, completion_ là những gì model đã viết. Chúng được tính giá khác nhau, đó là mục đích của việc in chúng ra. Nếu sự khác biệt này mới với bạn, input vs output tokens giải thích trong năm phút.
Tự mình thử xemThử xem: đặt "max_tokens" thành 5 và chạy lại. finish_reason nói gì?Hiện đáp án
Trong định dạng OpenAI Chat Completions, nó nói length. Model đã chạm giới hạn của bạn và câu bị cắt giữa chừng. Với một câu trả lời bình thường, nó nói stop. Nếu bạn thấy length trong một công việc thực tế, hãy tăng max_tokens — bài viết này đề cập đến cách khắc phục.
Một yêu cầu tốn bao nhiêu#
Giả sử bạn chạy cuộc gọi này trong một vòng lặp, một câu hỏi nhỏ vào và một câu trả lời ngắn ra: 300 token input và 200 token output mỗi lần. Trên DeepSeek-V4-Flash, đó là $0.000025 mỗi yêu cầu, từ giá trực tiếp là $0.015 trên 1M token input và $0.10 trên 1M token output. Tính gộp lại, input và output, rẻ hơn OpenRouter, và model giữ ngữ cảnh 380K và trả lời tối đa 32.768 token.
Bảng dưới đây hiển thị cùng yêu cầu trên mọi model, nhân với 1.000.
| Mô hình | Đầu vào $/1M | Đầu ra $/1M | Mỗi yêu cầu | 1.000 yêu cầu | OpenRouter, 1.000 yêu cầu |
|---|---|---|---|---|---|
| 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 token đầu vào và 200 token đầu ra mỗi yêu cầu. Giá trên 1 triệu token là giá hiện hành và thay đổi cùng với biểu phí của chúng tôi; cột OpenRouter hiển thị giá tham chiếu cho cùng khối lượng công việc.
Giá có trên trang định giá.
Chuyển đổi model#
Code không thay đổi khi model thay đổi; chỉ chuỗi trong "model" thay đổi. Ví dụ, zai- có ngữ cảnh 390K và trả lời tối đa 8.192 token. Để tránh chỉnh sửa code hoàn toàn, hãy đọc id từ một biến thứ hai với std::env::var("CHEAPTOKENS_. Nếu bạn không chắc key của mình thấy những id nào, liệt kê model với GET /v1/models.
Nếu nó không hoạt động#
environment variable not foundngay từ đầu: key chưa được export trong terminal này. Export lại trong cùng cửa sổ nơi bạn chạycargo run.- Lỗi 401 từ API: key sai hoặc có khoảng trắng hoặc dấu ngoặc kép thừa xung quanh nó.
- Lỗi 404: kiểm tra rằng base URL kết thúc bằng
/v1và id model là id đầy đủ, với tiền tốdeepseek-ai/. API 401 hoặc 404: key, base URL, model id hướng dẫn qua. - Trình biên dịch không tìm thấy
create_byot: featurebyotchưa được bật. Chạy lại dòngcargo addtừ phần thiết lập.
Đối với một vấn đề kết nối không thuộc các trường hợp trên, xem các lỗi kết nối phổ biến.
Yêu cầu đầu tiên tương tự tồn tại cho các ngôn ngữ khác: Go và Ruby. Để biết thêm về API, mở tài liệu CheapTokens.



