An AI trace records more than timings: prompt, output, model, token counts, cost, latency, tool arguments, retrieved chunk ids, and quality scores. Without it you cannot answer "why did this user get that answer?".
ts
const trace = obs.trace({ name: "support.reply", userId, sessionId });
const retrieval = trace.span({ name: "retrieve", input: q });
const chunks = await search(q);
retrieval.end({ output: chunks.map((c) => c.id), metadata: { topScore: chunks[0]?.score } });
const gen = trace.span({ name: "generate", model: "openai/gpt-5.6-sol" });
const res = await gateway.chat({ ... });
gen.end({ usage: res.usage, cost: price(res.usage), output: res.text });
trace.update({ tags: ["rag"], scores: { grounded: await scoreGrounding(res.text, chunks) } });Tools such as LangSmith, Langfuse, Phoenix, Helicone, and Weights & Biases provide this; OpenTelemetry GenAI semantic conventions let you keep AI spans in the same backend as the rest of your system. Redact prompt bodies before export when they may contain personal data, and sample heavy payloads rather than storing every one.
Exercise: instrument one endpoint, then answer three questions from the traces alone: p95 latency, cost per request, and the retrieval score distribution on runs the user rated bad.