ms-ai-architect/skills/ms-ai-engineering/references/agent-orchestration/agent-monitoring-observability.md
Kjell Tore Guttormsen 3a73eeafdc refactor(ms-ai-architect): R13 del 1 — nøytraliser Cosmo-personaen i ref-korpusets headinger, etter å ha rettet en gate som var målt usann to ganger
Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:

1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
   produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
   substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
   `Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
   tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
   kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
   formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
   132 bokføres til R13b/R14.

Tre korreksjoner av premisser som sto i ordren og STATE:
  «ca 320 produkt»   -> 451 (case-sensitivt nett manglet 327 lowercase
                        TOC-ankre + 99 identifikatorer; sann nevner 1 638)
  «169 headinger»    -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
                        internt inkonsistent med sin egen topp-variant (204)
  «417 matcher ingen
   populasjon»       -> 417 er cosmo-headinger utenfor kodefences; briefens
                        nevner var reell hele tiden

Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.

TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.

Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.

Verifisering (alle 7 kriterier fra ordren):
  G1 persona på heading-linjer   401 -> 0
  G2 døde fragmentlenker         1 -> 1 (pre-eksisterende, unntatt)
  G3 produkt-forekomster         451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
  de 3 kun-produkt-filene        byte-identiske
  nettet validert begge veier    injisert persona feller G1; genitiv feller G1;
                                 produkt-heading og de 3 filene passerer
  hele diffen                    802 heading-linjer + 654 TOC-linjer, ANNET = 0
  linjeantall                    728 lagt til = 728 slettet
  suite                          1120/1120 (1097 + 23 nye)
  validate-plugin                250 PASS / 0 FAIL
  stikkprøve                     10 filer, alle 5 skills, inkl. de 3 mest
                                 produkt-tunge (26/20/19) — kun heading+TOC

Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 22:12:28 +02:00

15 KiB

Agent Monitoring, Observability and Debugging

Last updated: 2026-02 Status: GA / Preview (Agent 365) Category: Agent Orchestration & Automation Type: reference


Innhold

Introduksjon

Observability for agentsystemer går utover tradisjonell applikasjonsovervåking. Agenter opererer probabilistisk, tar dynamiske beslutninger, og produserer ulike outputs for identiske inputs. Denne ikke-deterministiske naturen krever spesialiserte overvåkingsverktøy som fanger ikke bare ytelsesmetrikker, men også beslutningsprosesser, verktøybruk, prompt-respons-par og evalueringskvalitet.

Microsoft tilbyr en komplett observability-stack for agenter gjennom Microsoft Foundry Tracing, Application Insights, Azure Monitor og Microsoft Agent 365. Foundry-plattformen integrerer OpenTelemetry-basert tracing med AI-spesifikke semantiske konvensjoner, slik at hvert LLM-kall, tool-invokasjon og orkestreringsbeslutning fanges som spans i en distribuert trace.

Agent 365 er Microsofts unified plattform for agentobservability på tvers av Copilot Studio, Microsoft Foundry og tredjepartsruntimes. Den gir enterprise-grade governance med sikkerhet, compliance og business impact-metrikker for hele agentflåten.

Kjernekomponenter

Komponent Formål Teknologi
Distributed Tracing Capture full request lifecycle OpenTelemetry, Microsoft Foundry Tracing
Agent Event Logging Logg agentbeslutninger og handlinger Application Insights, Log Analytics
Performance Profiling Identifiser flaskehalser Azure Monitor Metrics, custom spans
Error Categorization Klassifiser og prioriter feil Azure Monitor Alerts, Sentinel
Debugging Tools Interaktiv feilsøking Foundry Portal, Aspire Dashboard
Agent 365 Unified agent governance og observability Microsoft Agent 365 platform

Distributed Tracing for Agents

OpenTelemetry-basert tracing med Microsoft Foundry

from azure.ai.projects import AIProjectClient
from azure.monitor.opentelemetry import configure_azure_monitor
from azure.identity import DefaultAzureCredential
import os

# Aktiver content recording for full prompt/respons-logging
os.environ["AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED"] = "true"

# Koble til prosjekt
project_client = AIProjectClient(
    credential=DefaultAzureCredential(),
    endpoint=os.environ["PROJECT_ENDPOINT"]
)

# Hent Application Insights connection string fra prosjektet
connection_string = (
    project_client.telemetry
    .get_application_insights_connection_string()
)

# Konfigurer Azure Monitor telemetry
configure_azure_monitor(connection_string=connection_string)

Trace-konsepter

Konsept Beskrivelse Eksempel
Trace Fullstendig reise for en forespørsel gjennom systemet Bruker-spørsmål → routing → RAG → LLM → respons
Span Enkeloperasjon innenfor en trace Ett LLM-kall, ett tool-kall
Attributes Nøkkel-verdi metadata på spans gen_ai.prompt, gen_ai.completion, tool.name
Semantic Conventions Standardiserte attributtnavn OpenTelemetry GenAI semantic conventions

Custom spans for agentorkestrering

from opentelemetry import trace

tracer = trace.get_tracer("agent-orchestrator")

async def orchestrate_agent_request(query: str, user_id: str):
    with tracer.start_as_current_span("agent_orchestration") as root_span:
        root_span.set_attribute("user.id", user_id)
        root_span.set_attribute("query.text", query)

        # Routing span
        with tracer.start_as_current_span("intent_routing") as route_span:
            routing = await classify_intent(query)
            route_span.set_attribute("routing.target", routing.agent)
            route_span.set_attribute("routing.confidence", routing.confidence)
            route_span.set_attribute("routing.intent", routing.intent)

        # RAG retrieval span
        with tracer.start_as_current_span("rag_retrieval") as rag_span:
            documents = await retrieve_context(query, routing.agent)
            rag_span.set_attribute("rag.doc_count", len(documents))
            rag_span.set_attribute("rag.sources",
                [d.source for d in documents])

        # Agent invocation span
        with tracer.start_as_current_span("agent_invocation") as agent_span:
            agent_span.set_attribute("agent.name", routing.agent)
            response = await invoke_agent(routing.agent, query, documents)
            agent_span.set_attribute("response.token_count",
                response.usage.total_tokens)
            agent_span.set_attribute("response.model", response.model)

        root_span.set_attribute("total_tokens", response.usage.total_tokens)
        return response

Agent Event Logging

Strukturert hendelseslogging

import logging
import json
from datetime import datetime

class AgentEventLogger:
    """Strukturert logging for agent-hendelser"""

    def __init__(self, app_insights_handler):
        self.logger = logging.getLogger("agent-events")
        self.logger.addHandler(app_insights_handler)

    def log_agent_decision(self, event: dict):
        """Logg en agentbeslutning med full kontekst"""
        self.logger.info(json.dumps({
            "event_type": "agent_decision",
            "timestamp": datetime.utcnow().isoformat(),
            "agent_name": event["agent"],
            "decision_type": event["type"],  # routing, tool_selection, response
            "input_summary": event.get("input_summary", ""),
            "decision": event["decision"],
            "confidence": event.get("confidence", None),
            "reasoning": event.get("reasoning", ""),
            "tokens_used": event.get("tokens", 0),
            "latency_ms": event.get("latency_ms", 0),
            "metadata": event.get("metadata", {})
        }))

    def log_tool_invocation(self, tool_name: str, input_params: dict,
                            output: str, duration_ms: float, success: bool):
        self.logger.info(json.dumps({
            "event_type": "tool_invocation",
            "timestamp": datetime.utcnow().isoformat(),
            "tool_name": tool_name,
            "input_params": input_params,
            "output_preview": output[:200],
            "duration_ms": duration_ms,
            "success": success
        }))

Performance Profiling

KQL-spørringer for agentytelse

// Latency-breakdown per agent-komponent
traces
| where timestamp > ago(24h)
| where customDimensions.event_type == "agent_decision"
| extend
    agent = tostring(customDimensions.agent_name),
    decision_type = tostring(customDimensions.decision_type),
    latency = todouble(customDimensions.latency_ms),
    tokens = toint(customDimensions.tokens_used)
| summarize
    p50_latency = percentile(latency, 50),
    p95_latency = percentile(latency, 95),
    p99_latency = percentile(latency, 99),
    avg_tokens = avg(tokens),
    request_count = count()
    by agent, decision_type
| order by p95_latency desc
// Identifiser trege tool calls
traces
| where timestamp > ago(7d)
| where customDimensions.event_type == "tool_invocation"
| extend
    tool = tostring(customDimensions.tool_name),
    duration = todouble(customDimensions.duration_ms),
    success = tobool(customDimensions.success)
| summarize
    avg_duration = avg(duration),
    p95_duration = percentile(duration, 95),
    failure_rate = countif(success == false) * 100.0 / count(),
    total_calls = count()
    by tool
| where p95_duration > 2000 or failure_rate > 5
| order by p95_duration desc

Azure Monitor dashboards

// Agent health dashboard - hoveddatakilder
let agent_health = traces
| where timestamp > ago(1h)
| where customDimensions.event_type in
    ("agent_decision", "tool_invocation")
| extend agent = tostring(customDimensions.agent_name)
| summarize
    requests = count(),
    errors = countif(customDimensions.success == "false"),
    avg_latency = avg(todouble(customDimensions.latency_ms)),
    avg_tokens = avg(todouble(customDimensions.tokens_used))
    by agent, bin(timestamp, 5m);

agent_health
| render timechart

Error Categorization

Feilkategorisering for agentsystemer

Kategori Eksempler Alvorlighet Handling
Model Errors Rate limit, timeout, content filter Medium Retry med backoff
Tool Failures API-feil, timeout, ugyldige params Medium Fallback til alternativt verktøy
Routing Errors Feil agent valgt, lav confidence Lav Logg + iterér på router-prompt
Hallucination Agent fabrikkerer fakta Høy Groundedness-evaluering + alert
Safety Violations Upassende innhold generert Kritisk Umiddelbar blokkering + varsling
Data Quality RAG returnerer irrelevante dokumenter Medium Indeks-kvalitetsjekk
# Automatisk feilkategorisering
class AgentErrorClassifier:
    ERROR_CATEGORIES = {
        "rate_limit": {"severity": "medium", "retry": True},
        "timeout": {"severity": "medium", "retry": True},
        "content_filter": {"severity": "high", "retry": False},
        "tool_failure": {"severity": "medium", "retry": True},
        "hallucination": {"severity": "high", "retry": False},
        "routing_error": {"severity": "low", "retry": True},
    }

    def classify(self, error: Exception, context: dict) -> dict:
        if "429" in str(error):
            return {**self.ERROR_CATEGORIES["rate_limit"],
                    "wait_seconds": self._extract_retry_after(error)}
        if "timeout" in str(error).lower():
            return self.ERROR_CATEGORIES["timeout"]
        if "content_filter" in str(error).lower():
            return self.ERROR_CATEGORIES["content_filter"]
        # Default
        return {"severity": "unknown", "retry": False}

Debugging Tools

Microsoft Foundry Portal

Foundry-portalen gir visuell trace-inspeksjon:

  1. Traces-visning: Filter traces etter tidsrom, agent, bruker eller status
  2. Span-detaljer: Se inputs, outputs og attributter for hver operasjon
  3. Call tree: Visualiser hierarkisk relasjon mellom spans
  4. Evaluering: Se evalueringsresultater direkte på traces

Aspire Dashboard for lokal debugging

# Lokal debugging med Aspire Dashboard
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter
)

# Eksporter til Aspire Dashboard (localhost:4317)
exporter = OTLPSpanExporter(endpoint="http://localhost:4317")
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(SimpleSpanProcessor(exporter))
trace.set_tracer_provider(tracer_provider)

# Alle agent-operasjoner vises nå i Aspire Dashboard
# Start med: docker run --rm -p 18888:18888 -p 4317:18889 \
#   mcr.microsoft.com/dotnet/aspire-dashboard:latest

Debugging-strategi for agenter

1. Reprodusér → Finn den spesifikke tracen i Foundry/AppInsights
2. Isolér    → Identifiser hvilken span som forårsaket problemet
3. Inspiser  → Se prompt, kontekst og respons for den spannen
4. Hypotese  → Er det routing? RAG? Modell? Verktøy?
5. Test      → Kjør isolert test med samme input
6. Fiks      → Oppdater prompt/config/verktøy
7. Verifiser → Sammenlign metrikker før/etter

Observability SDK Integration

Agent Framework observability

// Microsoft Agent Framework med full observability
var builder = WebApplication.CreateBuilder(args);

// Aktiver agent observability
builder.Services.AddAgentObservability(options =>
{
    options.EnableSensitiveData = true; // Full prompt logging
    options.ServiceName = "customer-support-agent";
    options.ExportToApplicationInsights(
        connectionString: builder.Configuration["AppInsights:ConnectionString"]
    );
});

Norsk offentlig sektor

Aspekt Krav Implementering
Logging av AI-beslutninger EU AI Act Art. 12 Full trace med decision reasoning
Personvern i logger GDPR Art. 5 Redact PII fra traces, eller disable content recording
Arkivering Arkivloven Retensjon av agent-traces minimum 5 år
Innsyn Offentlighetsloven Tilgjengeliggjør agent-beslutningslogger for innsyn
Sikkerhetshendelser NSM Grunnprinsipper Azure Sentinel-integrasjon for anomali-deteksjon

Personvern i observability

# Sensitive data redaction for offentlig sektor
import re

class PIIRedactor:
    PATTERNS = {
        "fnr": r"\b\d{11}\b",  # Fødselsnummer
        "email": r"\b[\w.-]+@[\w.-]+\.\w+\b",
        "phone": r"\b(?:\+47|0047)?\s*\d{8}\b",
    }

    def redact(self, text: str) -> str:
        for pii_type, pattern in self.PATTERNS.items():
            text = re.sub(pattern, f"[REDACTED_{pii_type.upper()}]", text)
        return text

# Bruk i tracing
redactor = PIIRedactor()
span.set_attribute("query.text", redactor.redact(query))

Beslutningsrammeverk

Scenario Anbefaling Begrunnelse
Utvikling/testing Aspire Dashboard + full content recording Maksimal synlighet for debugging
Pre-produksjon Foundry Tracing + evaluatorer Kvalitetssikring før lansering
Produksjon standard Application Insights + 10% sampling Balanse mellom synlighet og kostnad
Produksjon høy-risiko 100% tracing + Sentinel + Agent 365 Full compliance og sikkerhet
Multi-team organisasjon Agent 365 + sentralisert Log Analytics Unified governance på tvers av team

For arkitekten

  • OpenTelemetry-basert tracing er fundamentet -- all agent-observability bygger på traces med spans. Implementer fra dag 1, ikke legg til etterpå.
  • Agent 365 er veien fremover for enterprise-scale agent governance -- det gir unified synlighet på tvers av Copilot Studio, Foundry og tredjepartsagenter.
  • Redact PII i traces for offentlig sektor -- bruk AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED=false i produksjon med persondata, eller implementer custom redaction.
  • KQL er ditt viktigste verktøy for å analysere agent-atferd i produksjon -- bygg dashboards for latency, feilrater, token-bruk og kvalitetsmetrikker per agent.
  • Debugging-workflow: Start alltid med å finne tracen, deretter isolér den problematiske spannen -- 90% av agent-feil kan diagnostiseres ved å inspisere prompt, kontekst og respons.