Skip to content

Provider & Model Management

This page adapts the original AI SDK documentation: Provider & Model Management.

When you work with multiple providers and models, it is often desirable to manage them in a central place and access the models through simple string ids.

The AI SDK offers custom providers and a provider registry for this purpose:

  • With custom providers, you can pre-configure model settings, provide model name aliases, and limit the available models.
  • The provider registry lets you mix multiple providers and access them through simple string ids.

You can mix and match custom providers, the provider registry, and middleware in your application.

You can create a custom provider using customProvider.

You might want to override the default model settings for a provider or provide model name aliases with pre-configured settings.

import SwiftAISDK
import OpenAIProvider
// Custom provider with different provider options:
let customOpenAI = customProvider(
languageModels: [
// Replacement model with custom provider options:
"gpt-4o": wrapLanguageModel(
model: openai.languageModel(modelId: "gpt-4o"),
middleware: .single(defaultSettingsMiddleware(
settings: DefaultSettings(
providerOptions: ["openai": [
"reasoningEffort": "high"
]]
)
))
),
// Alias model with custom provider options:
"gpt-4o-mini-high-reasoning": wrapLanguageModel(
model: openai.languageModel(modelId: "gpt-4o-mini"),
middleware: .single(defaultSettingsMiddleware(
settings: DefaultSettings(
providerOptions: ["openai": [
"reasoningEffort": "high"
]]
)
))
)
],
fallbackProvider: openai
)

You can also provide model name aliases, so you can update the model version in one place in the future:

import SwiftAISDK
import AnthropicProvider
// Custom provider with alias names:
let customAnthropic = customProvider(
languageModels: [
"opus": anthropic.languageModel(modelId: "claude-3-opus-20240229"),
"sonnet": anthropic.languageModel(modelId: "claude-3-5-sonnet-20240620"),
"haiku": anthropic.languageModel(modelId: "claude-3-haiku-20240307")
],
fallbackProvider: anthropic
)

You can limit the available models in the system, even if you have multiple providers.

import SwiftAISDK
import AnthropicProvider
import OpenAIProvider
let myProvider = customProvider(
languageModels: [
"text-medium": anthropic.languageModel(modelId: "claude-3-5-sonnet-20240620"),
"text-small": openai.languageModel(modelId: "gpt-4o-mini"),
"reasoning-medium": wrapLanguageModel(
model: openai.languageModel(modelId: "gpt-4o"),
middleware: .single(defaultSettingsMiddleware(
settings: DefaultSettings(
providerOptions: ["openai": [
"reasoningEffort": "high"
]]
)
))
),
"reasoning-fast": wrapLanguageModel(
model: openai.languageModel(modelId: "gpt-4o-mini"),
middleware: .single(defaultSettingsMiddleware(
settings: DefaultSettings(
providerOptions: ["openai": [
"reasoningEffort": "high"
]]
)
))
)
],
textEmbeddingModels: [
"embedding": openai.textEmbeddingModel(modelId: "text-embedding-3-small")
]
// No fallback provider
)

You can create a provider registry with multiple providers and models using createProviderRegistry.

import SwiftAISDK
import AnthropicProvider
import OpenAIProvider
let registry = createProviderRegistry(
providers: [
// Register provider with prefix:
"anthropic": anthropic,
// Register provider with custom configuration:
"openai": createOpenAI(
apiKey: ProcessInfo.processInfo.environment["OPENAI_API_KEY"]
)
]
)

By default, the registry uses : as the separator between provider and model IDs. You can customize this separator:

import SwiftAISDK
import AnthropicProvider
import OpenAIProvider
let customSeparatorRegistry = createProviderRegistry(
providers: [
"anthropic": anthropic,
"openai": openai
],
options: ProviderRegistryOptions(separator: " > ")
)

You can access language models by using the languageModel method on the registry. The provider id will become the prefix of the model id: providerId:modelId.

import SwiftAISDK
let result = try await generateText(
model: registry.languageModel(id: "openai:gpt-4o"), // default separator
// or with custom separator:
// model: customSeparatorRegistry.languageModel(id: "openai > gpt-4o"),
prompt: "Invent a new holiday and describe its traditions."
)

You can access text embedding models by using the textEmbeddingModel method on the registry. The provider id will become the prefix of the model id: providerId:modelId.

import SwiftAISDK
let result = try await embed(
model: .v3(registry.textEmbeddingModel(id: "openai:text-embedding-3-small")),
value: "sunny day at the beach"
)

You can access image models by using the imageModel method on the registry. The provider id will become the prefix of the model id: providerId:modelId.

import SwiftAISDK
let result = try await generateImage(
model: registry.imageModel(id: "openai:dall-e-3"),
prompt: "A beautiful sunset over a calm ocean"
)

Combining Custom Providers, Provider Registry, and Middleware

Section titled “Combining Custom Providers, Provider Registry, and Middleware”

The central idea of provider management is to set up a file that contains all the providers and models you want to use. You may want to pre-configure model settings, provide model name aliases, limit the available models, and more.

Here is an example that implements the following concepts:

  • Pass through a full provider with a namespace prefix (here: xai > *)
  • Setup model name aliases (here: anthropic > fast, anthropic > writing, anthropic > reasoning)
  • Pre-configure model settings (here: anthropic > reasoning)
  • Use a fallback provider (here: anthropic > *)
  • Limit a provider to certain models without a fallback (here: groq > gemma2-9b-it, groq > qwen-qwq-32b)
  • Define a custom separator for the provider registry (here: >)
import SwiftAISDK
import AnthropicProvider
import XAIProvider
import GroqProvider
let registry = createProviderRegistry(
providers: [
// Pass through a full provider with a namespace prefix
"xai": xai,
// Setup model name aliases
"anthropic": customProvider(
languageModels: [
"fast": anthropic.languageModel(modelId: "claude-3-haiku-20240307"),
// Simple model
"writing": anthropic.languageModel(modelId: "claude-3-7-sonnet-20250219"),
// Extended reasoning model configuration:
"reasoning": wrapLanguageModel(
model: anthropic.languageModel(modelId: "claude-3-7-sonnet-20250219"),
middleware: .single(defaultSettingsMiddleware(
settings: DefaultSettings(
maxOutputTokens: 100000, // example default setting
providerOptions: ["anthropic": [
"thinking": [
"type": "enabled",
"budgetTokens": 32000
]
]]
)
))
)
],
fallbackProvider: anthropic
),
// Limit a provider to certain models without a fallback
"groq": customProvider(
languageModels: [
"gemma2-9b-it": groq.languageModel(modelId: "gemma2-9b-it"),
"qwen-qwq-32b": groq.languageModel(modelId: "qwen-qwq-32b")
]
)
],
options: ProviderRegistryOptions(separator: " > ")
)
// Usage:
let model = registry.languageModel(id: "anthropic > reasoning")

You can apply middleware to all language models accessed through the registry:

import SwiftAISDK
import OpenAIProvider
let registry = createProviderRegistry(
providers: [
"openai": openai
],
options: ProviderRegistryOptions(
languageModelMiddleware: .single(
extractReasoningMiddleware(
options: ExtractReasoningOptions(tagName: "think")
)
)
)
)
// All language models from this registry will have reasoning extraction enabled
let result = try await generateText(
model: registry.languageModel(id: "openai:gpt-4o"),
prompt: "Think step by step and wrap reasoning in <think> tags"
)
  1. Create a central registry file - Define all providers and models in one place (e.g., Registry.swift)
  2. Use aliases for versioning - Map semantic names to specific model versions for easy updates
  3. Combine with middleware - Pre-configure models with default settings or behavior modifications
  4. Limit model access - Use custom providers without fallbacks to restrict available models
  5. Use custom separators - Choose separators that match your naming conventions (:, >, /, etc.)