Skip to main content

Azure OpenAI Provider

Azure OpenAI Service provides OpenAI-compatible models through Azure resources and deployments. In Go-AI, the deployment name is the model ID you pass to the provider.

Setup​

import (
"os"

"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/azure"
)

Set credentials:

export AZURE_API_KEY=your-key
export AZURE_RESOURCE_NAME=your-resource-name

Create a Responses model:

provider, err := azure.New(azure.Config{
APIKey: os.Getenv("AZURE_API_KEY"),
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
})
if err != nil {
log.Fatal(err)
}

model, err := provider.LanguageModel("gpt-4o-deployment")
if err != nil {
log.Fatal(err)
}

LanguageModel matches the TypeScript Azure provider default and uses the Responses API at /openai/v1/responses?api-version=v1. Use ChatModel when you need the Chat Completions endpoint or CompletionModel when you need the legacy Completions endpoint.

Microsoft Entra ID Authentication​

Use ADTokenProvider when Azure OpenAI should authenticate with Microsoft Entra ID instead of an API key. The token provider is called with the request context and sets Authorization: Bearer <token> across Responses, Chat Completions, Completions, embeddings, image, speech, and transcription request surfaces.

provider, err := azure.New(azure.Config{
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
ADTokenProvider: func(ctx context.Context) (string, error) {
return acquireToken(ctx)
},
})
if err != nil {
log.Fatal(err)
}

Passing both APIKey and ADTokenProvider returns an invalid-argument error, matching the TypeScript createAzure validation.

Responses Provider Tools​

Azure exposes the OpenAI Responses provider tools as Azure helpers:

  • azure.CodeInterpreter
  • azure.FileSearch
  • azure.ImageGeneration
  • azure.WebSearch
  • azure.WebSearchPreview

Use them with Responses-compatible Azure deployments.

searchContext := "low"
result, err := ai.StreamText(ctx, ai.StreamTextOptions{
Model: model,
Prompt: "Summarize how to upgrade AI SDK from 5 to 6.",
Tools: []types.Tool{
azure.WebSearch(openaitool.WebSearchConfig{
SearchContextSize: searchContext,
Filters: &openaitool.WebSearchFilters{
AllowedDomains: []string{"ai-sdk.dev"},
},
}),
},
})
if err != nil {
log.Fatal(err)
}
defer result.Close()

This matches the TypeScript azure.tools behavior by serializing provider-executed tools as OpenAI Responses hosted tools.

Regional And Private Endpoints​

For the standard Azure URL format, set ResourceName. For custom regional, proxy, or private-link endpoints, set BaseURL to the Azure OpenAI /openai prefix:

ResourceName is interpolated directly into the request host (https://{resourceName}.openai.azure.com/...), so New rejects a value that isn't a single DNS label (letters, digits, and hyphens, 1-63 characters, no leading/trailing hyphen) with an InvalidArgumentError before building the client — a value like user@internal:8080/# would otherwise rewrite the destination host. This only applies when BaseURL is unset; a custom BaseURL is used as-is and ResourceName is ignored.

provider, err := azure.New(azure.Config{
BaseURL: "https://your-resource-eastus.openai.azure.com/openai",
APIKey: os.Getenv("AZURE_API_KEY"),
})
if err != nil {
log.Fatal(err)
}

The default URL shape matches TypeScript: {baseURL}/v1{path}?api-version=v1. This only applies to a recognized Azure OpenAI / AI Foundry / Cognitive Services host (*.openai.azure.com, *.services.ai.azure.com, *.cognitiveservices.azure.com); a BaseURL host outside those patterns is treated as a custom gateway and used exactly as given, with no /v1 suffix or api-version query param appended — verify your proxy's URL matches one of the recognized patterns if you expect Azure's own query-string behavior.

Set UseDeploymentBasedURLs only for Azure deployments that still require {baseURL}/deployments/{deployment}{path}:

provider, err := azure.New(azure.Config{
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
APIKey: os.Getenv("AZURE_API_KEY"),
UseDeploymentBasedURLs: true,
})
if err != nil {
log.Fatal(err)
}

Other Model Types​

Azure also supports completions, embeddings, image generation, speech, and transcription through deployment names:

completionModel, err := provider.CompletionModel("gpt-35-turbo-instruct")
embeddingModel, err := provider.EmbeddingModel("text-embedding-3-small")
imageModel, err := provider.ImageModel("dall-e-3")
speechModel, err := provider.SpeechModel("tts-1")
transcriptionModel, err := provider.TranscriptionModel("whisper-1")

Azure DeepSeek deployments are available through provider.DeepSeek("deployment-name"). The model uses Azure authentication, the Azure api-version query parameter, and the "azure" provider option namespace while preserving DeepSeek reasoning-effort request behavior.

MAI-Transcribe And MAI-Voice (Azure Speech)​

provider.TranscriptionModel and provider.SpeechModel route Microsoft AI's MAI-Transcribe and MAI-Voice model families through the Azure Speech API instead of Azure OpenAI, since they use a different protocol and endpoint. Routing is automatic by model ID, and can be overridden per call with providerOptions.azure.api ("openai", "speech", or "mai"):

Model IDDefault API
mai-transcribe-2, mai-transcribe-1.5Speech (file transcription)
mai-transcribe-2-streamingMAI realtime (streaming transcription only)
mai-voice-2, mai-voice-2-flash, mai-voice-2.1, mai-voice-2.1-flashSpeech (SSML text-to-speech)
any other deployment nameOpenAI
provider, err := azure.New(azure.Config{
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
APIKey: os.Getenv("AZURE_API_KEY"),
})
if err != nil {
log.Fatal(err)
}

transcriptionModel, err := provider.TranscriptionModel("mai-transcribe-2")
if err != nil {
log.Fatal(err)
}
result, err := transcriptionModel.DoTranscribe(ctx, &provider.TranscriptionOptions{
Audio: audioBytes,
MimeType: "audio/wav",
ProviderOptions: map[string]interface{}{
"azure": map[string]interface{}{
"timestamps": "segment", // "word" | "segment" | "none"; default "segment"
"locales": []interface{}{"en"},
},
},
})

providerOptions.azure is validated strictly for both models: an unrecognized key, or an option a given MAI model doesn't support (e.g. diarization on MAI-Transcribe-1.5), returns an InvalidArgumentError instead of being silently dropped; an option that only applies to a different backend (e.g. style routed to OpenAI TTS) is reported as an unsupported warning on the result instead.

MAI-Voice speech picks a default voice from Language when Voice is unset, and accepts providerOptions.azure.style / styleDegree for Azure's mstts:express-as speaking styles:

speechModel, err := provider.SpeechModel("mai-voice-2")
result, err := speechModel.DoGenerate(ctx, &provider.SpeechGenerateOptions{
Text: "Hello from Azure.",
Language: "es", // selects es-MX-Valeria when Voice is unset
ProviderOptions: map[string]interface{}{
"azure": map[string]interface{}{"style": "excited", "styleDegree": 1.5},
},
})

MAI-Transcribe-2-Streaming only supports ai.ExperimentalStreamTranscribe (streaming transcription), over a WebSocket to the MAI realtime API; it requires 16-bit mono PCM audio at 16000 or 24000 Hz.

gpt-realtime-whisper deployments (and dated snapshots, e.g. gpt-realtime-whisper-2026-01-01) also support ai.ExperimentalStreamTranscribe, streaming over the OpenAI-compatible realtime WebSocket at your Azure resource's /realtime?intent=transcription endpoint instead of the REST transcription endpoint; DoTranscribe (non-streaming) is unsupported for these deployments, matching OpenAI's own gpt-realtime-whisper restriction.

Two optional azure.Config settings control the endpoints these models use, both defaulting from ResourceName and validated the same way as ResourceName itself (a single DNS label) before being used:

  • SpeechBaseURL — the Azure Speech endpoint prefix (default https://{ResourceName}.cognitiveservices.azure.com), used for both MAI-Transcribe file transcription and MAI-Voice speech.
  • MaiBaseURL — the MAI realtime endpoint prefix (default https://{ResourceName}.services.ai.azure.com/mai/v1), used for MAI-Transcribe-2-Streaming.
provider, err := azure.New(azure.Config{
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
APIKey: os.Getenv("AZURE_API_KEY"),
SpeechBaseURL: "https://eastus.api.cognitive.microsoft.com",
})

Custom Headers​

Use Headers for request metadata that should be sent with every provider call:

provider, err := azure.New(azure.Config{
ResourceName: os.Getenv("AZURE_RESOURCE_NAME"),
APIKey: os.Getenv("AZURE_API_KEY"),
Headers: map[string]string{
"X-Request-ID": "unique-request-id",
},
})
if err != nil {
log.Fatal(err)
}

Per-call headers can also be supplied through generation options and override provider-level headers.