Providers and models
A Model value carries both the provider and the wire model ID. Choosing a model therefore chooses a provider — there is no separate provider setting to keep in sync.
#![allow(unused)]
fn main() {
use rai_sdk::{Model, ProviderKind};
let model = Model::gpt4o_mini();
assert_eq!(model.provider(), ProviderKind::OpenAI);
}
OpenAI
Constructors cover the current GPT and reasoning families, for example:
#![allow(unused)]
fn main() {
use rai_sdk::Model;
let _ = Model::gpt4o_mini();
let _ = Model::gpt4o();
let _ = Model::gpt4_1();
let _ = Model::gpt5();
let _ = Model::gpt5_mini();
let _ = Model::o3();
let _ = Model::o4_mini();
}
Reasoning (o-series) models are detected by the SDK, which omits sampling parameters they reject such as temperature and top_p. You do not need to special-case that yourself.
Anthropic
#![allow(unused)]
fn main() {
use rai_sdk::Model;
let _ = Model::claude_sonnet_46();
let _ = Model::claude_opus_47();
let _ = Model::claude_haiku_45();
let _ = Model::claude_35_sonnet();
}
Anthropic model IDs are not vendor-prefixed, unlike OpenRouter’s.
OpenRouter
OpenRouter proxies many vendors behind one API, which makes it a good default when you want breadth without managing several accounts.
#![allow(unused)]
fn main() {
use rai_sdk::Model;
// Let OpenRouter pick.
let _ = Model::openrouter_auto();
// Curated constructors.
let _ = Model::openrouter_gpt5();
let _ = Model::openrouter_claude_sonnet_4_5();
let _ = Model::openrouter_gemini_25_flash();
let _ = Model::openrouter_deepseek_r1();
let _ = Model::openrouter_qwen3_coder();
}
OpenRouter IDs are vendor-prefixed (vendor/model).
Any OpenRouter model
The curated list will always lag the catalog, so pass an ID directly for anything not covered:
#![allow(unused)]
fn main() {
use rai_sdk::Model;
let model = Model::openrouter_custom("mistralai/mistral-large-2512");
}
The ID is passed through verbatim, so a typo surfaces as a provider error rather than a compile error.
Attribution
OpenRouter identifies calling apps through attribution headers. Set them once on the client:
use rai_sdk::{ClientBuilder, Model};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ClientBuilder::new()
.from_env()
.openrouter_http_referer("https://your-app.example")
.openrouter_title("Your App")
.model(Model::openrouter_auto())
.build()?;
let response = client
.request()
.prompt("Summarize OpenRouter in one paragraph.")
.generate()
.await?;
println!("{}", response.text());
Ok(())
}
See Configuration for the environment-variable equivalents.
Choosing a provider
- OpenAI — strongest structured-output support via native JSON Schema mode.
- Anthropic — long-context work and tool use.
- OpenRouter — breadth, fallback, and access to models you do not have direct accounts for. Note that per-vendor quirks leak through: Gemini models reached via OpenRouter reject schemas containing
$schema,$defs, or$ref, which is why the SDK normalizes and inlines generated schemas. See Structured output.
Mixing providers in one process
One client has one default model, but each request can override it, and a client only needs credentials for the providers it actually uses. Check availability at runtime:
use rai_sdk::{ClientBuilder, Model, ProviderKind};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ClientBuilder::new()
.from_env()
.model(Model::gpt4o_mini())
.build()?;
if client.is_provider_available(ProviderKind::Anthropic) {
let response = client
.request()
.model(Model::claude_sonnet_46())
.prompt("Hello from Anthropic.")
.generate()
.await?;
println!("{}", response.text());
}
Ok(())
}