Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/ infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk (fra første ## seksjon), advisor urørt (0 endringer). To applier-fixes oppdaget under kjøring (TDD, RED→GREEN): - insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer 500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor scan-vinduet, applierens post-write-assertion fanget + restaurerte). - normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i 500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent utvidelse av carve-out; kun stray metadata-linjer, aldri prosa. test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet (fila bærer nå Source). Suite 728/728 grønn.
14 KiB
Agent Latency Optimization and Performance Tuning
Last updated: 2026-02 Status: GA Category: Agent Orchestration & Automation Type: reference
Innhold
- Introduksjon
- Kjernekomponenter
- Latency-anatomi for agentsystemer
- Response Streaming
- Request Batching
- Prefetching Strategies
- Semantic Caching med APIM
- Async-Awaitable Patterns
- Model Selection for Latency
- Norsk offentlig sektor
- Beslutningsrammeverk
- For Cosmo
Introduksjon
Responstid er en kritisk kvalitetsfaktor for AI-agenter. Brukere forventer sub-sekund initial respons og fullstendige svar innen få sekunder. I multi-agent-systemer akkumuleres latency gjennom hver orkestreringsbeslutning, modellkall, verktøyinvokasjon og data-retrieval. Uten bevisst optimalisering kan en agent som involverer 3-4 LLM-kall raskt nå 15-30 sekunders total responstid, noe som er uakseptabelt for interaktive scenarier.
Azure OpenAI tilbyr flere mekanismer for latency-optimalisering: modellvalg (GPT-4o mini for lavest latency), streaming for opplevd rask respons, prompt-caching for gjentatte forespørsler, og batching for asynkrone workloads. I tillegg gir Azure API Management som AI Gateway mulighet for intelligent routing, semantic caching og request-deduplication.
For agentsystemer spesifikt er de største latency-driverne antall sekvensielle LLM-kall, størrelsen på kontekstvinduer, og ventetid på eksterne verktøy. Parallellisering av uavhengige operasjoner, prefetching av sannsynlige data-behov, og async-patterns for verktøybruk er de mest effektive optimaliseringene.
Kjernekomponenter
| Komponent | Formål | Teknologi |
|---|---|---|
| Streaming | Reduser opplevd latency | Azure OpenAI streaming, SSE |
| Prompt Caching | Reduser time-to-first-token for gjentatte prefixer | Azure OpenAI prompt caching |
| Request Batching | Samle bulk-operasjoner | Azure OpenAI Batch API |
| Semantic Caching | Cache semantisk like forespørsler | APIM semantic caching policy |
| Model Selection | Velg riktig modell for oppgavens krav | GPT-4o mini, GPT-4o, Model Router |
| Async Patterns | Parallelliser uavhengige operasjoner | C# async/await, Python asyncio |
Latency-anatomi for agentsystemer
Typisk breakdown
┌─────────────────────────────────────────────────────┐
│ Total agent response: ~8-15 sekunder (uten opt.) │
│ │
│ Router LLM-kall: ~0.5-1.5s │
│ RAG retrieval: ~0.3-1.0s │
│ Specialist LLM-kall: ~2-5s │
│ Tool invocation (API): ~0.5-3s │
│ Response formatting: ~0.5-1.5s │
│ Content filtering: ~0.1-0.3s │
│ │
│ Etter optimalisering: ~2-5 sekunder │
└─────────────────────────────────────────────────────┘
Latency-metrikker
| Metrikk | Beskrivelse | Måling |
|---|---|---|
| Time to First Token (TTFT) | Tid til første token i streamed respons | Azure Monitor, streaming |
| End-to-End Request Time | Total tid for komplett respons | API Gateway metrics |
| Token Generation Rate | Tokens per sekund under generering | Calculated metric |
| Tool Call Latency | Tid brukt på verktøyinvokasjoner | Custom spans |
| Orchestration Overhead | Tid brukt i routing/orkestrering | Custom spans |
Response Streaming
Implementering med Semantic Kernel
// Streaming reduserer opplevd latency dramatisk
public async IAsyncEnumerable<string> StreamAgentResponse(
ChatCompletionAgent agent,
string userMessage,
AgentThread thread)
{
var message = new ChatMessageContent(
AuthorRole.User, userMessage);
await foreach (var chunk in
agent.InvokeStreamingAsync(message, thread))
{
if (!string.IsNullOrEmpty(chunk.Content))
{
yield return chunk.Content;
}
}
}
// Bruk med SignalR for web-klienter
public class AgentHub : Hub
{
public async Task SendMessage(string query)
{
await foreach (var token in
_orchestrator.StreamAgentResponse(query))
{
await Clients.Caller.SendAsync("ReceiveToken", token);
}
await Clients.Caller.SendAsync("ResponseComplete");
}
}
Streaming med Azure OpenAI direkte
import asyncio
from openai import AsyncAzureOpenAI
client = AsyncAzureOpenAI(
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
api_key=os.environ["AZURE_OPENAI_KEY"],
api_version="2024-12-01-preview"
)
async def stream_response(messages: list):
stream = await client.chat.completions.create(
model="gpt-4o",
messages=messages,
stream=True,
# Optimaliseringer
max_tokens=500, # Begrens generering
temperature=0.3, # Lavere = raskere konvergens
)
async for chunk in stream:
if chunk.choices[0].delta.content:
yield chunk.choices[0].delta.content
Request Batching
Azure OpenAI Batch API
For ikke-interaktive workloads tilbyr Batch API 50% kostnadsreduksjon og høyere throughput:
# Batch API for bulk-operasjoner (24-timers SLA)
import json
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
api_key=os.environ["AZURE_OPENAI_KEY"],
api_version="2024-12-01-preview"
)
# Opprett batch-fil med JSONL
batch_requests = []
for i, query in enumerate(evaluation_queries):
batch_requests.append({
"custom_id": f"eval-{i}",
"method": "POST",
"url": "/chat/completions",
"body": {
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "Evaluer følgende..."},
{"role": "user", "content": query}
],
"max_tokens": 200
}
})
# Skriv JSONL-fil
with open("batch_input.jsonl", "w") as f:
for req in batch_requests:
f.write(json.dumps(req) + "\n")
# Last opp og start batch
file = client.files.create(
file=open("batch_input.jsonl", "rb"),
purpose="batch"
)
batch = client.batches.create(
input_file_id=file.id,
endpoint="/chat/completions",
completion_window="24h"
)
Prefetching Strategies
Proaktiv data-henting
import asyncio
class PrefetchingOrchestrator:
"""Parallelliser data-henting med LLM-klassifisering"""
async def process_query(self, query: str) -> str:
# Start routing og data-henting PARALLELT
routing_task = asyncio.create_task(
self.classify_intent(query)
)
# Prefetch de mest sannsynlige datakildene
common_data_task = asyncio.create_task(
self.fetch_common_context(query)
)
# Vent på routing-resultat
routing = await routing_task
common_data = await common_data_task
# Hent spesialisert data basert på routing
specialized_data = await self.fetch_specialized_data(
routing.target_agent, query
)
# Kombiner kontekst og generer svar
context = {**common_data, **specialized_data}
return await self.generate_response(
routing.target_agent, query, context
)
async def fetch_common_context(self, query: str) -> dict:
"""Hent data som sannsynligvis trengs uansett agent"""
user_profile, recent_history = await asyncio.gather(
self.get_user_profile(),
self.get_recent_interactions(limit=3)
)
return {
"user_profile": user_profile,
"recent_history": recent_history
}
Semantic Caching med APIM
APIM Semantic Cache Policy
<!-- Azure API Management semantic caching for AI-forespørsler -->
<policies>
<inbound>
<!-- Sjekk semantic cache før videresending -->
<azure-openai-semantic-cache-lookup
score-threshold="0.90"
embeddings-backend-id="embedding-backend"
embeddings-backend-auth="system-assigned" />
</inbound>
<outbound>
<!-- Lagre respons i cache for fremtidige like forespørsler -->
<azure-openai-semantic-cache-store
duration="3600" />
</outbound>
</policies>
Cache-invalidering
class AgentCacheManager:
"""Håndter cache-invalidering for agent-systemer"""
def __init__(self, redis_client):
self.redis = redis_client
async def cache_response(
self, query_embedding: list, response: str, ttl: int = 3600
):
key = self._embedding_to_key(query_embedding)
await self.redis.setex(key, ttl, response)
async def invalidate_on_knowledge_update(
self, updated_sources: list
):
"""Når kunnskapsbase oppdateres, invalider relaterte cacher"""
# Fjern alle cache-entries som refererer til oppdaterte kilder
for source in updated_sources:
pattern = f"agent_cache:*:{source}:*"
keys = await self.redis.keys(pattern)
if keys:
await self.redis.delete(*keys)
async def invalidate_on_model_change(self):
"""Ved modellbytte, flush hele cachen"""
await self.redis.flushdb()
Async-Awaitable Patterns
Parallell verktøyinvokasjon
// Parallelliser uavhengige tool calls
public class OptimizedAgentToolHandler
{
public async Task<ToolResults> ExecuteToolsParallel(
IEnumerable<ToolCall> toolCalls)
{
// Grupper verktøykall etter avhengigheter
var independentCalls = toolCalls
.Where(t => !t.HasDependencies)
.ToList();
var dependentCalls = toolCalls
.Where(t => t.HasDependencies)
.ToList();
// Kjør uavhengige kall parallelt
var parallelResults = await Task.WhenAll(
independentCalls.Select(tool =>
ExecuteToolWithTimeout(tool, TimeSpan.FromSeconds(5))
)
);
// Kjør avhengige kall sekvensielt
var sequentialResults = new List<ToolResult>();
foreach (var tool in dependentCalls)
{
var result = await ExecuteToolWithTimeout(
tool, TimeSpan.FromSeconds(5));
sequentialResults.Add(result);
}
return new ToolResults(parallelResults, sequentialResults);
}
private async Task<ToolResult> ExecuteToolWithTimeout(
ToolCall tool, TimeSpan timeout)
{
using var cts = new CancellationTokenSource(timeout);
try
{
return await tool.ExecuteAsync(cts.Token);
}
catch (OperationCanceledException)
{
return ToolResult.Timeout(tool.Name);
}
}
}
Model Selection for Latency
Modell-latency sammenligning
| Modell | TTFT (median) | Tokens/sek | Anbefalt bruk |
|---|---|---|---|
| gpt-4o-mini | ~200ms | ~120 | Routing, klassifisering, enkle svar |
| gpt-4o | ~400ms | ~80 | Komplekse resonneringer, RAG |
| gpt-4.1 | ~350ms | ~90 | Generell agent-bruk |
| gpt-4.1-mini | ~180ms | ~130 | Høyvolum, lav-latency |
| gpt-4.1-nano | ~100ms | ~150 | Ultra-lav latency, enkel klassifisering |
Tiered Model Strategy
# Velg modell basert på oppgavens kompleksitet
MODEL_TIERS = {
"routing": "gpt-4.1-nano", # Ultra-rask routing
"simple_qa": "gpt-4o-mini", # Enkle spørsmål
"rag_synthesis": "gpt-4o", # RAG med resonnering
"complex_analysis": "gpt-4.1", # Dype analyser
"evaluation": "gpt-4o-mini", # Batch-evaluering
}
async def select_model_for_task(task_type: str, context: dict) -> str:
base_model = MODEL_TIERS.get(task_type, "gpt-4o-mini")
# Override basert på kontekst
if context.get("token_count", 0) > 4000:
# Store kontekster trenger kraftigere modell
return "gpt-4o"
if context.get("requires_reasoning", False):
return "gpt-4.1"
return base_model
Norsk offentlig sektor
| Aspekt | Krav | Latency-implikasjon |
|---|---|---|
| Data residency | Azure Norway East | +20-50ms vs. West Europe |
| Content filtering | Obligatorisk for offentlig sektor | +100-200ms per request |
| Audit logging | Full logging av alle kall | +10-30ms overhead |
| VNet isolation | Private endpoints | +5-15ms for DNS resolution |
| Token-grenser | Budget-begrensninger | Bruk mindre modeller der mulig |
Beslutningsrammeverk
| Scenario | Anbefaling | Begrunnelse |
|---|---|---|
| Chat-bot med < 2s krav | Streaming + gpt-4o-mini + semantic cache | Lavest opplevd latency |
| Multi-agent med 3+ steg | Parallelliser uavhengige steg + prefetching | Reduserer sekvensielle ventetider |
| Høy-volum asynkront | Batch API + gpt-4o-mini | 50% kostnadsreduksjon, 24h SLA |
| RAG med store dokumenter | Prompt caching + chunk-optimalisering | Reduser TTFT for store prompts |
| Global distribusjon | APIM multi-region + Front Door | Nearest-region routing |
For Cosmo
- Streaming er alltid-på for interaktive agenter -- det er den enkelttiltaket som mest forbedrer brukeropplevelsen, selv om total tid forblir lik.
- Model tiering er obligatorisk for kostnadseffektiv latency-optimalisering -- bruk nano/mini for routing og klassifisering, gpt-4o for kompleks resonnering.
- Parallelliser aggressivt: Prefetch data mens routing pågår, kjør uavhengige verktøykall parallelt, og bruk async/await konsekvent.
- Semantic caching i APIM gir dramatisk forbedring for repetitive forespørsler -- spesielt i kundestøtte-scenarier der mange brukere stiller lignende spørsmål.
- Mål alltid TTFT og total latency separat -- TTFT driver brukeropplevelse, total latency driver kostnad. Optimaliser begge men prioriter TTFT for interaktive scenarier.