🤖 Agents IA

agent-agent-observability

Observabilité complète pour agents IA — distributed tracing, métriques custom, log correlation et dashboards de supervision.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- agent-agent-observability --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } agent-agent-observability -Launch"

🚀 Déjà installé ?

claude "/agent-agent-observability"

Ou tapez /agent-agent-observability dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

observabilité agenttracing agentmétriques agentagent observabilityOpenTelemetry agent

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/agent-agent-observability ~/.claude/skills/

Payload du plugin : skills/agent-agent-observability · source éditable : agent-skills/agent-observability

📖 Manuel

Agent Observability

Workflow

1. Choisir la stratégie d'instrumentation

Identifie les trois piliers à couvrir selon le type d'agent :

Type d'agentTracesMétriques prioritairesLogs
Agent autonome (ReAct)Chaque itération reason→acttokens/iter, nb iterationsprompt + tool calls
Orchestrateur multi-agentsSpans parent→enfant par sous-agentlatence inter-agents, taux délégationhandoff payloads
Agent RAGRetrieval + LLM call séparésrecall@k, rerank score, latence retrievalquery + docs retenus
Pipeline séquentielUn span par étape du pipelinethroughput, erreurs par étapeinputs/outputs chaque step

Critère de décision : si tu as plus de 2 agents en chaîne → distributed tracing obligatoire. Agent isolé → métriques + logs structurés suffisent pour commencer.


2. Instrumenter avec OpenTelemetry

Installer le SDK Python ou TypeScript selon le runtime :

# Python
pip install opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-httpx

# TypeScript / Node
npm install @opentelemetry/sdk-node @opentelemetry/exporter-otlp-http @opentelemetry/instrumentation-http

Initialiser le tracer en entrée de l'agent (une seule fois) :

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider(resource=Resource({"service.name": "my-agent", "agent.version": "1.0"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4318")))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

Wrapper minimal autour des appels LLM :

def call_llm(prompt: str, model: str = "claude-sonnet-4-6") -> str:
    with tracer.start_as_current_span("llm.call") as span:
        span.set_attributes({
            "llm.model": model,
            "llm.prompt_tokens": count_tokens(prompt),
            "llm.prompt_hash": sha256(prompt)[:8],  # pas le texte en clair
        })
        response = client.messages.create(model=model, messages=[{"role": "user", "content": prompt}])
        span.set_attributes({
            "llm.completion_tokens": response.usage.output_tokens,
            "llm.cost_usd": estimate_cost(response.usage),
        })
        return response.content[0].text

Propager le context entre agents (HTTP) :

from opentelemetry.propagate import inject, extract

# Agent émetteur — injecter dans les headers
headers = {}
inject(headers)
requests.post("http://sub-agent/run", json=payload, headers=headers)

# Agent récepteur — extraire le context
ctx = extract(request.headers)
with tracer.start_as_current_span("sub_agent.run", context=ctx):
    ...

3. Définir les métriques custom agents IA

from opentelemetry import metrics

meter = metrics.get_meter("agent-metrics")

# Compteurs et histogrammes à créer
llm_tokens = meter.create_counter("agent.llm.tokens_total", unit="tokens")
llm_latency = meter.create_histogram("agent.llm.latency_ms", unit="ms")
tool_calls = meter.create_counter("agent.tool.calls_total")
tool_errors = meter.create_counter("agent.tool.errors_total")
task_iterations = meter.create_histogram("agent.task.iterations")
agent_cost = meter.create_counter("agent.cost_usd_total", unit="USD")

# Usage dans le code
llm_tokens.add(tokens, {"model": model, "agent_id": agent_id})
llm_latency.record(elapsed_ms, {"model": model})

Métriques critiques à ne pas oublier :


4. Structurer les logs avec corrélation trace

import logging, json
from opentelemetry import trace

class AgentLogger:
    def __init__(self, name: str):
        self.logger = logging.getLogger(name)

    def _base(self, extra: dict) -> dict:
        span = trace.get_current_span()
        ctx = span.get_span_context()
        return {
            "trace_id": format(ctx.trace_id, "032x") if ctx.is_valid else None,
            "span_id": format(ctx.span_id, "016x") if ctx.is_valid else None,
            **extra,
        }

    def tool_call(self, tool: str, params: dict, result_summary: str):
        self.logger.info(json.dumps(self._base({
            "event": "tool.call",
            "tool": tool,
            "params_keys": list(params.keys()),  # pas les valeurs sensibles
            "result_summary": result_summary[:200],
        })))

    def decision(self, reason: str, action: str):
        self.logger.info(json.dumps(self._base({
            "event": "agent.decision",
            "reason": reason[:500],
            "action": action,
        })))

Règle de masquage PII : ne logguer que les clés des paramètres (pas les valeurs), tronquer les textes libres à 200-500 chars, ne jamais logguer tokens API, mots de passe, données personnelles.


5. Dashboards — panels essentiels

Grafana / Datadog — structure recommandée :

Panel 1 — Overview (last 1h)
  - Agents actifs (gauge)
  - Requêtes/min (time series)
  - Taux d'erreur % (stat + threshold rouge >5%)
  - Coût total estimé (stat)

Panel 2 — LLM Performance
  - Latence p50/p95/p99 par modèle (histogram)
  - Tokens consommés par requête (time series)
  - Distribution des longueurs de prompt (histogram)

Panel 3 — Tool Calls
  - Top 10 outils les plus appelés (bar chart)
  - Taux d'échec par outil (table)
  - Latence moyenne par outil (bar chart)

Panel 4 — Multi-agent (si applicable)
  - Graphe de dépendances agents (node graph panel)
  - Latence inter-agents (heatmap)
  - Chaînes les plus longues (table)

Panel 5 — Traces individuelles
  - Lien vers Jaeger/Tempo avec filtre trace_id

6. Alertes — seuils 2026

# Prometheus AlertManager — exemples copiables
- alert: AgentHighLatency
  expr: histogram_quantile(0.95, agent_llm_latency_ms_bucket) > 10000
  for: 5m
  labels: { severity: warning }
  annotations:
    summary: "LLM p95 latency > 10s sur {{ $labels.model }}"

- alert: AgentLoopDetected
  expr: increase(agent_loop_detected_total[5m]) > 0
  labels: { severity: critical }
  annotations:
    summary: "Boucle infinie détectée — agent {{ $labels.agent_id }}"

- alert: AgentHighCost
  expr: increase(agent_cost_usd_total[1h]) > 10
  labels: { severity: warning }
  annotations:
    summary: "Coût agent > $10/h — vérifier les requêtes abusives"

- alert: AgentErrorRate
  expr: rate(agent_tool_errors_total[5m]) / rate(agent_tool_calls_total[5m]) > 0.1
  for: 3m
  labels: { severity: critical }

7. Tracer les workflows multi-agents

Pattern recommandé — chaque agent reçoit et propage le trace context :

# Orchestrateur — crée la trace racine
with tracer.start_as_current_span("orchestrator.task", attributes={"task.id": task_id}):
    # Déléguer à sous-agent A
    with tracer.start_as_current_span("delegate.agent_a"):
        result_a = call_sub_agent("agent-a", payload_a)

    # Déléguer à sous-agent B en parallèle
    with tracer.start_as_current_span("delegate.agent_b"):
        result_b = call_sub_agent("agent-b", payload_b)

    # Agréger
    with tracer.start_as_current_span("aggregate"):
        final = aggregate(result_a, result_b)

Visualisation dans Jaeger/Tempo : waterfall view → identifier quel agent bloque la chaîne.


Anti-patterns et pièges

PiègeConséquenceSolution
Logguer le prompt complet en prodFuite PII + coût stockage élevéHash du prompt + tronquage
Créer un span par token streaméOverhead OTel > temps LLMUn seul span par appel LLM complet
Pas de sampling en prodVolume ingestion x100Tail-based sampling à 10-20% + 100% sur erreurs
Alertes sur métriques brutes sans baselineFatigue d'alerte dès le lancementDéfinir les seuils après 1 semaine d'observation
Trace context non propagé vers les workers asyncTraces orphelines, corrélation impossibleToujours passer le context explicitement aux threads/coroutines
Métriques LLM sans dimension modelImpossible de comparer les modèlesToujours tagger avec model, agent_id, env
Retention 30 jours par défautCoûts ingestion élevés7j traces détaillées, 90j métriques agrégées

Bonnes pratiques 2026