ms-ai-architect/skills/ms-ai-governance/references/monitoring-observability/application-insights-llm-monitoring.md

818 lines
24 KiB
Markdown

# Application Insights for LLM Monitoring
**Category:** Monitoring & Observability
**Last updated:** 2026-02-05
**Status:** Komplett
**Type:** reference
## Innhold
- [Oversikt](#oversikt)
- [Hvorfor Application Insights for LLM-applikasjoner?](#hvorfor-application-insights-for-llm-applikasjoner)
- [LLM-spesifikk telemetri i Application Insights](#llm-spesifikk-telemetri-i-application-insights)
- [Custom Events for AI-interaksjoner](#custom-events-for-ai-interaksjoner)
- [Distributed Tracing for AI Pipelines](#distributed-tracing-for-ai-pipelines)
- [Performance Baselines for LLMs](#performance-baselines-for-llms)
- [Error Tracking og Alerting](#error-tracking-og-alerting)
- [Framework-integrasjoner](#framework-integrasjoner)
- [Lokal debugging med Aspire Dashboard](#lokal-debugging-med-aspire-dashboard)
- [Best Practices](#best-practices)
- [Visualisering i Azure Portal](#visualisering-i-azure-portal)
- [For Cosmo Skyberg: Application Insights for LLM Monitoring](#for-cosmo-skyberg-application-insights-for-llm-monitoring)
## Oversikt
Application Insights er Azures native observability-plattform for å overvåke LLM-applikasjoner med OpenTelemetry-kompatibel tracing. Denne guiden dekker LLM-spesifikk telemetri, custom events for AI-interaksjoner, distributed tracing for AI-pipelines, performance baselines, og error tracking.
Application Insights integrerer sømløst med Microsoft Foundry, Azure OpenAI Service, og alle større AI-rammeverk (LangChain, Semantic Kernel, Microsoft Agent Framework, OpenAI Agents SDK).
## Hvorfor Application Insights for LLM-applikasjoner?
### Utfordringer med LLM-observabilitet
LLM-applikasjoner introduserer unike overvåkingsutfordringer:
1. **Komplekse kjeder** — Agent kan kjøre 10+ steg med nøstede tool calls
2. **Varierende flows** — Execution path avhenger av user input og model reasoning
3. **Lange inputs/outputs** — Prompts og responses kan være 1000+ tokens
4. **Multi-agent orchestration** — Koordinering mellom flere agenter og tools
5. **Kostnadskontroll** — Token usage og latency må spores per operasjon
### Application Insights løsning
- **OpenTelemetry-standard** — Følger GenAI semantic conventions
- **Full trace tree** — Se nøstede spans for agent → tool → LLM calls
- **Token tracking** — Custom metrics for input/output tokens og cost
- **Performance baselines** — P50, P90, P95 latency per operasjon
- **Error correlation** — Link exceptions til spesifikk LLM call eller tool
- **Multi-framework** — Samme backend for LangChain, Semantic Kernel, etc.
## LLM-spesifikk telemetri i Application Insights
### Telemetri-typer for AI-applikasjoner
Application Insights lagrer LLM-telemetri i standardtabeller:
| Telemetri | Tabell | Bruk for LLM-applikasjoner |
|-----------|--------|----------------------------|
| **Request** | `AppRequests` | HTTP request til AI endpoint (chat completion, agent run) |
| **Dependency** | `AppDependencies` | Kall til Azure OpenAI, embeddings API, vector database |
| **Trace** | `AppTraces` | Agent reasoning steps, tool outputs, system messages |
| **Exception** | `AppExceptions` | Model errors (rate limit, content filter), tool failures |
| **Custom Event** | `AppEvents` | User feedback, agent decisions, evaluation results |
| **Custom Metric** | `AppMetrics` | Token count, cost per request, embedding dimensions |
### OpenTelemetry Spans for GenAI
Application Insights støtter OpenTelemetry Semantic Conventions for GenAI:
**Standard span-attributter:**
```json
{
"gen_ai.system": "azure_openai",
"gen_ai.request.model": "gpt-4o",
"gen_ai.request.max_tokens": 1000,
"gen_ai.request.temperature": 0.7,
"gen_ai.response.finish_reason": "stop",
"gen_ai.usage.input_tokens": 450,
"gen_ai.usage.output_tokens": 320,
"gen_ai.prompt": "[redacted]", // hvis content recording er enabled
"gen_ai.completion": "[redacted]"
}
```
**Multi-agent spans (Microsoft-utvidelse):**
| Span type | Attributt | Beskrivelse |
|-----------|-----------|-------------|
| `execute_task` | — | Task planning og event propagation |
| `invoke_agent` | `agent.name`, `agent.id` | Agent invocation |
| `agent_to_agent_interaction` | `source_agent`, `target_agent` | Inter-agent kommunikasjon |
| `agent.state.management` | `memory_type` | Memory og context management |
| `agent_planning` | `plan_steps` | Agent's internal planning |
| `execute_tool` | `tool.name`, `tool.call.arguments`, `tool.call.results` | Tool execution |
| `gen_ai.evaluation` | `evaluation.name`, `evaluation.score` | Agent performance evaluation |
## Custom Events for AI-interaksjoner
### Logg user feedback
User feedback er kritisk for å evaluere LLM-output kvalitet:
```python
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
tracer = trace.get_tracer(__name__)
def log_user_feedback(response_id: str, rating: int, comment: str):
"""Log user feedback som OpenTelemetry event."""
with tracer.start_as_current_span("user_feedback") as span:
span.set_attribute("gen_ai.response.id", response_id)
span.set_attribute("user_feedback.rating", rating)
span.set_attribute("user_feedback.comment", comment)
# Link til parent span (LLM response)
span.set_attribute("parent_span_id", get_response_span_id(response_id))
```
**Query i Application Insights:**
```kusto
AppTraces
| where OperationName == "user_feedback"
| extend Rating = tolong(Properties.user_feedback_rating)
| summarize AvgRating = avg(Rating), Count = count() by bin(TimeGenerated, 1h)
```
### Agent decisions som events
Logg agent decisions for å forstå reasoning:
```python
def log_agent_decision(agent_name: str, decision: str, reasoning: str):
"""Log agent decision point."""
with tracer.start_as_current_span("agent_decision") as span:
span.set_attribute("agent.name", agent_name)
span.set_attribute("agent.decision", decision)
span.set_attribute("agent.reasoning", reasoning)
span.set_attribute("timestamp", datetime.utcnow().isoformat())
```
### Tool invocation tracking
Track tool usage patterns:
```python
def track_tool_usage(tool_name: str, success: bool, latency_ms: float):
"""Track tool execution metrics."""
with tracer.start_as_current_span(f"tool_{tool_name}") as span:
span.set_attribute("tool.name", tool_name)
span.set_attribute("tool.success", success)
span.set_attribute("tool.latency_ms", latency_ms)
if not success:
span.set_status(Status(StatusCode.ERROR))
```
## Distributed Tracing for AI Pipelines
### Trace hele agent execution
Application Insights viser full trace tree for agent execution:
```
[Request] POST /chat/completions (2.3s)
├─ [Span] agent_session (2.2s)
│ ├─ [Span] agent_planning (0.1s)
│ ├─ [Span] execute_task (2.0s)
│ │ ├─ [Span] invoke_agent: ResearchAgent (1.2s)
│ │ │ ├─ [Dependency] Azure OpenAI gpt-4o (0.8s)
│ │ │ └─ [Span] execute_tool: web_search (0.4s)
│ │ │ └─ [Dependency] Bing Search API (0.35s)
│ │ └─ [Span] invoke_agent: SummaryAgent (0.7s)
│ │ └─ [Dependency] Azure OpenAI gpt-4o-mini (0.6s)
│ └─ [Span] agent.state.management (0.1s)
└─ [Custom Event] user_feedback (rating: 5)
```
### Correlation IDs
Application Insights bruker W3C Trace Context for correlation:
- `operation_Id` — Unique ID for hele request (trace-id)
- `operation_ParentId` — Parent span ID (parent-id)
- `id` — Current span ID
**Query relaterte spans:**
```kusto
AppRequests
| where OperationId == "abc123..."
| union (AppDependencies | where OperationId == "abc123...")
| union (AppTraces | where OperationId == "abc123...")
| order by TimeGenerated asc
```
### Instrumentering med Microsoft Foundry SDK
**Python setup:**
```python
from azure.ai.projects import AIProjectClient
from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry import trace
# Connect til AI Foundry project
project_client = AIProjectClient(
credential=DefaultAzureCredential(),
endpoint=os.environ["PROJECT_ENDPOINT"]
)
# Hent Application Insights connection string
connection_string = project_client.telemetry.get_application_insights_connection_string()
# Enable Azure Monitor tracing
configure_azure_monitor(connection_string=connection_string)
# Get tracer
tracer = trace.get_tracer(__name__)
# Trace agent execution
with tracer.start_as_current_span("my_agent_flow"):
agent = project_client.agents.create_agent(...)
run = project_client.agents.runs.create_and_process(...)
```
### Content recording (opt-in)
For å trace prompt/completion content (kan inneholde persondata):
```python
import os
os.environ["AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED"] = "true"
```
**Alternativt via miljøvariabel:**
```bash
# PowerShell
$env:AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED = "true"
# Bash
export AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED=true
```
⚠️ **Sikkerhet:** Content recording logger prompts og responses. Vurder GDPR/privacy før aktivering.
## Performance Baselines for LLMs
### Definere baselines
LLM-applikasjoner har annen performance-profil enn tradisjonelle APIs:
| Metric | Baseline (gpt-4o) | Baseline (gpt-4o-mini) |
|--------|-------------------|------------------------|
| **Latency P50** | 1.2s | 0.6s |
| **Latency P95** | 3.5s | 1.8s |
| **Tokens/sec (output)** | 40-60 | 80-120 |
| **Time to first token** | 0.3s | 0.2s |
| **Tool call overhead** | +0.5s per tool | +0.3s per tool |
### Custom metrics for LLM performance
**Track token usage:**
```python
from opentelemetry import metrics
meter = metrics.get_meter(__name__)
# Create metrics
input_tokens = meter.create_counter(
"gen_ai.input_tokens",
description="Total input tokens consumed",
unit="tokens"
)
output_tokens = meter.create_counter(
"gen_ai.output_tokens",
description="Total output tokens generated",
unit="tokens"
)
cost_metric = meter.create_counter(
"gen_ai.cost_usd",
description="Estimated cost in USD",
unit="USD"
)
# Log metrics
def track_llm_call(model: str, input_tokens: int, output_tokens: int):
input_tokens.add(input_tokens, {"model": model})
output_tokens.add(output_tokens, {"model": model})
# Calculate cost (example rates)
cost = (input_tokens * 0.000005) + (output_tokens * 0.000015)
cost_metric.add(cost, {"model": model})
```
**Query metrics i Application Insights:**
```kusto
AppMetrics
| where Name == "gen_ai.input_tokens"
| summarize TotalTokens = sum(Sum) by Model = tostring(Properties.model), bin(TimeGenerated, 1h)
| render timechart
```
### Latency percentiles
**Query latency distribution:**
```kusto
AppDependencies
| where Target contains "openai.azure.com"
| extend Model = tostring(Properties["gen_ai.request.model"])
| summarize
P50 = percentile(DurationMs, 50),
P90 = percentile(DurationMs, 90),
P95 = percentile(DurationMs, 95),
P99 = percentile(DurationMs, 99),
Count = count()
by Model, bin(TimeGenerated, 1h)
```
### Time to first token (TTFT)
TTFT er kritisk metric for user experience:
```python
import time
def track_streaming_latency(model: str):
"""Track time to first token for streaming response."""
with tracer.start_as_current_span("streaming_call") as span:
start_time = time.time()
first_token_received = False
for chunk in stream_response:
if not first_token_received:
ttft = (time.time() - start_time) * 1000 # ms
span.set_attribute("gen_ai.ttft_ms", ttft)
first_token_received = True
```
**Query TTFT:**
```kusto
AppTraces
| where OperationName == "streaming_call"
| extend TTFT = todouble(Properties.gen_ai_ttft_ms)
| summarize avg(TTFT), percentile(TTFT, 95) by bin(TimeGenerated, 1h)
```
## Error Tracking og Alerting
### LLM-spesifikke errors
**Common error patterns:**
| Error type | Årsak | Mitigering |
|------------|-------|------------|
| **RateLimitError** | 429 Too Many Requests | Implement exponential backoff, øk TPM quota |
| **ContentFilterError** | Content policy violation | Sanitize prompts, adjust content filter settings |
| **TimeoutError** | Request > 10min timeout | Chunk inputs, bruk streaming |
| **TokenLimitExceeded** | Input > model context window | Truncate history, summarize context |
| **ModelNotFound** | Deployment name feil | Validate deployment names i config |
### Exception tracking
Application Insights fanger exceptions automatisk, men legg til context:
```python
def safe_llm_call(prompt: str):
"""LLM call with exception handling."""
with tracer.start_as_current_span("llm_call") as span:
try:
response = client.chat.completions.create(...)
span.set_attribute("gen_ai.success", True)
return response
except RateLimitError as e:
span.set_status(Status(StatusCode.ERROR, "Rate limit exceeded"))
span.record_exception(e)
span.set_attribute("gen_ai.error.type", "rate_limit")
span.set_attribute("gen_ai.retry_after", e.retry_after)
raise
except ContentFilterError as e:
span.set_status(Status(StatusCode.ERROR, "Content filtered"))
span.record_exception(e)
span.set_attribute("gen_ai.error.type", "content_filter")
span.set_attribute("gen_ai.filter.category", e.category)
raise
```
**Query error rates:**
```kusto
AppExceptions
| where Properties.gen_ai_error_type == "rate_limit"
| summarize ErrorCount = count() by bin(TimeGenerated, 5m)
| render timechart
```
### Smart alerting for LLM failures
**Alert rule examples:**
1. **High error rate:**
```kusto
AppDependencies
| where Target contains "openai.azure.com"
| where Success == false
| summarize ErrorRate = (count() * 100.0) / todouble(count()) by bin(TimeGenerated, 5m)
| where ErrorRate > 10 // > 10% errors
```
2. **Latency spike:**
```kusto
AppDependencies
| where Target contains "openai.azure.com"
| summarize P95 = percentile(DurationMs, 95) by bin(TimeGenerated, 5m)
| where P95 > 5000 // > 5 seconds P95
```
3. **Cost spike:**
```kusto
AppMetrics
| where Name == "gen_ai.cost_usd"
| summarize TotalCost = sum(Sum) by bin(TimeGenerated, 1h)
| where TotalCost > 100 // > $100/hour
```
### Anomaly detection for token usage
Application Insights har innebygd anomaly detection:
```kusto
AppMetrics
| where Name == "gen_ai.input_tokens"
| make-series TotalTokens = sum(Sum) default=0 on TimeGenerated step 1h
| extend Anomalies = series_decompose_anomalies(TotalTokens, 1.5)
| where Anomalies > 0 // Anomali detektert
```
## Framework-integrasjoner
### LangChain / LangGraph
**Instrumentering:**
```python
from langchain_azure_ai.callbacks.tracers import AzureAIOpenTelemetryTracer
azure_tracer = AzureAIOpenTelemetryTracer(
connection_string=os.environ["APPLICATION_INSIGHTS_CONNECTION_STRING"],
enable_content_recording=True,
name="My Agent",
id="agent_v1"
)
# Attach til LangChain model
llm = AzureChatOpenAI(..., callbacks=[azure_tracer])
# Eller til agent
agent = create_agent(model=llm, tools=tools, callbacks=[azure_tracer])
```
**Query LangChain traces:**
```kusto
AppTraces
| where Properties.framework == "langchain"
| extend ChainName = tostring(Properties.chain_name)
| summarize Count = count(), AvgDuration = avg(DurationMs) by ChainName
```
### Semantic Kernel
Semantic Kernel har native Application Insights støtte:
```csharp
using Microsoft.ApplicationInsights;
using Microsoft.SemanticKernel;
var telemetryClient = new TelemetryClient();
var kernel = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(...)
.Build();
// Tracing er automatisk enabled
var result = await kernel.InvokePromptAsync("...");
```
### Microsoft Agent Framework
Agent Framework sender automatisk telemetri til Application Insights:
```python
from azure.ai.agents.telemetry import AIAgentsInstrumentor
# Enable instrumentation
AIAgentsInstrumentor().instrument()
# All agent calls er automatisk tracet
agent = project_client.agents.create_agent(...)
```
### OpenAI Agents SDK
**Instrumentering:**
```python
from opentelemetry.instrumentation.openai_agents import OpenAIAgentsInstrumentor
# Instrument SDK
OpenAIAgentsInstrumentor().instrument(tracer_provider=trace.get_tracer_provider())
# All OpenAI agent calls er tracet
with tracer.start_as_current_span("agent_session"):
# ... run agent
pass
```
## Lokal debugging med Aspire Dashboard
For lokal utvikling uten Application Insights:
**Setup:**
```bash
pip install opentelemetry-exporter-otlp
```
**Code:**
```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# Setup OTLP exporter (Aspire Dashboard)
provider = TracerProvider()
provider.add_span_processor(
BatchSpanProcessor(
OTLPSpanExporter(endpoint="http://localhost:4317")
)
)
trace.set_tracer_provider(provider)
```
**Start Aspire Dashboard:**
```bash
docker run -p 4317:4317 -p 18888:18888 mcr.microsoft.com/dotnet/aspire-dashboard:latest
```
Åpne `http://localhost:18888` for å se traces lokalt.
## Best Practices
### 1. Service naming
Bruk `cloud_RoleName` for å skille tjenester:
```python
from opentelemetry.sdk.resources import Resource
resource = Resource.create({
"service.name": "chat-api",
"service.version": "1.2.0",
"deployment.environment": "production"
})
provider = TracerProvider(resource=resource)
```
**Query per service:**
```kusto
AppRequests
| where AppRoleName == "chat-api"
```
### 2. Redact sensitive data
**Ikke logg:**
- User PII (navn, epost, telefon)
- API keys eller secrets
- Sensitive business data
**Implementer redaction:**
```python
import re
def redact_pii(text: str) -> str:
"""Redact common PII patterns."""
# Email
text = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', '[EMAIL]', text)
# Phone (US)
text = re.sub(r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b', '[PHONE]', text)
# SSN
text = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN]', text)
return text
# Bruk før logging
span.set_attribute("gen_ai.prompt", redact_pii(original_prompt))
```
### 3. Sampling for kostnadsoptimalisering
For high-volume applikasjoner, bruk adaptive sampling:
```python
from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor(
connection_string=connection_string,
enable_adaptive_sampling=True,
sampling_rate=0.1 # 10% av requests
)
```
**Aldri sample:**
- Errors og exceptions
- High-value user sessions (premium users)
- Performance anomalies
### 4. Correlation med evaluations
Link tracing til offline evaluation runs:
```python
def log_evaluation_result(trace_id: str, metric_name: str, score: float):
"""Link evaluation score til original trace."""
with tracer.start_as_current_span("evaluation_result") as span:
span.set_attribute("evaluation.trace_id", trace_id)
span.set_attribute("evaluation.metric", metric_name)
span.set_attribute("evaluation.score", score)
```
**Query:**
```kusto
AppTraces
| where OperationName == "evaluation_result"
| join kind=inner (
AppRequests
| extend TraceId = OperationId
) on $left.Properties.evaluation_trace_id == $right.TraceId
| project TimeGenerated, RequestName, EvaluationScore = todouble(Properties.evaluation_score)
```
### 5. Cost allocation per customer
Tag requests med customer ID:
```python
with tracer.start_as_current_span("customer_request") as span:
span.set_attribute("customer.id", customer_id)
span.set_attribute("customer.tier", "enterprise")
```
**Query cost per customer:**
```kusto
AppMetrics
| where Name == "gen_ai.cost_usd"
| extend CustomerId = tostring(Properties.customer_id)
| summarize TotalCost = sum(Sum) by CustomerId
| order by TotalCost desc
```
## Visualisering i Azure Portal
### Transaction details view
Application Insights **End-to-end transaction details** viser:
1. Full trace timeline med alle spans
2. Dependencies sortert etter latency
3. Exceptions linket til parent spans
4. Custom properties per span
**Navigasjon:**
- Application Insights → **Investigate** → **Performance**
- Velg en request → Klikk **View all telemetry**
### Workbooks for LLM monitoring
**Pre-built workbook template:**
1. Token usage over time (per model)
2. Cost per hour/day/month
3. Latency percentiles (P50, P95, P99)
4. Error rate by error type
5. Top 10 slowest requests
6. User feedback distribution
**Opprett workbook:**
- Application Insights → **Monitoring** → **Workbooks** → **+ New**
### Dashboards
**Key metrics dashboard:**
- Total requests (trendline)
- Average latency (by model)
- Error rate (%)
- Total cost (daily/monthly)
- Token usage (input vs output)
- Active users
## For Cosmo Skyberg: Application Insights for LLM Monitoring
**Når anbefalte:**
Application Insights er riktig valg for LLM-observabilitet når:
1. **Azure-native setup** — Kunden bruker Microsoft Foundry eller Azure OpenAI
2. **Multi-framework miljø** — LangChain, Semantic Kernel, Agent Framework i samme system
3. **Enterprise compliance** — Trenger logging i Azure subscription med RBAC
4. **Cost tracking** — Viktig å korrelere token usage med fakturering
5. **Eksisterende Azure Monitor** — Allerede bruker App Insights for web APIs
**Når vurdere alternativer:**
- **LangSmith** — Hvis kun LangChain, og trenger dataset curation
- **Weights & Biases** — Hvis ML engineering team, trenger experiment tracking
- **Elastic APM** — Hvis eksisterende Elastic stack for logging
- **Aspire Dashboard** — Lokal dev/debugging (ikke produksjon)
**Key decision factors:**
| Faktor | Application Insights | LangSmith | W&B |
|--------|----------------------|-----------|-----|
| **OpenTelemetry native** | ✅ Ja | ⚠️ Partial | ❌ Nei |
| **Cost per GB** | ~$2.76/GB | $0 (gratis tier), $39+ | $0 (gratis tier), $50+ |
| **Retention** | 90 dager default | 14 dager (gratis), 400 dager (betalt) | Ubegrenset |
| **Multi-framework** | ✅ Alle | ⚠️ LangChain best | ⚠️ Custom integration |
| **Azure integration** | ✅ Native | ❌ Nei | ❌ Nei |
| **Offline evaluation** | ⚠️ Via custom code | ✅ Built-in | ✅ Built-in |
**Arkitekturrådgiving:**
1. **Start med Application Insights** — Enkleste setup for Azure-kunder
2. **Enable content recording selektivt** — Kun for debugging, ikke produksjon
3. **Implementer custom metrics** — Token cost, latency percentiles, TTFT
4. **Sett opp alerting** — Error rate, cost spikes, latency anomalies
5. **Kombiner med prompt evaluation** — Microsoft Foundry Evaluation + App Insights tracing
**Eksempel-arkitektur:**
```
[User] → [Azure API Management]
↓ (trace-id propagation)
[Chat API] → [Application Insights]
↓
[Agent Orchestrator]
├─ [LangChain Agent] → [Azure OpenAI] → [Token metrics]
├─ [Tool: Azure AI Search] → [Dependency trace]
└─ [Tool: Bing Search] → [Dependency trace]
```
**Kostnadsestimat:**
- **Ingestion:** 1M requests/måned ≈ 10 GB ≈ $27/mnd
- **Query:** 10 GB scanned/mnd ≈ $0.50/mnd
- **Retention:** 90 dager default (inkludert i pris)
- **Total:** ~$30-50/mnd for medium-scale produksjon
**Sett opp i 10 minutter:**
```bash
# 1. Connect Application Insights til AI Foundry project
az monitor app-insights component create \
--app my-ai-app \
--location norwayeast \
--resource-group my-rg
# 2. Link til Foundry project (via portal eller CLI)
# 3. Install SDK + configure
pip install azure-ai-projects azure-monitor-opentelemetry
# 4. Skriv 5 linjer code (se "Instrumentering med Microsoft Foundry SDK")
# 5. Deploy → Se traces i portal
```
**Første queries å kjøre:**
```kusto
// 1. Top 10 slowest requests
AppRequests
| top 10 by DurationMs desc
| project TimeGenerated, Name, DurationMs, Success
// 2. Error distribution
AppExceptions
| summarize Count = count() by Type
| order by Count desc
// 3. Cost per hour
AppMetrics
| where Name == "gen_ai.cost_usd"
| summarize Cost = sum(Sum) by bin(TimeGenerated, 1h)
| render timechart
```
---
**Relaterte referanser:**
- `token-usage-tracking.md` — Token metrics og cost calculation
- `azure-monitor-integration.md` — Full Azure Monitor setup
- `llm-performance-baselines.md` — Performance benchmarks per model
- `distributed-tracing-patterns.md` — Multi-service correlation