Applied AI: Observability

Observability

Information in this post reflects publicly available sources as of October 18, 2026.

A customer writes in, angry. Your support assistant told them their refund had been approved. It had not. They want to know why, and so does your manager.

You open the logs. They show the request arrived at 14:02, returned HTTP 200, and took 6.8 seconds, and nothing more. You cannot see what the model was asked, which documents it retrieved, which tools it called, what those tools returned, or which version of the prompt was live that afternoon. You try the same question yourself and get a correct answer, which proves nothing.

Traditional logs record that a request happened. AI features need a record of why the answer came out the way it did. Building that record is observability for AI applications, and without it every bad answer is a mystery you cannot solve.


Why ordinary monitoring is not enough

Conventional monitoring is built around a clear idea of failure: errors, timeouts, crashes. AI features mostly fail in a different way. The request succeeds, the latency is fine, the status code is 200, and the answer is wrong. Nothing in a standard dashboard turns red.

Three more properties make it harder. Outputs are non-deterministic, so replaying a request later may not reproduce the problem. A single answer often involves many steps, such as several model calls, a retrieval, and a few tool calls, and the mistake can start in any of them. And cost varies per request, so a change in behavior can show up first as a change in spending.

The answer is to capture, for each request, a structured record of every step the system took and what each step saw and produced. That record is a trace.


How it works

Traces and spans

The idea comes from distributed tracing, which most backend engineers already know. A trace represents one request from start to finish. It is made of spans, one for each unit of work, nested to show which step called which. For an AI feature, the spans are model calls, retrievals, tool calls, and agent steps, each carrying its inputs, outputs, token counts, and timing.

ONE TRACE, SIX SPANS 0s 1s 2s 3s 4s 5s 6s 7s invoke_agent 6.8 s total · 13.7k in, 1.1k out · $0.06 chat · plan 3.2k in · 120 out retrieval · policies 5 chunks, one from 2023 policy chat · decide 4.4k in · 90 out execute_tool · lookup refund status: pending chat · answer 6.1k in · 900 out The waterfall shows where the time and tokens went. The retrieval span shows where the answer went wrong: the model saw an outdated policy that said refunds are auto-approved, and trusted it over the tool result.

With this trace, the refund mystery takes minutes instead of days. The tool correctly reported the refund as pending. But retrieval also returned a chunk from a 2023 policy, back when refunds under $50 were approved automatically, and the model trusted the policy over the tool. The fix belongs in the retrieval index, not the prompt, and you would never have found it from a status code.

The waterfall also answers questions nobody asked yet. Most of the 6.8 seconds went to the final answer, which generated 900 tokens for a reply that needed about 150. That is a latency problem and a cost problem, visible at a glance.

What to record

Each span should capture enough to understand and reproduce that step. In practice, that means:

FieldWhy it matters
Model and parametersBehavior changes when the model version, temperature, or reasoning effort changes
Prompt template and versionLets you connect a change in quality to the prompt change that caused it
Input messages and outputThe only way to see what the model actually saw and said
Finish reasonSeparates complete answers from truncated ones and refusals
Token counts and costAttributes spending to features, users, and steps
Tool calls, arguments, and resultsShows whether a tool failed or the model misused it
Retrieved document IDsShows whether the right context reached the model
User feedback, linked to the traceConnects a complaint to the exact request behind it

The prompt version is the field teams most often forget, and the one they miss most. Without it, a quality drop on Tuesday cannot be tied to the prompt change deployed on Tuesday morning.

The cleanest fix is to treat prompts as versioned artifacts rather than strings buried in code. Store each template with an identifier and version, render it at request time, and record both on the span. Many observability platforms include prompt management for exactly this reason: the same tool that shows a quality dip can show which prompt version was live and what changed in it.

The OpenTelemetry conventions

You do not need to invent field names. OpenTelemetry, the open standard most backend tracing already uses, defines semantic conventions for generative AI. Spans carry attributes such as gen_ai.operation.name, gen_ai.request.model, gen_ai.usage.input_tokens, and gen_ai.response.finish_reasons. Agent runs are modeled as a tree, with an invoke_agent span as the parent of chat and execute_tool spans, exactly as in the waterfall above.

A manually instrumented model call looks like this:

from opentelemetry import trace

tracer = trace.get_tracer("support-assistant")

def call_model(messages, model, prompt_version):
    with tracer.start_as_current_span(f"chat {model}") as span:
        span.set_attribute("gen_ai.operation.name", "chat")
        span.set_attribute("gen_ai.provider.name", "openai")
        span.set_attribute("gen_ai.request.model", model)
        span.set_attribute("app.prompt.version", prompt_version)   # your own attribute

        response = client.chat.completions.create(model=model, messages=messages)

        span.set_attribute("gen_ai.response.model", response.model)
        span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)
        span.set_attribute("gen_ai.usage.output_tokens", response.usage.completion_tokens)
        span.set_attribute("gen_ai.response.finish_reasons", [response.choices[0].finish_reason])
        return response

Because this is ordinary OpenTelemetry, the span joins the same trace as your web request, database queries, and downstream services. You rarely need to write it by hand: instrumentation libraries such as OpenLLMetry and OpenInference patch the common SDKs and frameworks to emit these spans automatically, and agent frameworks increasingly emit traces out of the box.

Two caveats apply. As of mid-2026, every generative AI convention in OpenTelemetry is still marked as in development, so attribute names can change between releases. And capturing the actual prompt and response content is opt-in by design, for reasons covered under what goes wrong.

From traces to signals

Individual traces explain individual failures. To notice failures in the first place, you need aggregate signals built from those traces, and they come in three layers.

Quality: is it right? Judge scores on sampled traces, thumbs-down rate, escalations to humans Behavior: is it acting normally? Truncations and refusals, tool error rate, steps per task, retrieval results Health: is it up and affordable? Latency p50 and p95, errors and rate limits, cost per feature closer to what users feel easier to measure Most teams stop at the bottom layer. The failures users notice live in the top two.

Health signals are the familiar ones: latency, error rates, rate limiting, and cost per feature. They catch outages and runaway spending. Most teams already have them.

Behavior signals are specific to AI and cheap to compute from trace data.

A rising share of responses that stop because they hit the token limit means answers are being cut off. A jump in refusals often follows a prompt or model change. More steps per agent task suggests the agent is struggling, and retrieval that suddenly returns nothing points to an indexing problem. None of these show up as errors.

Quality signals are the hardest and the most valuable. Run an LLM judge, built and calibrated as in the evals post, on a sample of production traces. Track thumbs-down rates and how often conversations escalate to a human. When any of these moves, the traces behind it tell you why.

Alert on change, not just on thresholds. A jump in truncated responses right after a deploy, cost per request doubling overnight, a spike in refusals after a model upgrade, or a drop in judge scores for one category are all worth a page. Each of them usually traces back to a specific change, and catching it within hours rather than weeks keeps the damage small.

From a trace to a fix

The payoff comes when observability connects to the rest of the development loop. A complaint leads to a trace, the trace leads to a root cause, and the root cause becomes a permanent test.

Thumbs down linked to trace ID Open the trace every step, every input Root cause 2023 policy in retrieval Add an eval case this exact question Fix the index drop superseded documents Verify eval passes, signal recovers Without the trace, the loop stops at the first box. With it, one complaint fixes a whole class of bugs.

Notice where the eval case comes in: before the fix. Writing the test first proves it catches the bug, and then proves the fix works. That is the same flywheel from the evals post, with traces as its main source of new cases.


When to invest, and how much

Start on day one, even in a prototype. During development, capture full traces of everything: they are the fastest way to understand what a model or agent is actually doing, and reading traces is how most teams discover their first real bugs. It costs almost nothing at prototype volume.

Keep reading traces after launch, too. A short weekly review of a random handful of production traces, plus the ones with negative feedback, surfaces problems no metric was designed to catch: an agent taking a strange detour, a tool returning far more data than needed, or users asking for something the feature was never built to do.

In production, scale the detail to the risk. Capture metadata such as tokens, latency, model, prompt version, and finish reason for every request. Capture full content for a sample of traffic, for every error, and for every request that gets negative feedback. Add quality signals once you have enough traffic for the numbers to mean something.

Agents need tracing more than anything else. A single-call feature can sometimes be debugged from its input and output. A ten-step agent, or the multi-agent systems from the earlier post, cannot be debugged at all without a trace that links every step to its parent task.


What goes wrong

Traces leak sensitive data. Prompts contain whatever users type and whatever your tools return: names, addresses, account numbers, sometimes credentials. Storing full content creates a second copy of sensitive data, often with weaker access controls than the primary system.

Redact or mask sensitive fields before export, restrict who can view raw content, and set retention limits. This is why content capture is opt-in in the OpenTelemetry conventions.

Sampling misses the failures. Keeping a random 1% of traces means the one that matters is usually gone. Sample with intent: keep every trace with an error, a refusal, a truncation, negative feedback, or an unusual cost, and sample the rest.

Feedback is not linked to traces. A thumbs-down stored in a product analytics tool, with no trace ID, tells you a user was unhappy and nothing about why. Pass the trace ID to the front end and attach it to every feedback event.

Dashboards watch only health. Latency and error charts stay green while answers get worse. Add at least one behavior signal and one quality signal per feature, and alert on sudden changes, not only on thresholds.

Replays do not reproduce. Re-running a traced request can produce a different answer, because outputs vary and the retrieved documents or tool results may have changed since. Debug from what the trace recorded, not from a fresh run, and store tool results and retrieved content in the trace for exactly this reason.


Cost and complexity

AI traces are large. A single agent request with full prompts, retrieved documents, and tool results can easily reach 20 KB. At a million requests a day, full capture means about 20 GB a day, or 600 GB a month, plus the cost of indexing and searching it.

Sampling changes that sharply. Keeping about 1 KB of metadata for every request and full content for 10% of them comes to about 3 GB a day, roughly 90 GB a month, while still keeping every error and every complaint in full. Quality signals add model costs too: running a judge on 1% of traffic is a small addition to the bill, while judging everything can rival the cost of the feature itself.

The integration work is modest if you build on standards. OpenTelemetry instrumentation libraries cover the major SDKs, and most observability platforms accept OpenTelemetry data, so the instrumentation does not lock you into a vendor.


The current landscape

On the standards side, the OpenTelemetry generative AI semantic conventions define spans, attributes, and metrics for model calls, tool calls, and agents, though they remain in development status as of mid-2026. OpenLLMetry from Traceloop and OpenInference from Arize provide instrumentation for the common SDKs and frameworks, and the OpenAI Agents SDK, among other frameworks, includes built-in tracing.

For storage and analysis, Langfuse is open source under the MIT license for its core and can be self-hosted; ClickHouse acquired it in January 2026 and said it would remain open source. Arize Phoenix is source-available and OpenTelemetry-native, and Helicone, open source under Apache 2.0, works as a gateway that logs traffic when you change your API base URL. LangSmith, Braintrust, and W&B Weave combine tracing with evals, and Datadog LLM Observability adds AI spans to existing Datadog dashboards.

Most of these overlap with the eval platforms from the evals post, and that convergence is the clearest trend. Tracing, evaluation, and datasets are becoming one workflow, because the traces you collect in production are the best source of the test cases you run before the next release.


Summary

AI features fail quietly. The request succeeds, the dashboard stays green, and the answer is wrong. Observability for AI means recording not just that a request happened, but every step it took, what each step saw, and what each step produced, so that any bad answer can be traced back to its cause.

Build it early and on open standards. Capture traces with prompt versions and token counts, link user feedback to them, watch behavior and quality alongside health, and turn every investigated failure into an eval case. Then a complaint stops being a mystery and becomes the start of a fix that stays fixed.


Part of the Applied AI series: AI from the builder's side.



×