Model Providers (Cloud)

ADK-Rust supports multiple cloud LLM providers through the adk-model crate. All providers implement the Llm trait, making them interchangeable in your agents.

Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     Cloud Model Providers                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                     โ”‚
โ”‚   โ€ข Gemini (Google)    โญ Default    - Multimodal, large context    โ”‚
โ”‚   โ€ข OpenAI (GPT-5)    ๐Ÿ”ฅ Popular    - Best ecosystem               โ”‚
โ”‚   โ€ข Anthropic (Claude) ๐Ÿง  Smart      - Best reasoning               โ”‚
โ”‚   โ€ข DeepSeek           ๐Ÿ’ญ Thinking   - Chain-of-thought, cheap      โ”‚
โ”‚   โ€ข Groq               โšก Ultra-Fast  - Fastest inference           โ”‚
โ”‚                                                                     โ”‚
โ”‚   For local/offline models, see:                                    โ”‚
โ”‚   โ€ข Ollama     โ†’ ollama.md                                          โ”‚
โ”‚   โ€ข mistral.rs โ†’ mistralrs.md                                       โ”‚
โ”‚                                                                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Quick Comparison

ProviderBest ForSpeedCostKey Feature
GeminiGeneral useโšกโšกโšก๐Ÿ’ฐMultimodal, large context, thinking
OpenAIReliabilityโšกโšก๐Ÿ’ฐ๐Ÿ’ฐBest ecosystem
AnthropicComplex reasoningโšกโšก๐Ÿ’ฐ๐Ÿ’ฐSafest, most thoughtful
DeepSeekChain-of-thoughtโšกโšก๐Ÿ’ฐThinking mode, cheap
GroqSpeed-criticalโšกโšกโšกโšก๐Ÿ’ฐFastest inference

Step 1: Installation

Add the providers you need to your Cargo.toml:

[dependencies]
# Pick one or more providers:
adk-model = { version = "2.0.0", features = ["gemini"] }        # Google Gemini (default)
adk-model = { version = "2.0.0", features = ["openai"] }        # OpenAI GPT-5
adk-model = { version = "2.0.0", features = ["anthropic"] }     # Anthropic Claude
adk-model = { version = "2.0.0", features = ["deepseek"] }      # DeepSeek
adk-model = { version = "2.0.0", features = ["groq"] }          # Groq (ultra-fast)

# Or all cloud providers at once:
adk-model = { version = "2.0.0", features = ["all-providers"] }

Step 2: Set Your API Key

export GOOGLE_API_KEY="your-key"      # Gemini
export OPENAI_API_KEY="your-key"      # OpenAI
export ANTHROPIC_API_KEY="your-key"   # Anthropic
export DEEPSEEK_API_KEY="your-key"    # DeepSeek
export GROQ_API_KEY="your-key"        # Groq

Schema Normalization

Each provider automatically normalizes MCP tool schemas at request time. You don't need to do anything โ€” it works transparently. But here's what happens under the hood:

ProviderSchema AdapterBehavior
GeminiGeminiSchemaAdapterAggressive: resolves $ref, collapses combiners, strips unsupported keywords
OpenAI (strict)OpenAiStrictSchemaAdapterPreserves structure, adds additionalProperties: false
OpenAIOpenAiSchemaAdapterMinimal safe fixes
AnthropicAnthropicSchemaAdapterNear pass-through
DeepSeekGenericSchemaAdapterConservative safe transforms
OllamaGenericSchemaAdapterConservative safe transforms

Access the adapter programmatically via the Llm trait:

use adk_core::{Llm, SchemaAdapter};

let adapter = model.schema_adapter();
let normalized = adapter.normalize_schema(raw_schema);

See Schema Normalization for full documentation.


Gemini (Google) โญ Default

Best for: General purpose, multimodal tasks, large documents

Key highlights:

  • ๐Ÿ–ผ๏ธ Native multimodal (images, video, audio, PDF)
  • ๐Ÿ“š Up to 2M token context window
  • ๐Ÿง  Thinking mode: level-based (Gemini 3) and budget-based (Gemini 2.5) with thought signatures
  • ๐Ÿ’ฐ Competitive pricing
  • โšก Fast inference

Complete Working Example

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    let agent = LlmAgentBuilder::new("gemini_assistant")
        .description("Gemini-powered assistant")
        .instruction("You are a helpful assistant powered by Google Gemini. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

Available Models

ModelDescriptionContext
gemini-3.1-pro-previewStrongest reasoning for complex agentic workflows2M tokens
gemini-3-flash-previewFast and efficient for code and agents1M tokens
gemini-3.1-flash-lite-previewCheapest, fastest routing and high-volume tasks1M tokens
gemini-2.5-proAdvanced reasoning and multimodal1M tokens
gemini-2.5-flashBalanced speed and capability (recommended)1M tokens

Thinking Mode

Gemini 3 models support level-based thinking, while Gemini 2.5 uses budget-based thinking. When using thinking mode with function calling, Gemini 2.5+ and 3.x models return thoughtSignature values that must be echoed back in subsequent turns to preserve reasoning context. ADK-Rust handles this automatically โ€” signatures are serialized when present and omitted when None.

use adk_gemini::{Gemini, ThinkingLevel};

// Gemini 3: level-based thinking
let response = client.generate_content()
    .with_user_message("Solve this step by step")
    .with_thinking_level(ThinkingLevel::High)
    .with_thoughts_included(true)
    .execute().await?;

// Gemini 2.5: budget-based thinking
let response = client.generate_content()
    .with_user_message("Solve this step by step")
    .with_thinking_budget(2048)
    .with_thoughts_included(true)
    .execute().await?;

Example Output

๐Ÿ‘ค User: What's in this image? [uploads photo of a cat]

๐Ÿค– Gemini: I can see a fluffy orange tabby cat sitting on a windowsill. 
The cat appears to be looking outside, with sunlight illuminating its fur. 
It has green eyes and distinctive striped markings typical of tabby cats.

Best for: Production apps, reliable performance, broad capabilities

Key highlights:

  • ๐Ÿ† Industry standard
  • ๐Ÿ”ง Excellent tool/function calling
  • ๐Ÿ“– Best documentation & ecosystem
  • ๐ŸŽฏ Consistent, predictable outputs
  • ๐Ÿ“‹ Structured output with JSON schema enforcement
  • ๐Ÿง  Reasoning effort control for o1/o3 reasoning models
  • ๐Ÿ†• Responses API โ€” dedicated client for /v1/responses with reasoning summaries, built-in tools, and server-side state

Complete Working Example

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("OPENAI_API_KEY")?;
    let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?;

    let agent = LlmAgentBuilder::new("openai_assistant")
        .description("OpenAI-powered assistant")
        .instruction("You are a helpful assistant powered by OpenAI GPT-5. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

Structured Output (JSON Schema)

OpenAI supports guaranteed JSON output via output_schema. ADK-Rust automatically wires this to OpenAI's response_format API:

use adk_rust::prelude::*;
use serde_json::json;
use std::sync::Arc;

let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?;

let agent = LlmAgentBuilder::new("data_extractor")
    .model(Arc::new(model))
    .instruction("Extract person information from the text.")
    .output_schema(json!({
        "type": "object",
        "properties": {
            "name": { "type": "string" },
            "age": { "type": "number" },
            "email": { "type": "string" }
        },
        "required": ["name", "age"]
    }))
    .build()?;

// Response is guaranteed to be valid JSON matching the schema

For strict mode with nested objects, include additionalProperties: false at each level:

.output_schema(json!({
    "type": "object",
    "properties": {
        "title": { "type": "string" },
        "metadata": {
            "type": "object",
            "properties": {
                "author": { "type": "string" },
                "tags": { "type": "array", "items": { "type": "string" } }
            },
            "required": ["author"],
            "additionalProperties": false  // Required for nested objects
        }
    },
    "required": ["title", "metadata"],
    "additionalProperties": false  // Auto-injected at root level
}))

Reasoning Effort (o1, o3 Models)

For OpenAI reasoning models, control how much reasoning effort the model applies:

use adk_model::openai::{OpenAIClient, OpenAIConfig, ReasoningEffort};

let config = OpenAIConfig::new(&api_key, "o3-mini")
    .with_reasoning_effort(ReasoningEffort::High);
let model = OpenAIClient::new(config)?;

Available levels: Low, Medium, High. Higher effort produces more thorough reasoning at the cost of latency and tokens.

OpenAI-Compatible Local APIs

Use OpenAIConfig::compatible() to connect to local servers (Ollama, vLLM, LM Studio):

// Ollama exposes OpenAI-compatible API at /v1
let config = OpenAIConfig::compatible(
    "not-needed",                      // API key (ignored by Ollama)
    "http://localhost:11434/v1",       // Base URL
    "llama3.2"                         // Model name
);
let model = OpenAIClient::new(config)?;

Note: Structured output (output_schema) requires backend support. Native OpenAI fully supports it; local servers may have limited support.

Gemini via the OpenAI-Compatible Endpoint

Gemini models are reachable through the OpenAI Chat Completions wire format at https://generativelanguage.googleapis.com/v1beta/openai. Use the OpenAICompatibleConfig::gemini(...) preset (under the openai feature) with a GEMINI_API_KEY to run Gemini through the same OpenAI-compatible client you use for every other provider:

use adk_model::openai_compatible::{OpenAICompatible, OpenAICompatibleConfig};

let api_key = std::env::var("GEMINI_API_KEY")?;
let model = OpenAICompatible::new(
    OpenAICompatibleConfig::gemini(api_key, "gemini-3.5-flash"),
)?;

This path supports chat, streaming, function calling, structured output, and reasoning effort (OpenAI's reasoning_effort maps to Gemini thinking levels/budgets). Gemini-specific options โ€” e.g. thinking_config with include_thoughts, or cached_content โ€” are passed through the request's extensions["openai"]["extra_body"]["google"] map, which the client merges verbatim into the request body.

When to use this vs GeminiModel: For native Gemini features (server-side tools, the Interactions API, native ThinkingConfig, multimodal-first ergonomics), prefer GeminiModel. Use the OpenAI-compatible preset when you want a single uniform client across providers.

Examples (require GEMINI_API_KEY or GOOGLE_API_KEY):

# Direct client: chat, reasoning effort, extra_body thinking, streaming,
# function calling, structured output.
cargo run -p adk-model --features openai --example gemini_openai_compat

# The same compat client driving a normal LlmAgent in a Runner.
# (Lives in adk-agent: it exercises the agent layer, which sits above adk-model.)
cargo run -p adk-agent --example gemini_openai_compat_agent

Reasoning Effort (o1, o3 Models)

Control how much reasoning effort the model applies with ReasoningEffort:

use adk_model::openai::{OpenAIClient, OpenAIConfig, ReasoningEffort};

let config = OpenAIConfig::new(&api_key, "o3-mini")
    .with_reasoning_effort(ReasoningEffort::High);
let model = OpenAIClient::new(config)?;

Available levels: Low (fastest), Medium (balanced), High (most thorough).

Available Models

ModelDescriptionContext
gpt-5State-of-the-art unified model with adaptive thinking256K tokens
gpt-5-miniEfficient version for most tasks (recommended)128K tokens
gpt-5-nanoLowest-cost routing and classification128K tokens
gpt-4.1Stable production model for legacy GPT-4.1 deployments1M tokens

Example Output

๐Ÿ‘ค User: Write a haiku about Rust programming

๐Ÿค– GPT-5: Memory so safe,
Ownership guards every byteโ€”
Compiler, my friend.

Anthropic (Claude) ๐Ÿง  Smart

Best for: Complex reasoning, safety-critical apps, long documents

Key highlights:

  • ๐Ÿง  Exceptional reasoning ability
  • ๐Ÿ›ก๏ธ Most safety-focused
  • ๐Ÿ“š 200K token context
  • โœ๏ธ Excellent writing quality

Complete Working Example

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("ANTHROPIC_API_KEY")?;
    let model = AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-4-6"))?;

    let agent = LlmAgentBuilder::new("anthropic_assistant")
        .description("Anthropic-powered assistant")
        .instruction("You are a helpful assistant powered by Anthropic Claude. Be concise and thoughtful.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

Available Models

ModelDescriptionContext
claude-opus-4-7Most capable GA model, adaptive thinking only1M tokens
claude-opus-4-6Previous flagship for complex autonomous tasks1M tokens
claude-sonnet-4-6Balanced intelligence and cost (recommended)1M tokens
claude-haiku-4-5-20251001Ultra-efficient for high-volume workloads200K tokens
claude-opus-4-20250514Hybrid model with extended thinking200K tokens
claude-sonnet-4-20250514Balanced model with extended thinking1M tokens

Example Output

๐Ÿ‘ค User: Explain quantum entanglement to a 10-year-old

๐Ÿค– Claude: Imagine you have two magic coins. When you flip them, they always 
land the same way - both heads or both tails - even if one coin is on Earth 
and the other is on the Moon! Scientists call this "entanglement." The coins 
are connected in a special way that we can't see, like invisible best friends 
who always make the same choice at the exact same time.

DeepSeek ๐Ÿ’ญ Thinking

Best for: Complex problem-solving, math, coding, reasoning tasks

Key highlights:

  • ๐Ÿ’ญ Thinking mode - shows chain-of-thought reasoning
  • ๐Ÿ’ฐ Very cost-effective (10x cheaper than GPT-4)
  • ๐Ÿ”„ Context caching for repeated prefixes
  • ๐Ÿงฎ Strong at math and coding

Complete Working Example

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("DEEPSEEK_API_KEY")?;
    
    // Standard chat model
    let model = DeepSeekClient::chat(&api_key)?;
    
    // OR: Reasoning model with thinking mode
    // let model = DeepSeekClient::reasoner(&api_key)?;

    let agent = LlmAgentBuilder::new("deepseek_assistant")
        .description("DeepSeek-powered assistant")
        .instruction("You are a helpful assistant powered by DeepSeek. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

Available Models

ModelDescriptionSpecial Feature
deepseek-r1-0528Latest reasoning modelEnhanced thinking depth
deepseek-r1Advanced reasoningComparable to o1
deepseek-v3.1Latest 671B MoE modelGeneral tasks
deepseek-chat671B MoE model (V3)General purpose, cheap
deepseek-vl2Vision-language modelMultimodal

Example Output (Reasoner with Thinking Mode)

๐Ÿ‘ค User: What's 17 ร— 23?

๐Ÿค– DeepSeek: <thinking>
Let me break this down:
17 ร— 23 = 17 ร— (20 + 3)
       = 17 ร— 20 + 17 ร— 3
       = 340 + 51
       = 391
</thinking>

The answer is 391.

Groq โšก Ultra-Fast

Best for: Real-time applications, chatbots, speed-critical tasks

Key highlights:

  • โšก Fastest inference - 10x faster than competitors
  • ๐Ÿ”ง LPU (Language Processing Unit) technology
  • ๐Ÿ’ฐ Competitive pricing
  • ๐Ÿฆ™ Runs LLaMA, Mixtral, Gemma models

Complete Working Example

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("GROQ_API_KEY")?;
    let model = GroqClient::llama70b(&api_key)?;

    let agent = LlmAgentBuilder::new("groq_assistant")
        .description("Groq-powered assistant")
        .instruction("You are a helpful assistant powered by Groq. Be concise and fast.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

Available Models

ModelMethodDescription
llama-4-scoutGroqClient::new(GroqConfig::new(key, "llama-4-scout"))Llama 4 Scout (17Bx16E)
llama-3.2-90b-text-previewGroqClient::new(GroqConfig::new(key, "llama-3.2-90b-text-preview"))Large text model
llama-3.1-70b-versatileGroqClient::llama70b()Versatile large model
llama-3.1-8b-instantGroqClient::llama8b()Fastest
mixtral-8x7b-32768GroqClient::mixtral()Good balance
Any modelGroqClient::new(GroqConfig::new(key, "model"))Custom model

Example Output

๐Ÿ‘ค User: Quick! Name 5 programming languages

๐Ÿค– Groq (in 0.2 seconds): 
1. Rust
2. Python
3. JavaScript
4. Go
5. TypeScript

Switching Providers

All providers implement the same Llm trait, so switching is easy:

use adk_agent::LlmAgentBuilder;
use std::sync::Arc;

// Just change the model - everything else stays the same!
let model: Arc<dyn adk_core::Llm> = Arc::new(
    // Pick one:
    // GeminiModel::new(&api_key, "gemini-2.5-flash")?
    // OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?
    // AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-4-6"))?
    // DeepSeekClient::chat(&api_key)?
    // GroqClient::llama70b(&api_key)?
);

let agent = LlmAgentBuilder::new("assistant")
    .instruction("You are a helpful assistant.")
    .model(model)
    .build()?;

Examples

Use cargo-adk to generate provider-specific projects with validated 0.8 dependencies:

cargo adk new gemini_agent --provider gemini
cargo adk new openai_agent --template openai
cargo adk new anthropic_agent --provider anthropic

The generated projects are compiled in CI by scripts/check-cargo-adk-templates.sh. Browse and run the complete example gallery in the ADK-Rust Playground embedded in this website.



Previous: โ† Realtime Agents | Next: Ollama (Local) โ†’

What happens to content a provider cannot carry

Content can express more than any single provider transport accepts, so each adapter has to decide what to do with the remainder. Those decisions are now recorded rather than applied invisibly. Every part is classified:

DispositionMeaning
ConvertedCarried to the provider in an equivalent native form
DowngradedCarried in a lossier form โ€” a file reference rendered as descriptive text the model can read but not fetch
OmittedNot carried at all

Downgrades and omissions emit a tracing warning as they are recorded, naming the part kind, MIME type, and reason, so neither is silent.

To see the outcome before dispatching a request:

use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;

let content = Content {
    role: "user".to_string(),
    parts: vec![Part::inline_data("audio/wav", vec![0u8; 16])],
};
let report = report_for_contents(std::slice::from_ref(&content));

for omission in report.omitted_parts() {
    println!("{} was dropped: {}", omission.kind, omission.detail);
}

To refuse a request that would reach the model incomplete rather than receive an answer about material the model never saw:

use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;

let content = Content {
    role: "user".to_string(),
    parts: vec![Part::inline_data("video/mp4", vec![0u8; 16])],
};

if let Some(error) = report_for_contents(std::slice::from_ref(&content)).into_error() {
    return Err(error);
}

into_error covers omissions only. A downgrade still reaches the model, and rejecting it would refuse the documented textual fallback.

Note: the ledger is complete by construction. Any part that leaves an adapter without a recorded fate โ€” including one added by a future change โ€” is recorded as an omission with an explicit "no recorded reason", and adk-model/tests/part_conversion_matrix_tests.rs fails on it.

Bedrock Converse coverage

PartDisposition
Text, FunctionCall, FunctionResponse, ThinkingConverted
InlineData with JPEG, PNG, GIF, WebPConverted as an image block
InlineData with a supported document type (PDF and similar)Converted as a document block
InlineData with audio, video, or arbitrary binaryOmitted
FileData for an image or supported documentDowngraded to text โ€” Converse takes S3 URIs, not arbitrary URLs
FileData for any other typeOmitted
ServerToolCall, ServerToolResponseOmitted โ€” Gemini-specific
EmbeddedResource text, or a blob of a supported typeConverted
EmbeddedResource blob of an unsupported typeOmitted