# Latency Optimization for Azure OpenAI

**Last updated:** 2026-02
**Status:** GA
**Category:** Performance & Scalability

---

## Introduksjon

Latens er en av de mest kritiske ytelsesparameterne for AI-applikasjoner i produksjon. For norsk offentlig sektor, der innbyggertjenester krever rask respons og interne saksbehandlingssystemer må operere effektivt, er optimalisering av Azure OpenAI-latens avgjorende. Høy latens kan direkte påvirke brukeropplevelsen og redusere adopsjonen av AI-drevne tjenester.

Azure OpenAI-latens bestemmes av flere faktorer: modellvalg, prompt-storrelse, genereringsstorrelse, nettverksavstand til endepunktet, og hvordan applikasjonen er konfigurert. Forstaelse av disse faktorene og systematisk optimalisering av hver komponent er nodvendig for a oppna akseptabel ytelse i produksjonsmiljoer.

Denne referansen dekker de viktigste teknikkene for a redusere latens i Azure OpenAI-baserte applikasjoner, fra request pipeline-optimalisering til regional endepunktsplassering, med spesielt fokus pa norske deployments i North Europe og Sweden Central-regionene.

## Forstaelse av latenskomponenter

### Request Pipeline Breakdown

En Azure OpenAI-request traverserer flere stadier, og hvert stadium bidrar til total latens:

| Stadium | Beskrivelse | Typisk latens |
|---------|-------------|---------------|
| DNS-oppslag | Resolusjon av Azure OpenAI-endepunkt | 1-50 ms |
| TLS-handshake | Sikker forbindelse etableres | 20-100 ms |
| Nettverkstransport | Data sendes til Azure-regionen | 5-200 ms |
| Token-prosessering (input) | Prompt-tokens prosesseres | Varierer med storrelse |
| Token-generering (output) | Completion-tokens genereres sekvensielt | Storste latensbidraget |
| Content filtering | Sikkerhetsfiltrering av input/output | 10-50 ms |
| Responstransport | Svar sendes tilbake til klient | 5-200 ms |

### Latensmetrikker

For effektiv maling av latens bor du spore disse metrikkene:

**For non-streaming requests:**
- **End-to-end Request Time:** Total tid fra request sendt til komplett respons mottatt.

**For streaming requests:**
- **Time to First Token (TTFT):** Tid fra request sendt til forste token mottatt. Oker med prompt-storrelse.
- **Average Token Generation Rate:** Tid fra forste token til siste token, delt pa antall genererte tokens. Oker med systembelastning.

```python
import time
from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    api_version="2025-03-01-preview"
)

# Mal TTFT og total latens
start_time = time.perf_counter()
first_token_time = None

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hva er personopplysningsloven?"}],
    stream=True,
    max_tokens=200
)

for chunk in response:
    if first_token_time is None and chunk.choices[0].delta.content:
        first_token_time = time.perf_counter()
        ttft = first_token_time - start_time
        print(f"Time to First Token: {ttft:.3f}s")

total_time = time.perf_counter() - start_time
print(f"Total latens: {total_time:.3f}s")
```

## Request Pipeline-optimalisering

### Modellvalg for lav latens

Modellvalg har direkte innvirkning pa latens. For identiske requests varierer latens betydelig mellom modeller:

| Modell | Relativ latens | Anbefalt bruk |
|--------|---------------|----------------|
| GPT-4o mini | Lavest | Enkel klassifisering, rask sortering, chatbots |
| GPT-4o | Moderat | Generelt formalsbruk, RAG-svar |
| GPT-4.1 | Moderat-hoy | Kompleks resonnering, kodeanalyse |
| o3-mini | Hoy | Avansert resonnering med lavere tokenbruk |

**Anbefaling for norsk offentlig sektor:** Bruk GPT-4o mini for innbyggertjenester som krever rask respons (chatbots, FAQ-svar). Reserver GPT-4o og storre modeller for saksbehandlingsstotte der kvalitet er viktigere enn hastighet.

### Max Tokens-optimalisering

`max_tokens`-parameteren pavirker latens betydelig. Azure OpenAI reserverer beregningskapasitet basert pa denne verdien ved request-start:

```python
# DARLIG: For hoy max_tokens oker latens selv om faktisk output er kort
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Svar ja eller nei: Er dette en klage?"}],
    max_tokens=4096  # Reserverer kapasitet for 4096 tokens
)

# BRA: Tilpass max_tokens til forventet output-lengde
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Svar ja eller nei: Er dette en klage?"}],
    max_tokens=10  # Reserverer kun nodvendig kapasitet
)
```

**Tommelregel:** Sett `max_tokens` til 1.5x forventet output-lengde. For klassifiseringsoppgaver: 10-50 tokens. For korte svar: 100-300 tokens. For lengre generering: tilpass etter behov.

### Stop Sequences

Bruk `stop`-parameteren for a avslutte generering tidlig nar onskede data er produsert:

```python
# Stopp sa snart klassifiseringen er ferdig
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Klassifiser henvendelsen. Svar med kun: KLAGE, SPORSMAL, eller TILBAKEMELDING"},
        {"role": "user", "content": user_input}
    ],
    max_tokens=20,
    stop=["\n", "."]  # Stopp etter forste linje/setning
)
```

### Separasjon av arbeidslaster

Blanding av ulike arbeidslaster pa samme endepunkt pavirker latens negativt:

1. **Batch-interferens:** Korte og lange requests batches sammen under inferens, sa korte kall ma vente pa lange completions.
2. **Cache-konkurranise:** Ulike arbeidslaster konkurrerer om prompt cache-plass.

**Anbefalt arkitektur:**

```
Innbyggerportal (chatbot)  --> Deployment: gpt-4o-mini-chat (Standard, hoy TPM)
Saksbehandling (analyse)   --> Deployment: gpt-4o-analyse (Standard, moderat TPM)
Dokumentgenerering         --> Deployment: gpt-4o-dokument (Standard, lav TPM)
Batchprosessering          --> Deployment: gpt-4o-batch (Global Batch)
```

## Connection Pooling og gjenbruk

### HTTP Connection Reuse

Opprettelse av nye HTTP-forbindelser for hver request legger til DNS-oppslag og TLS-handshake. Gjenbruk av forbindelser eliminerer dette:

```python
from openai import AzureOpenAI
import httpx

# Opprett klient EN gang og gjenbruk
# Python SDK bruker httpx med connection pooling automatisk
client = AzureOpenAI(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    api_version="2025-03-01-preview",
    http_client=httpx.Client(
        limits=httpx.Limits(
            max_connections=100,         # Maks samtidige forbindelser
            max_keepalive_connections=20, # Hold forbindelser levende
            keepalive_expiry=30          # Sekunder for keepalive
        )
    )
)

# DARLIG: Ny klient per request
def process_request_bad(prompt):
    client = AzureOpenAI(...)  # Ny TLS-handshake hver gang
    return client.chat.completions.create(...)

# BRA: Gjenbruk eksisterende klient
def process_request_good(prompt):
    return client.chat.completions.create(  # Gjenbruker forbindelse
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}]
    )
```

### Async Connection Pooling

For hoy-throughput applikasjoner, bruk async-klienten:

```python
from openai import AsyncAzureOpenAI
import asyncio

async_client = AsyncAzureOpenAI(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    api_version="2025-03-01-preview"
)

async def process_batch(prompts: list[str]) -> list:
    """Prosesser flere requests parallelt med connection pooling."""
    tasks = [
        async_client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": p}],
            max_tokens=200
        )
        for p in prompts
    ]
    return await asyncio.gather(*tasks)

# Kjor 10 requests parallelt
results = asyncio.run(process_batch(prompts[:10]))
```

### Retry-strategi med eksponentiell backoff

Azure OpenAI SDK har innebygd retry-logikk for 429-feil (rate limiting):

```python
from openai import AzureOpenAI

# Konfigurer retry-oppforsel
client = AzureOpenAI(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    api_version="2025-03-01-preview",
    max_retries=5,     # Standard: 2
    timeout=60.0       # Standard: 10 minutter
)

# For PTU-deployments: Respekter retry-after header
# SDK gjor dette automatisk, men du kan tilpasse:
client_no_retry = AzureOpenAI(
    azure_endpoint="https://your-resource.openai.azure.com/",
    api_key="your-api-key",
    api_version="2025-03-01-preview",
    max_retries=0  # Deaktiver for a handtere selv
)
```

## Regional endepunktsvalg

### Azure-regioner for Norge

For norsk offentlig sektor er datasuverenitet og latens begge kritiske:

| Region | Latens fra Norge | Datasuverenitet | Tilgjengelige modeller |
|--------|-----------------|-----------------|----------------------|
| Sweden Central | ~10-20 ms | EU/EOS | Alle GPT-4o-modeller, PTU |
| North Europe (Irland) | ~30-50 ms | EU/EOS | De fleste modeller |
| West Europe (Nederland) | ~25-40 ms | EU/EOS | De fleste modeller |
| UK South | ~30-50 ms | Utenfor EOS | Begrenset relevans |

**Anbefaling:** Sweden Central som primaerregion for lavest latens og EU-datasuverenitet. North Europe som sekundaerregion for failover.

### Multi-region arkitektur med prioritet

For a oppna bade lav latens og hoy tilgjengelighet:

```python
# Prioritetsbasert lastbalansering med Azure API Management
# APIM-policy for smart routing:
```

```xml
<!-- Azure API Management policy for multi-region routing -->
<policies>
    <inbound>
        <set-variable name="primary-backend"
            value="https://aoai-sweden-central.openai.azure.com/" />
        <set-variable name="fallback-backend"
            value="https://aoai-north-europe.openai.azure.com/" />
    </inbound>
    <backend>
        <retry condition="@(context.Response.StatusCode == 429)"
               count="1"
               interval="0">
            <set-backend-service base-url="@((string)context.Variables["fallback-backend"])" />
            <forward-request buffer-response="false" />
        </retry>
    </backend>
</policies>
```

### Global vs. Regional Deployment Types

| Deployment Type | Databehandling | Latens | Bruksomrade |
|----------------|---------------|--------|-------------|
| Regional Standard | Kun i valgt region | Lavest | Produksjon, compliance-kritisk |
| Data Zone Standard | Innenfor EU/US-sone | Lav | Generelt, fleksibel kapasitet |
| Global Standard | Enhver Azure-region | Variabel | Hoy throughput, tolererer variasjon |
| Regional PTU | Kun i valgt region | Lavest og mest forutsigbar | Misjonskritisk, stabile laster |

## Time-to-First-Token-reduksjon

### Prompt Caching

Azure OpenAI prompt caching reduserer latens og kostnad for requests med identisk prefix:

```python
# Prompt caching aktiveres automatisk for stottede modeller
# Krav: Minimum 1024 tokens, identisk prefix

# System prompt som gjenbrukes pa tvers av requests
SYSTEM_PROMPT = """Du er en saksbehandlingsassistent for Direktoratet for digital tjenesteutvikling.
Du hjelper med a analysere og klassifisere innkommende henvendelser
relatert til forerkort, kjoretoysregistrering og veiprosjekter.

Folg disse retningslinjene:
1. Klassifiser henvendelsen i riktig kategori
2. Identifiser relevante lovhjemler
3. Foresla videre behandling
... (lang systemprompt over 1024 tokens)
"""

# Forste request: Ingen caching (cold start)
response1 = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": "Henvendelse 1..."}
    ]
)
# usage.prompt_tokens_details.cached_tokens = 0

# Etterfølgende requests: Caching aktiv (redusert latens)
response2 = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},  # Identisk prefix
        {"role": "user", "content": "Henvendelse 2..."}
    ]
)
# usage.prompt_tokens_details.cached_tokens = 1024+
```

**Viktige regler for prompt caching:**
- Minimum 1024 tokens i prompten
- De forste 1024 tokenene ma vaere identiske
- Etter forste 1024: cache hit for hver 128 identiske tokens
- Cache ryddes etter 5-10 minutter uten aktivitet, alltid innen 1 time
- Cacher deles IKKE mellom Azure-abonnementer
- Stottede modeller: GPT-4o, GPT-4o mini, o3-mini, GPT-4.1 og nyere

### Prompt-optimalisering for hastighet

| Teknikk | Beskrivelse | Latensreduksjon |
|---------|-------------|-----------------|
| Kompakt systemprompt | Fjern unodvendig tekst i systemprompt | 5-15% |
| Strukturerte input | JSON fremfor fritekst | 5-10% |
| Relevant kontekst | Kun relevante dokumenter i RAG | 10-30% |
| Token-effektive formater | Korte variabelnavn, kompakt format | 3-8% |

```python
# DARLIG: Verbose prompt
messages = [
    {"role": "system", "content": """
    Du er en hjelpesom assistent som jobber for norsk offentlig sektor.
    Nar du far et sporsmal, skal du tenke noye gjennom det og gi et
    grundig og gjennomtenkt svar som er presist og korrekt.
    Husk a vaere hoeflig og profesjonell i all kommunikasjon.
    """},
    {"role": "user", "content": f"Hele dokumentet pa 5000 ord: {document}\n\nSporsmal: Er dette en klage?"}
]

# BRA: Kompakt prompt med kun relevant kontekst
messages = [
    {"role": "system", "content": "Klassifiser henvendelse. Svar: KLAGE eller IKKE_KLAGE"},
    {"role": "user", "content": f"Sammendrag: {document_summary[:500]}\n\nKlassifiser:"}
]
```

### Content Filtering-optimalisering

Content filtering legger til latens men er kritisk for sikkerhet. For lavrisiko-bruksomrader kan man vurdere tilpassede filterpolicyer:

| Konfigurasjon | Latenspavirkning | Nar a bruke |
|--------------|-----------------|-------------|
| Standard filter (default) | +10-50 ms | Alle innbyggertjenester |
| Tilpasset filter (redusert) | +5-20 ms | Interne analyser, lav risiko |
| Asynkron filter | Minimal | Batch-prosessering |

**Merk:** I norsk offentlig sektor bor content filtering alltid vaere aktivert for innbyggerrettede tjenester. Vurder kun reduksjon for interne, kontrollerte miljoer.

## Provisioned Throughput Units (PTU) for forutsigbar latens

### Nar bruke PTU vs. Standard

PTU gir dedikert kapasitet og forutsigbar latens:

| Aspekt | Standard | PTU |
|--------|----------|-----|
| Latensgaranti | Ingen | Konsistent per-call latens |
| Throttling | 429 ved kvotegrense | 429 kun over 100% utnyttelse |
| Pris | Per token | Fast manedspris per PTU |
| Egnet for | Variabel last, utvikling | Produksjon, stabil last |

### PTU-kapasitetsplanlegging

Bruk Azure AI Foundry PTU-kalkulatoren:

1. Estimer input TPM (tokens per minutt) fra historiske data
2. Estimer output TPM fra historiske data
3. Beregn nodvendige PTUs via kalkulatoren
4. Legg til 20% buffer for trafikkvariasjon

```
PTU-utnyttelse = (PTUs forbrukt i perioden) / (PTUs deployet i perioden)

Mal: Hold utnyttelse under 80% for stabil latens
Over 100%: 429-feil returneres
```

### Hybrid PTU + Standard-arkitektur

```
Basislast (forutsigbar)  --> PTU deployment (Sweden Central)
                              |
                              | (ved 429 / overflow)
                              v
Toppbelastning           --> Standard deployment (North Europe, fallback)
```

## Overvaking og malinger

### Viktige Azure Monitor-metrikker

| Metrikk | Aggregering | Terskel |
|---------|-------------|---------|
| Azure OpenAI Requests | Count per minutt | Varsle ved >80% av kvote |
| Processed Inference Tokens | Sum per minutt | Spor mot TPM-grense |
| Provisioned-Managed Utilization V2 | Gjennomsnitt | Varsle ved >80% |
| Time to Response (streaming) | P95 | Varsle ved >2s TTFT |
| End-to-end Request Time | P95 | Varsle ved >5s |

### KQL-query for latensanalyse

```kusto
// Azure Monitor - Analyse av Azure OpenAI-latens
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Category == "RequestResponse"
| extend latency_ms = DurationMs
| summarize
    p50 = percentile(latency_ms, 50),
    p95 = percentile(latency_ms, 95),
    p99 = percentile(latency_ms, 99),
    avg_latency = avg(latency_ms),
    request_count = count()
    by bin(TimeGenerated, 5m), ModelDeploymentName_s
| order by TimeGenerated desc
```

## Sjekkliste for latensoptimalisering

| Prioritet | Tiltak | Forventet effekt |
|-----------|--------|-----------------|
| 1 | Velg riktig modell for oppgaven | 30-70% reduksjon |
| 2 | Optimaliser max_tokens | 10-30% reduksjon |
| 3 | Aktiver streaming for brukerrettede tjenester | Redusert opplevd latens |
| 4 | Gjenbruk HTTP-forbindelser | 50-100 ms per request |
| 5 | Bruk naermeste Azure-region (Sweden Central) | 10-40 ms reduksjon |
| 6 | Implementer prompt caching | 10-30% reduksjon pa input |
| 7 | Separer arbeidslaster pa egne deployments | 10-20% reduksjon |
| 8 | Vurder PTU for stabile produksjonslaster | Forutsigbar latens |

## For Cosmo

- **Latens er sammensatt:** Optimaliser hele pipelinen, ikke bare modellvalget. Max tokens, connection reuse, regionvalg og prompt caching bidrar alle.
- **Sweden Central er forstevalg** for norske deployments med lavest latens (~10-20 ms) og EU-datasuverenitet. North Europe som failover.
- **PTU for produksjon:** Nar arbeidslaster er forutsigbare og latens er kritisk, gir PTU garantert kapasitet. Hybrid PTU + Standard er kostnadseffektiv arkitektur.
- **Prompt caching er gratis ytelse:** Strukturer prompts med identisk prefix (system prompt over 1024 tokens) for automatisk caching. Ingen konfigurasjon nodvendig.
- **Separasjon av arbeidslaster:** Aldri bland chatbot-trafikk med batch-prosessering pa samme deployment. Bruk dedikerte deployments per bruksomrade.
