Zum Inhalt springen

Observability und Telemetrie

Diese Seite richtet sich an Entwickler. Sie beschreibt, wie das Paket @ai-systems-manager/sdk jeden Aufruf instrumentiert: OpenTelemetry-Spans nach den GenAI Semantic Conventions, die Usage-Meldung an die Plattform über den MetricBuffer und den Schema-Retry. Wer das SDK zuerst grundsätzlich einrichten will, liest SDK einrichten und aufrufen.

Ohne Konfiguration verwendet das SDK einen NoopTracer: Es werden keine Spans emittiert, und es entsteht kein Crash. Wer Spans sammeln will, gibt über das optionale Konfigfeld otel einen der beiden Anschlusspfade an.

Wenn die Anwendung bereits ein OpenTelemetry-Setup hat (eigener instrumentation.ts mit TracerProvider und Exporter), reicht man den Tracer über otel.tracer durch. Das SDK verwendet ihn unverändert:

import { trace } from '@opentelemetry/api'
import { createAsmClient } from '@ai-systems-manager/sdk'
const asm = createAsmClient({
baseUrl: process.env.ASM_BASE_URL!,
token: process.env.ASM_FEATURE_TOKEN!,
otel: { tracer: trace.getTracer('my-service', '1.0.0') },
})

Der durchgereichte Tracer hat höchste Priorität. Erfüllt das übergebene Objekt nicht die OpenTelemetry-Tracer-Schnittstelle (startActiveSpan), wirft das SDK schon beim Erzeugen des Clients einen Fehler.

Ohne eigenes Setup genügt eine Collector-Adresse über otel.otlpUrl. Das SDK bootet daraufhin lazy einen OTLP-HTTP-Exporter (BasicTracerProvider mit BatchSpanProcessor und OTLPTraceExporter). Dafür müssen die optionalen Pakete installiert sein:

Terminal-Fenster
pnpm add @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources
import { createAsmClient } from '@ai-systems-manager/sdk'
const asm = createAsmClient({
baseUrl: process.env.ASM_BASE_URL!,
token: process.env.ASM_FEATURE_TOKEN!,
otel: { otlpUrl: 'http://localhost:4318/v1/traces' },
})

otel.tracer hat Vorrang vor otel.otlpUrl. Sind die optionalen Pakete bei gesetztem otlpUrl nicht installierbar, wirft das SDK einen Fehler mit dem Hinweis, sie zu installieren oder stattdessen einen fertigen Tracer durchzureichen. Optional lassen sich über otel zusätzlich otlpHeaders (z. B. ein Authorization-Header für den Collector), serviceName (Default asm-sdk) und resourceAttributes setzen.

Das SDK emittiert pro asm.invoke()-Aufruf eine Span-Hierarchie nach den OpenTelemetry GenAI Semantic Conventions:

asm.invoke (Wurzel, INTERNAL) - ein Span pro asm.invoke()-Aufruf
├── asm.chat (INTERNAL) - pro Provider-Aufruf
│ └── ai.generateText.doGenerate (Child aus dem AI SDK 6)
└── asm.execute_tool (INTERNAL) - pro Tool-Aufruf

Die Spans tragen GenAI-Attribute wie gen_ai.operation.name, gen_ai.provider.name, gen_ai.request.model und gen_ai.response.finish_reasons. Hinzu kommen SDK-spezifische Attribute zu Routing und Schema-Retry, etwa asm.feature_id, asm.contract_version_id, asm.routing.variant, asm.routing.failover_reason, asm.routing.attempt_index und asm.schema_retry.count.

Die Spans tragen niemals Klartext. Prompts, Completions, Tool-Argumente und Tool-Ergebnisse erscheinen nicht in den Span-Attributen - stattdessen nur SHA-256-Hashes, etwa asm.tool.args.hash und asm.tool.definition_hash. Unkritische Werte wie Token-Zahlen und Provider-Metadaten werden über gen_ai.usage.*-Attribute publiziert (gen_ai.usage.input_tokens, gen_ai.usage.output_tokens).

Dieses Two-Lane-Modell entspricht dem Observability-Prinzip der Plattform: Metadaten sind sichtbar, Inhalte bleiben es nicht. Mehr dazu unter Prinzipien.

Unabhängig von der OpenTelemetry-Konfiguration meldet das SDK Usage-Events an die Plattform. Jedes Event trägt unter anderem tokensInput, tokensOutput, latencyMs, costUsd, statusCode und die Routing-Entscheidung (routingDecision mit jedem Versuch der Provider-Kette). Diese Daten erscheinen auf der Plattform unter anderem im Cost Dashboard.

Das SDK puffert die Events in einer In-Memory-FIFO (Default 1000, einstellbar über bufferMaxSize) und sendet sie an POST /sdk/v1/usage. Bei einem Plattform-Ausfall (HTTP 5xx, Netzfehler) bleiben die Events in der Queue und werden nach Recovery via Jittered-Reconnect gedrained - mit höchstens bufferMaxConcurrentDrains parallelen Sends (Default 5).

OptionDefaultWirkung
bufferMaxSize1000Obergrenze der In-Memory-FIFO. Ohne bufferDir wird beim Überlauf das älteste Event verworfen (mit Warn).
bufferMaxConcurrentDrains5Maximale Zahl paralleler Sends beim Drainen.
bufferDir(kein)Aktiviert die Disk-Persistenz (siehe unten).

Mit gesetztem bufferDir ist die Disk-Datei die Quelle der Wahrheit; Events werden dann nicht verworfen.

Optional persistiert das SDK die Usage-Events auf die Festplatte, damit sie einen Prozess-Crash überstehen. Aktiviert wird das über bufferDir:

import { createAsmClient } from '@ai-systems-manager/sdk'
const asm = createAsmClient({
baseUrl: process.env.ASM_BASE_URL!,
token: process.env.ASM_FEATURE_TOKEN!,
bufferDir: '/var/lib/asm-sdk/buffer',
bufferMaxConcurrentDrains: 5,
})
  • Format: Append-only JSONL in buffer.jsonl, plus ein .checkpoint-Sentinel mit dem Byte-Offset des zuletzt erfolgreich gesendeten Events. Nach einem Restart wird ab diesem Offset fortgesetzt.
  • Crash-Safety: Eine partielle letzte Zeile nach einem unerwarteten Shutdown wird beim nächsten Replay stillschweigend übersprungen (mit Warn).
  • Rotation: Ab etwa 10 MiB wird die aktive Datei nach buffer-<ISO>.jsonl.archived rotiert und eine neue aktive Datei geöffnet.
  • Read-Only-Dateisystem: Lässt sich das Verzeichnis nicht anlegen (z. B. EROFS oder EACCES), fällt das SDK auf den In-Memory-Mode zurück und loggt einen Warn. Kein Crash.

Das SDK kompiliert das Output-Schema des Contracts zu einem Laufzeit-Validator (Zod) und prüft das Modell-Ergebnis. Verletzt das Ergebnis das Schema, versucht das SDK denselben Provider erneut - bis zu schemaRetryBudget Mal.

OptionDefaultMaximumWirkung
schemaRetryBudget310Anzahl der Wiederholungen am selben Provider bei Schema-Verletzung. 0 schaltet den Schema-Retry ab (Einzelversuch).

Schema-Retry ist getrennt vom Provider-Failover: Eine Schema-Verletzung bedeutet, dass das Modell geantwortet hat, das Ergebnis aber nicht zum Schema passt - ein erneuter Versuch am selben Provider gibt ihm eine weitere Chance. Netz- oder HTTP-Fehler dagegen lösen den Wechsel auf den nächsten Provider aus. Bleibt das Ergebnis nach dem Budget weiter ungültig, wirft das SDK OUTPUT_SCHEMA_VIOLATION. Die finale Retry-Zahl erscheint als asm.schema_retry.count in den Spans und im Usage-Event. Mehr zu den Fehlercodes unter Fehlerbehandlung.

  • Wie das SDK Provider auswählt und bei Ausfall umschaltet, beschreibt Routing und Failover.
  • Welche Fehler das SDK wirft und wie man sie behandelt, steht unter Fehlerbehandlung.
  • Das Datenschutz-Modell hinter Two-Lane erklärt Prinzipien.