Aller au contenu principal

G-01 Traçage distribué

Brique G de la plateforme Enterprise AI. Technologie : SDK OpenTelemetry et conventions sémantiques (gen_ai.*), propagation W3C traceparent. Version anglaise : ../../en/bricks/G-01-distributed-tracing.md.

Rôle et responsabilités​

  • Donner un identifiant de trace unique à toute une requête : portail ou SDK -> Control Plane -> gateway -> fournisseur -> outils -> workers asynchrones.
  • Porter les attributs eai.* (tenant, projet, agent, run, tâche, id de décision) sur chaque span.

Position et interactions​

  • Chemin d'exécution : tous les chemins (temps réel, batch, événement, workflow).
  • traceparent accepté sur chaque appel d'API et recopié dans les en-têtes NATS et le memo Temporal pour les chemins asynchrones.
  • X-Request-Id renvoyé et stocké dans les Usage et Audit Events pour la corrélation (G-14).

Part open source et part développée​

  • Open source réutilisé : SDK OpenTelemetry (Python, JS, Java, Go), auto-instrumentation FastAPI, httpx, psycopg.
  • Développé dans la plateforme : Convention d'attributs eai.*, propagation via NATS et Temporal, assistants dans les SDK.

Modèle de données​

Tables du Control Plane (schéma eai) : eai.telemetry_spans.

Chaque table de tenant a tenant_id uuid NOT NULL et une politique de sécurité au niveau des lignes sur current_setting('app.tenant_id', true)::uuid. ClickHouse usage_events est la réplique analytique de eai.usage_events (ReplacingMergeTree par event_id).

Contrat : contracts/v1/execution-contract.schema.json (schema_version 1.0). L'usage est toujours remonté avec contracts/v1/usage-event.schema.json, l'audit avec contracts/v1/audit-event.schema.json.

Endpoints d'API​

MéthodeChemin
POST/v1/telemetry/spans
GET/v1/telemetry/traces/{trace_id}

POST /v1/telemetry/spans​

Requête :

{
"spans": [
{
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"name": "gen_ai.chat",
"kind": "client",
"start_time": "2026-10-29T10:00:00.120Z",
"end_time": "2026-10-29T10:00:01.940Z",
"attributes": {
"gen_ai.request.model": "gpt-4o-mini",
"gen_ai.usage.input_tokens": 812,
"eai.agent_id": "agt_ap",
"eai.run_id": "run_42"
}
}
]
}

Réponse :

{
"accepted": 1,
"rejected": 0
}

GET /v1/telemetry/traces/{trace_id}​

Réponse :

{
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"spans": [
{
"span_id": "00f067aa0ba902b7",
"name": "gen_ai.chat",
"duration_ms": 1820
}
],
"links": {
"opik": {
"url": "https://<opik-host>/default/redirect/projects?name=eai-platform",
"metadata_key": "eai.trace_id",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}
}

Propagation de la trace (HTTP et file d'événements)​

  • HTTP : le span serveur de l'API continue le traceparent W3C reçu ; le Model Gateway (eai.llm.route, eai.llm.provider_call) et le Tool Gateway (eai.tool.invoke) ouvrent des spans enfants et l'appel sortant reçoit le traceparent du span courant.
  • File : scheduler.publish ouvre eai.event.publish et écrit traceparent et tracestate dans les en-têtes de l'événement (NATS ou eai.event_outbox). Le job outbox du worker ouvre eai.event.deliver comme enfant de ce traceparent, puis eai.event.dispatch pour les déclencheurs.
  • Le worker (python -m eai.worker) initialise OpenTelemetry avec les mêmes réglages EAI_OTEL_* que l'API.
  • Preuve : services/control-plane/tests/test_trace_end_to_end.py avec le vrai otelcol-contrib. Détails : docs/operations/slo.md.

Exemples SDK​

Python​

from enterprise_ai import EnterpriseAI

client = EnterpriseAI(base_url="<control-plane-url>", api_key="eai_live_xxx", tenant="acme", locale="fr")
client.telemetry.ingest(spans=spans)
client.telemetry.trace(trace_id="4bf92f3577b34da6a3ce929d0e0e4736")

TypeScript​

import { EnterpriseAI } from "@enterprise-ai/sdk";

const client = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY, tenant: "acme", locale: "fr" });
await client.telemetry.ingestSpans({ spans: spans });
await client.telemetry.trace({ traceId: "4bf92f3577b34da6a3ce929d0e0e4736" });

Java​

EnterpriseAIClient client = EnterpriseAIClient.builder()
.baseUrl("<control-plane-url>")
.apiKey(System.getenv("EAI_API_KEY"))
.tenant("acme")
.locale(Locale.FRENCH)
.build();
client.telemetry().ingestSpans(Map.of("spans", spans));
client.telemetry().trace("4bf92f3577b34da6a3ce929d0e0e4736");

Go​

client, err := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")), eai.WithTenant("acme"), eai.WithLocale("fr"))
if err != nil { log.Fatal(err) }
ctx := context.Background()
_, err = client.Telemetry.IngestSpans(ctx, map[string]any{"spans": spans})
_, err = client.Telemetry.Trace(ctx, "4bf92f3577b34da6a3ce929d0e0e4736")

Configuration​

Variables d'environnement : EAI_OTEL_EXPORTER_OTLP_ENDPOINT.

Clés de valeurs Helm (deploy/helm/enterprise-ai/values.yaml) : controlPlane.config.EAI_OTEL_EXPORTER_OTLP_ENDPOINT, global.monitoring.

Sécurité​

  • Aucun contenu de prompt ou de réponse dans les attributs OTel par défaut ; le contenu va à Opik avec masquage (G-03).
  • Tenant déduit de l'identifiant d'accès, jamais du corps ; sécurité au niveau des lignes PostgreSQL sur chaque table de tenant.
  • Chaque mutation et décision de politique écrit un événement d'audit chaîné par hachage (G-11).
  • Les erreurs utilisent l'enveloppe standard avec message_i18n en et fr.

Observabilité​

  • Autosurveillance : compteurs de spans perdus dans les exportateurs des SDK.
  • traceparent W3C propagé, X-Request-Id renvoyé, les spans portent eai.tenant_id, eai.project, eai.agent_id, eai.run_id.

Unités FinOps​

  • Volume de traces par tenant mesuré pour imputer le coût de stockage de l'observabilité.

Modes de défaillance et résilience​

  • Collecteur indisponible -> le SDK met en tampon puis abandonne les spans, sans jamais bloquer l'appel métier.

Adoption autonome​

Toute application cliente peut envoyer ses spans à POST /v1/telemetry/spans ou directement à son propre collecteur.

Tests d'acceptation​

  1. Un run appelant un outil via MCP présente une trace unique avec spans gateway, outil et modèle.
  2. Un job déclenché par NATS conserve l'id de trace parent.

Feuille de route d'implémentation