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.
400 lines
15 KiB
Markdown
400 lines
15 KiB
Markdown
# Agent Cost Optimization and Resource Management
|
|
|
|
**Last updated:** 2026-02
|
|
**Status:** GA
|
|
**Category:** Agent Orchestration & Automation
|
|
**Type:** reference
|
|
|
|
---
|
|
|
|
## Innhold
|
|
|
|
- [Introduksjon](#introduksjon)
|
|
- [Kjernekomponenter](#kjernekomponenter)
|
|
- [Model Selection per Task](#model-selection-per-task)
|
|
- [Token Optimization for Agents](#token-optimization-for-agents)
|
|
- [Request Deduplication](#request-deduplication)
|
|
- [Resource Pooling](#resource-pooling)
|
|
- [Cost Attribution per Agent](#cost-attribution-per-agent)
|
|
- [Foundry Control Plane Kostnadsoptimalisering](#foundry-control-plane-kostnadsoptimalisering)
|
|
- [Norsk offentlig sektor](#norsk-offentlig-sektor)
|
|
- [Beslutningsrammeverk](#beslutningsrammeverk)
|
|
- [For Cosmo](#for-cosmo)
|
|
|
|
## Introduksjon
|
|
|
|
Kostnadsoptimalisering for agentsystemer er en strategisk nødvendighet ettersom organisasjoner skalerer fra pilot til produksjon. Agenter som involverer flere LLM-kall, RAG-retrievals og verktøyinvokasjoner kan generere betydelige kostnader -- en enkelt kompleks agentforespørsel kan involvere 3-5 modellkall med totalt 5000-20000 tokens. Uten bevisst kostnadsstyring eskalerer utgiftene raskt når brukervolum øker.
|
|
|
|
Microsoft tilbyr et komplett verktøysett for agentkostnadsoptimalisering: Microsoft Foundry Control Plane med Ask AI-agenten for kostnadsanalyse, Model Router for automatisk modellvalg basert på kvalitet/kostnad, APIM som AI Gateway for token rate limiting og kostnadsallokering, og tiered deployment-modeller (Standard, Provisioned, Global). Foundry-portalen gir direkte sammenligning av modeller med hensyn til både ytelse og kostnad.
|
|
|
|
For norsk offentlig sektor er kostnadsbevissthet spesielt viktig gitt budsjettrammene i offentlige virksomheter. FinOps-prinsipper tilpasset AI -- med tagging, kostnadsallokering per enhet og budsjettvarslinger -- sikrer at AI-investeringer er sporbare og forsvarlge.
|
|
|
|
## Kjernekomponenter
|
|
|
|
| Komponent | Formål | Teknologi |
|
|
|-----------|--------|-----------|
|
|
| Model Selection | Velg kostnadseffektiv modell per oppgave | Model Router, Model Catalog |
|
|
| Token Optimization | Reduser token-forbruk | Prompt engineering, max_tokens |
|
|
| Request Deduplication | Unngå dupliserte forespørsler | Semantic caching, APIM policies |
|
|
| Resource Pooling | Del ressurser effektivt | Shared deployments, PTU |
|
|
| Cost Attribution | Spor kostnader per agent/bruker/avdeling | Azure Cost Management, tagging |
|
|
| Foundry Control Plane | Unified kostnadsovervåking | Ask AI agent, dashboards |
|
|
|
|
## Model Selection per Task
|
|
|
|
### Tiered modellstrategi
|
|
|
|
| Oppgavetype | Anbefalt modell | Kostnad/1M tokens (input) | Rasjonale |
|
|
|-------------|-----------------|---------------------------|-----------|
|
|
| Intent routing | gpt-4.1-nano | ~$0.10 | Minimal resonnering nødvendig |
|
|
| Enkel klassifisering | gpt-4o-mini | ~$0.15 | Rask, kostnadseffektiv |
|
|
| Standard agent-svar | gpt-4.1-mini | ~$0.40 | Balanse kvalitet/kostnad |
|
|
| RAG-syntetisering | gpt-4o | ~$2.50 | Krever god resonnering |
|
|
| Kompleks analyse | gpt-4.1 | ~$2.00 | Dyp resonnering |
|
|
| Evaluering (batch) | gpt-4o-mini (batch) | ~$0.075 | 50% rabatt via Batch API |
|
|
|
|
### Model Router
|
|
|
|
```python
|
|
# Microsoft Foundry Model Router for automatisk modellvalg
|
|
# Model Router velger dynamisk mellom modeller basert på oppgavekompleksitet
|
|
|
|
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"
|
|
)
|
|
|
|
# Model Router deployment ruter automatisk til gpt-4o-mini
|
|
# eller gpt-4o basert på oppgavens kompleksitet
|
|
response = client.chat.completions.create(
|
|
model="model-router", # Spesialdeployment for routing
|
|
messages=[
|
|
{"role": "system", "content": "Du er en hjelpsom assistent."},
|
|
{"role": "user", "content": query}
|
|
]
|
|
)
|
|
|
|
# Model Router sparer 30-50% på typiske workloads ved å
|
|
# rute enkle forespørsler til billigere modeller
|
|
```
|
|
|
|
### Manuell modellvalg basert på oppgave
|
|
|
|
```python
|
|
class CostAwareModelSelector:
|
|
"""Velg modell basert på oppgavens krav og budsjett"""
|
|
|
|
MODEL_COSTS = {
|
|
"gpt-4.1-nano": {"input": 0.10, "output": 0.40},
|
|
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
|
|
"gpt-4.1-mini": {"input": 0.40, "output": 1.60},
|
|
"gpt-4o": {"input": 2.50, "output": 10.00},
|
|
"gpt-4.1": {"input": 2.00, "output": 8.00},
|
|
}
|
|
|
|
def select_model(self, task: dict) -> str:
|
|
complexity = task.get("complexity", "medium")
|
|
budget_sensitive = task.get("budget_sensitive", True)
|
|
requires_reasoning = task.get("requires_reasoning", False)
|
|
|
|
if complexity == "low" or not requires_reasoning:
|
|
return "gpt-4o-mini"
|
|
if complexity == "medium" and budget_sensitive:
|
|
return "gpt-4.1-mini"
|
|
if complexity == "high" or requires_reasoning:
|
|
return "gpt-4o" if not budget_sensitive else "gpt-4.1-mini"
|
|
return "gpt-4o-mini" # Default til billigste
|
|
|
|
def estimate_cost(self, model: str,
|
|
input_tokens: int, output_tokens: int) -> float:
|
|
costs = self.MODEL_COSTS[model]
|
|
return (
|
|
(input_tokens / 1_000_000) * costs["input"] +
|
|
(output_tokens / 1_000_000) * costs["output"]
|
|
)
|
|
```
|
|
|
|
## Token Optimization for Agents
|
|
|
|
### Prompt-komprimering
|
|
|
|
```python
|
|
# Reduser system prompt størrelse uten å miste kvalitet
|
|
class PromptOptimizer:
|
|
def optimize_system_prompt(self, full_prompt: str,
|
|
max_tokens: int = 500) -> str:
|
|
"""Komprimer system prompt til essensielt innhold"""
|
|
sections = self._parse_sections(full_prompt)
|
|
prioritized = sorted(sections,
|
|
key=lambda s: s.priority, reverse=True)
|
|
|
|
optimized = []
|
|
current_tokens = 0
|
|
for section in prioritized:
|
|
section_tokens = self._count_tokens(section.text)
|
|
if current_tokens + section_tokens <= max_tokens:
|
|
optimized.append(section.text)
|
|
current_tokens += section_tokens
|
|
else:
|
|
# Komprimer seksjonen
|
|
compressed = self._compress_section(
|
|
section.text,
|
|
max_tokens - current_tokens
|
|
)
|
|
optimized.append(compressed)
|
|
break
|
|
|
|
return "\n".join(optimized)
|
|
|
|
def optimize_context_window(self, messages: list,
|
|
max_context_tokens: int) -> list:
|
|
"""Trim samtalehistorikk for å holde seg under token-grensen"""
|
|
total_tokens = sum(
|
|
self._count_tokens(m["content"]) for m in messages
|
|
)
|
|
|
|
if total_tokens <= max_context_tokens:
|
|
return messages
|
|
|
|
# Behold system message og siste N meldinger
|
|
system_msg = messages[0]
|
|
recent = messages[-4:] # Siste 2 turnarounds
|
|
|
|
# Komprimer mellomliggende meldinger til sammendrag
|
|
middle = messages[1:-4]
|
|
if middle:
|
|
summary = self._summarize_messages(middle)
|
|
return [system_msg,
|
|
{"role": "system", "content": f"Samtalesammendrag: {summary}"},
|
|
*recent]
|
|
|
|
return [system_msg, *recent]
|
|
```
|
|
|
|
### Max tokens-optimalisering
|
|
|
|
```python
|
|
# Sett max_tokens tilpasset oppgaven
|
|
TASK_TOKEN_LIMITS = {
|
|
"classification": 50, # Én label
|
|
"yes_no": 10, # Ja/nei
|
|
"short_answer": 200, # Kort svar
|
|
"detailed_answer": 500, # Detaljert svar
|
|
"analysis": 1000, # Dybdeanalyse
|
|
"code_generation": 2000, # Kode
|
|
}
|
|
|
|
def get_optimal_max_tokens(task_type: str) -> int:
|
|
return TASK_TOKEN_LIMITS.get(task_type, 500)
|
|
```
|
|
|
|
## Request Deduplication
|
|
|
|
### APIM-basert deduplication
|
|
|
|
```xml
|
|
<!-- Azure API Management policy for request deduplication -->
|
|
<policies>
|
|
<inbound>
|
|
<!-- Generer cache-nøkkel basert på request body -->
|
|
<set-variable name="cacheKey"
|
|
value="@{
|
|
var body = context.Request.Body.As<string>(true);
|
|
var hash = System.Security.Cryptography.SHA256.Create()
|
|
.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body));
|
|
return Convert.ToBase64String(hash);
|
|
}" />
|
|
|
|
<!-- Sjekk om identisk forespørsel nylig ble prosessert -->
|
|
<cache-lookup-value
|
|
key="@((string)context.Variables["cacheKey"])"
|
|
variable-name="cachedResponse" />
|
|
|
|
<choose>
|
|
<when condition="@(context.Variables.ContainsKey("cachedResponse"))">
|
|
<return-response>
|
|
<set-status code="200" />
|
|
<set-body>@((string)context.Variables["cachedResponse"])</set-body>
|
|
</return-response>
|
|
</when>
|
|
</choose>
|
|
</inbound>
|
|
<outbound>
|
|
<!-- Cache responsen for 5 minutter -->
|
|
<cache-store-value
|
|
key="@((string)context.Variables["cacheKey"])"
|
|
value="@(context.Response.Body.As<string>(true))"
|
|
duration="300" />
|
|
</outbound>
|
|
</policies>
|
|
```
|
|
|
|
## Resource Pooling
|
|
|
|
### Provisioned Throughput Units (PTU)
|
|
|
|
```python
|
|
# PTU vs. Standard deployment kostnadssammenligning
|
|
class DeploymentCostCalculator:
|
|
def compare_deployment_types(
|
|
self,
|
|
daily_requests: int,
|
|
avg_input_tokens: int,
|
|
avg_output_tokens: int,
|
|
model: str = "gpt-4o"
|
|
) -> dict:
|
|
# Standard (pay-per-token)
|
|
daily_input_cost = (daily_requests * avg_input_tokens / 1_000_000) * 2.50
|
|
daily_output_cost = (daily_requests * avg_output_tokens / 1_000_000) * 10.00
|
|
standard_monthly = (daily_input_cost + daily_output_cost) * 30
|
|
|
|
# PTU (fast pris per enhet)
|
|
# 1 PTU ~= 6 RPM for gpt-4o (avhenger av workload)
|
|
required_ptu = max(1, daily_requests / (6 * 60 * 24))
|
|
ptu_monthly = required_ptu * 2.00 * 24 * 30 # $2/PTU/time
|
|
|
|
return {
|
|
"standard_monthly_usd": round(standard_monthly, 2),
|
|
"ptu_monthly_usd": round(ptu_monthly, 2),
|
|
"recommendation": "PTU" if ptu_monthly < standard_monthly
|
|
else "Standard",
|
|
"savings_percent": round(
|
|
abs(standard_monthly - ptu_monthly) /
|
|
max(standard_monthly, 1) * 100, 1
|
|
)
|
|
}
|
|
```
|
|
|
|
## Cost Attribution per Agent
|
|
|
|
### Tagging-strategi
|
|
|
|
```python
|
|
# Kostnadsattribusjon med Azure resource tags og custom telemetry
|
|
class AgentCostTracker:
|
|
def __init__(self, app_insights_client):
|
|
self.client = app_insights_client
|
|
|
|
def track_agent_cost(
|
|
self,
|
|
agent_name: str,
|
|
department: str,
|
|
model: str,
|
|
input_tokens: int,
|
|
output_tokens: int,
|
|
cost_usd: float
|
|
):
|
|
self.client.track_event(
|
|
"agent_cost",
|
|
properties={
|
|
"agent_name": agent_name,
|
|
"department": department,
|
|
"model": model,
|
|
"cost_center": f"AI-{department}",
|
|
},
|
|
measurements={
|
|
"input_tokens": input_tokens,
|
|
"output_tokens": output_tokens,
|
|
"cost_usd": cost_usd,
|
|
"cost_nok": cost_usd * 11.0 # Omtrentlig kurs
|
|
}
|
|
)
|
|
```
|
|
|
|
### KQL for kostnadsrapportering
|
|
|
|
```kql
|
|
// Månedlig kostnad per agent og avdeling
|
|
customEvents
|
|
| where timestamp > ago(30d)
|
|
| where name == "agent_cost"
|
|
| extend
|
|
agent = tostring(customDimensions.agent_name),
|
|
department = tostring(customDimensions.department),
|
|
model = tostring(customDimensions.model),
|
|
cost_nok = todouble(customMeasurements.cost_nok),
|
|
tokens = todouble(customMeasurements.input_tokens)
|
|
+ todouble(customMeasurements.output_tokens)
|
|
| summarize
|
|
total_cost_nok = sum(cost_nok),
|
|
total_tokens = sum(tokens),
|
|
request_count = count(),
|
|
cost_per_request_nok = sum(cost_nok) / count()
|
|
by agent, department, model
|
|
| order by total_cost_nok desc
|
|
```
|
|
|
|
## Foundry Control Plane Kostnadsoptimalisering
|
|
|
|
Microsoft Foundry Control Plane tilbyr innebygd kostnadsanalyse:
|
|
|
|
```
|
|
Ask AI agent dialog-eksempler:
|
|
|
|
1. "Oppsummer min nylige kostnadstrend"
|
|
→ Identifiserer kostnadsdrivere og trender
|
|
|
|
2. "Hvilke agenter bidrar mest til kostnadsøkningen?"
|
|
→ Breakdown per agent med token-bruk
|
|
|
|
3. "Anbefal en billigere modell med lignende ytelse"
|
|
→ Sammenligner modeller i katalogen
|
|
|
|
4. "Evaluer ytelsesforskjellen mellom gpt-4o og gpt-4o-mini"
|
|
→ Kjører sammenlignende evaluering
|
|
|
|
5. "Vis meg oppsummering av siste data for kostnad"
|
|
→ Kontinuerlig forbedring etter modellbytte
|
|
```
|
|
|
|
## Norsk offentlig sektor
|
|
|
|
| Aspekt | Krav | Implementering |
|
|
|--------|------|----------------|
|
|
| Budsjettkontroll | Statsbudsjettet, rammefinansiering | Månedlige budsjettvarslinger per avdeling |
|
|
| Gevinstrealisering | DFDs gevinstmetodikk | Spor kostnad vs. tidsbesparelse per agent |
|
|
| Anskaffelse | Anskaffelsesloven | Rammeavtale for Azure-tjenester |
|
|
| Rapportering | Årsmelding, tildelingsbrev | Kvartalsvis AI-kostnadsrapport |
|
|
| Rettferdighet | Likebehandling | Lik tilgang til AI-verktøy på tvers av enheter |
|
|
|
|
### Budsjettvarslinger
|
|
|
|
```python
|
|
# Azure Monitor budget alerts for AI-kostnader
|
|
budget_alert_config = {
|
|
"name": "ai-agent-monthly-budget",
|
|
"amount": 50000, # NOK
|
|
"time_grain": "Monthly",
|
|
"notifications": [
|
|
{"threshold": 50, "contact_emails": ["ai-ops@virksomhet.no"]},
|
|
{"threshold": 80, "contact_emails": [
|
|
"ai-ops@virksomhet.no", "leder@virksomhet.no"
|
|
]},
|
|
{"threshold": 100, "contact_emails": [
|
|
"ai-ops@virksomhet.no", "leder@virksomhet.no",
|
|
"okonomi@virksomhet.no"
|
|
]}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Beslutningsrammeverk
|
|
|
|
| Scenario | Anbefaling | Begrunnelse |
|
|
|----------|------------|-------------|
|
|
| Ny agent, usikker bruk | Standard deployment + gpt-4o-mini | Lav risiko, betal per bruk |
|
|
| Stabil workload > 100K req/dag | PTU deployment | Forutsigbar kostnad, bedre ytelse |
|
|
| Mange lignende forespørsler | Semantic caching + APIM | Eliminer dupliserte LLM-kall |
|
|
| Budsjettsensitiv organisasjon | Model Router + strenge token-grenser | Automatisk kostnadsoptimalisering |
|
|
| Multi-avdelings deployment | Cost attribution med tagging | Sporbar kostnadsfordeling |
|
|
|
|
## For Cosmo
|
|
|
|
- **Model tiering er den viktigste optimaliseringen** -- bruk gpt-4.1-nano/mini for routing og klassifisering, og reserver gpt-4o for kompleks resonnering. Typisk 30-50% kostnadsreduksjon.
|
|
- **Model Router** i Microsoft Foundry er det enkleste tiltaket -- det ruter automatisk enkle forespørsler til billigere modeller uten kodeendringer.
|
|
- **Token-optimalisering** gjennom komprimerte system prompts og riktige max_tokens-verdier har kumulativ effekt -- 20% tokenreduksjon over millioner av kall er betydelig.
|
|
- **Cost attribution med Azure tags** er obligatorisk for offentlig sektor -- spor kostnad per agent, per avdeling, per bruksområde for budsjettering og gevinstrealisering.
|
|
- **PTU-deployment** lønner seg typisk ved > 50K forespørsler/dag med stabil trafikk -- under dette er Standard med pay-per-token mer kostnadseffektivt.
|