Add /ultraresearch-local for structured research combining local codebase analysis with external knowledge via parallel agent swarms. Produces research briefs with triangulation, confidence ratings, and source quality assessment. New command: /ultraresearch-local with modes --quick, --local, --external, --fg. New agents: research-orchestrator (opus), docs-researcher, community-researcher, security-researcher, contrarian-researcher, gemini-bridge (all sonnet). New template: research-brief-template.md. Integration: --research flag in /ultraplan-local accepts pre-built research briefs (up to 3), enriches the interview and exploration phases. Planning orchestrator cross-references brief findings during synthesis. Design principle: Context Engineering — right information to right agent at right time. Research briefs are structured artifacts in the pipeline: ultraresearch → brief → ultraplan --research → plan → ultraexecute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
14 KiB
Agent Monitoring, Observability and Debugging
Last updated: 2026-02 Status: GA / Preview (Agent 365) Category: Agent Orchestration & Automation
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 Azure AI 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, Azure AI 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, Azure AI 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 Azure AI 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
Azure AI Foundry Portal
Foundry-portalen gir visuell trace-inspeksjon:
- Traces-visning: Filter traces etter tidsrom, agent, bruker eller status
- Span-detaljer: Se inputs, outputs og attributter for hver operasjon
- Call tree: Visualiser hierarkisk relasjon mellom spans
- 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 Cosmo
- 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=falsei 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.