TramAI

Providers and Model Routing

What it is: TramAI supports multiple AI model providers with a unified API. Provider resolution follows a deterministic chain: operation override, model mapping, then default provider.

When to use it: Every TramAI application needs at least one provider configured. Use multiple providers when different operations need different models, you want fallback routing, or you need to switch between local and cloud models.

Provider Decision Guide

Not sure which provider to choose? Match your use case:

NeedRecommended ProviderWhy
Fast prototypingOpenAiProviderBroadcast model support, easiest setup, best ecosystem
Complex reasoningAnthropicProviderClaude excels at structured reasoning, long context, and nuanced tasks
Production gradeAnthropicProvider or OpenAiProviderBoth are production-tested with high reliability
Privacy / offlineOllamaProviderRuns 100% locally. Zero data leaves your machine
Budget-friendlyDeepSeekProviderCompetitive quality at lower cost via DeepSeek API
Google ecosystemGeminiProviderNative GCP integration, strong multimodal capabilities
AWS nativeBedrockProviderManaged access through AWS IAM, no API key management
Azure AD / enterpriseAzureOpenAiProviderAzure OpenAI with managed identity and compliance controls
Custom gatewayOpenAiCompatibleProviderConnect to internal AI gateways, self-hosted proxies, or any OpenAI-compatible endpoint

How Routing Works

TramAI resolves which provider to call in this exact order:

  1. Operation override: If @Operation(provider = "anthropic") is set, use that provider directly (skips model mapping)
  2. Model mapping: Look up the model name in the registry (e.g., "claude-sonnet-4-20250514" maps to "anthropic")
  3. Default provider: Use the provider marked default = true

Resolution Example

val tramai = Tramai {
   provider(OpenAiProvider(key), name = "openai", default = true)
   provider(AnthropicProvider(key), name = "anthropic")
   model("gpt-4o", "openai")
   model("claude-sonnet-4-20250514", "anthropic")
}

// Operation A: @Operation(model = "gpt-4o") → resolves to openai
// Operation B: @Operation(model = "claude-sonnet-4-20250514") → resolves to anthropic
// Operation C: @Operation(model = "unknown-model") → falls back to default provider (openai)
// Operation D: @Operation(model = "gpt-4o", provider = "anthropic") → explicit override → anthropic

Minimum Setup

val tramai = Tramai {
   provider(
       OpenAiProvider(apiKey = System.getenv("OPENAI_API_KEY")),
       name = "openai",
       default = true,
   )
   model("gpt-4o", "openai")
}

That's one provider, one model mapping. Every operation defaults to gpt-4o on OpenAI.

All Supported Providers

OpenAI (tramai-openai)

The standard choice for most applications. Supports GPT-4o, GPT-4o-mini, o-series models, and DALL-E through image APIs.

// API key
provider(
   OpenAiProvider(apiKey = System.getenv("OPENAI_API_KEY")),
   name = "openai",
)

// Bearer token
OpenAiProvider.bearerToken(
   bearerToken = System.getenv("OPENAI_BEARER_TOKEN"),
)

// Codex auth (experimental)
OpenAiProvider.codexAuth()

Dependency: dev.tramai:tramai-openai:0.3.1

Anthropic (tramai-anthropic)

Claude models for complex reasoning, long context, and structured tasks.

provider(
   AnthropicProvider(apiKey = System.getenv("ANTHROPIC_API_KEY")),
   name = "anthropic",
)

Dependency: dev.tramai:tramai-anthropic:0.3.1

Gemini (tramai-gemini)

Google's Gemini models with native GCP integration and strong multimodal support.

provider(
   GeminiProvider(apiKey = System.getenv("GEMINI_API_KEY")),
   name = "gemini",
)

Dependency: dev.tramai:tramai-gemini:0.3.1

DeepSeek (tramai-deepseek)

DeepSeek models at competitive pricing. Built on OpenAiCompatibleProvider.

provider(
   DeepSeekProvider(apiKey = System.getenv("DEEPSEEK_API_KEY")),
   name = "deepseek",
)

Dependency: dev.tramai:tramai-deepseek:0.3.1

Ollama (tramai-ollama)

Run models locally with Ollama. Perfect for development, testing, and privacy-sensitive workloads.

provider(
   OllamaProvider(baseUrl = "http://localhost:11434"),
   name = "ollama",
)

Dependency: dev.tramai:tramai-ollama:0.3.1

Bedrock (tramai-bedrock)

AWS Bedrock with IAM-based access. No API key to manage — uses AWS credentials from the environment.

provider(
   BedrockProvider(region = "us-west-2"),
   name = "bedrock",
)

Dependency: dev.tramai:tramai-bedrock:0.3.1

Azure OpenAI (tramai-azure-openai)

Azure OpenAI Service with resource-based endpoints and managed identity support.

provider(
   AzureOpenAiProvider(
       resourceName = "my-resource",
       deploymentId = "gpt-4o",
       apiKey = System.getenv("AZURE_OPENAI_API_KEY"),
   ),
   name = "azure-openai",
)

Dependency: dev.tramai:tramai-azure-openai:0.3.1

OpenAiCompatibleProvider (tramai-openai)

Connect to any service implementing the OpenAI Chat Completions API format — internal AI gateways, self-hosted proxies, or specialized vendors.

// Bearer token auth
provider(
   OpenAiCompatibleProvider.bearerToken(
       bearerToken = System.getenv("GATEWAY_TOKEN"),
       baseUrl = "https://your-gateway.internal/v1",
       providerName = "internal-ai",
   ),
   name = "internal-ai",
)

// API key auth
OpenAiCompatibleProvider(
   baseUrl = "https://your-gateway.internal/v1",
   apiKey = System.getenv("GATEWAY_KEY"),
   providerName = "internal-ai",
)

Dependency: dev.tramai:tramai-openai:0.3.1

Fallback Routing

When the primary provider fails (network error, rate limit, model unavailable), TramAI can fall back to an alternative route:

val tramai = Tramai {
   provider(OpenAiProvider(key), name = "openai", default = true)
   provider(AnthropicProvider(key), name = "anthropic")

   model("gpt-4o", "openai")
   model("claude-sonnet-4-20250514", "anthropic")

   // Fallback: gpt-4o → claude-sonnet-4-20250514 on anthropic
   fallbackModel("gpt-4o", "claude-sonnet-4-20250514", "anthropic")

   // Alternative: keep the same model on a different provider
   fallbackProvider("gpt-4o", "openai-fallback")
}

Fallback happens only at operation startup (before the first token for streaming). Engine handles the retry scheduling, circuit breaker, and jitter automatically.

Kotlin + Java Examples

Kotlin

val tramai = Tramai {
   provider(OpenAiProvider(System.getenv("OPENAI_API_KEY")), name = "openai")
   provider(AnthropicProvider(System.getenv("ANTHROPIC_API_KEY")), name = "anthropic")
   provider(OllamaProvider("http://localhost:11434"), name = "ollama")

   model("gpt-4o", "openai")
   model("claude-sonnet-4-20250514", "anthropic")
   model("llama3.2", "ollama")

   fallbackModel("gpt-4o", "claude-sonnet-4-20250514", "anthropic")
   defaultProvider = "openai"
}

Java

Tramai tramai = Tramai.builder()
   .provider(new OpenAiProvider(System.getenv("OPENAI_API_KEY")), "openai", true)
   .provider(new AnthropicProvider(System.getenv("ANTHROPIC_API_KEY")), "anthropic", false)
   .model("gpt-4o", "openai")
   .model("claude-sonnet-4-20250514", "anthropic")
   .fallbackModel("gpt-4o", "claude-sonnet-4-20250514", "anthropic")
   .build();

Environmental Provider Selection

Swap providers based on environment:

val tramai = Tramai {
   val (provider, name) = if (isDevEnvironment()) {
       OllamaProvider("http://localhost:11434") to "ollama"
   } else {
       OpenAiProvider(System.getenv("OPENAI_API_KEY")) to "openai"
   }
   provider(provider, name = name, default = true)
}

Provider Configuration Cheat Sheet

ProviderAuthKey Config
OpenAIapiKey or bearerTokenSystem.getenv("OPENAI_API_KEY")
AnthropicapiKeySystem.getenv("ANTHROPIC_API_KEY")
GeminiapiKeySystem.getenv("GEMINI_API_KEY")
DeepSeekapiKeySystem.getenv("DEEPSEEK_API_KEY")
OllamabaseUrl"http://localhost:11434"
BedrockAWS credentials (env/instance profile)region = "us-west-2"
Azure OpenAIapiKey + resourceName + deploymentIdSystem.getenv("AZURE_OPENAI_API_KEY")
OpenAiCompatiblebearerToken or apiKey + baseUrlCustom

Limitations

  • No dynamic provider selection: Provider resolution happens at call time based on the configured registry. There is no runtime provider selector that changes mid-operation.
  • No multi-provider aggregation: Each call goes to exactly one provider. No ensemble or voting across providers.
  • No provider-native streaming fallback: Fallback applies to the startup phase only. Once streaming starts, no failover occurs.
  • Provider-specific features: Provider-specific capabilities (thinking tokens, tool-use, image understanding) are available through the unified API but may have provider-specific behaviors.

Next Steps