Traceability vs. observability

When an analytics agent gives a wrong answer, the damage isn't the wrong number in a slide deck. It's the erosion of trust. A stakeholder who gets burned once by an agent's hallucinated insight will stop trusting agent-generated analysis entirely, and they'll be right to. The core problem is accountability: without instrumentation, you have no way to know what the agent did, why it did it, or whether the answer is defensible.

The harder truth: without observability, you often won't even know the answer was wrong. A plausible-sounding wrong answer is the most dangerous kind. If an agent says churn spiked because of a pricing change, and the real cause was a data quality issue (rows duplicated during an ETL migration) nobody questions it until weeks later when the pricing rollback doesn't move the needle. By then, a bad decision has already been made.

Traceability is what prevents this. A trace file for that investigation would show exactly which tables the agent queried, whether it validated row counts or checked for duplicates, and where it jumped from correlation to causation. In this example, the trace would reveal that the agent never ran a data quality check on the source table. It went straight from "churn is up" to "pricing is the cause" without validating the underlying data. That's a reviewable, fixable gap.

Observability is the broader view. It tells you how your agents are performing across many investigations. Are they getting faster? Producing fewer errors? Which question types are they struggling with? You can't improve what you can't measure.

These are related but distinct. Build traceability first. Observability is downstream of it: once you have structured trace files, most observability metrics fall out naturally. If you've already built specialized analytics agents, adding traceability is the natural next step. And if you're using BigQuery, the job label patterns below build on the connection setup covered in the BigQuery guide.

Trace files

The foundation of traceability is a structured log that the agent writes as it works. Make it a hard requirement in every agent's instructions, not an optional add-on.

CLAUDE.md /traceability requirements
## Traceability
Every investigation MUST produce a trace file at:
  ./traces/{timestamp}-{slug}.json

The trace file must contain:
{
  "question": "the original user question",
  "started_at": "ISO timestamp",
  "completed_at": "ISO timestamp",
  "steps": [
    {
      "step": 1,
      "action": "query | hypothesis | validation | summary",
      "description": "what this step is doing and why",
      "sql": "the query if applicable",
      "result_summary": "key numbers extracted from the result",
      "finding": "what was learned from this step",
      "next_action_reason": "why the next step was chosen"
    }
  ],
  "final_answer": "the answer presented to the user",
  "confidence": "high | medium | low",
  "caveats": ["list of known limitations or assumptions"],
  "data_freshness": "most recent date in the queried data"
}

This trace file is often more valuable than the answer itself. It lets you:

The next_action_reason field deserves attention. It forces the agent to articulate why it's doing what it's doing, which surfaces flawed reasoning at the step level rather than only when the final answer is wrong.

But the trace file is a summary of what happened. For full reproducibility, you need the actual artifacts the agent produced along the way.

Saving artifacts to disk

A trace file tells you what the agent did. The artifacts tell you exactly how. Every query, every intermediate output, every transformation script the agent wrote during an investigation should be saved to disk as a first-class artifact. This is the single most important traceability practice: if you can't replay an investigation from its saved artifacts alone, your traceability has gaps.

Instruct the agent to write each SQL query to its own file, named by step number. Save query results as CSVs or JSON. If the agent generates Python scripts, pandas transformations, or Jupyter notebooks as part of the analysis, those go to disk too. The goal is a self-contained directory that fully reconstructs the investigation without needing to re-run anything.

CLAUDE.md /artifact requirements
## Artifacts
Every investigation MUST save all artifacts to:
  ./traces/{timestamp}-{slug}/

Directory structure:
  trace.json                    # the trace file
  queries/
    step-01-revenue-by-segment.sql
    step-02-churn-by-tier.sql
    step-03-validation-check.sql
  results/
    step-01-revenue-by-segment.csv
    step-02-churn-by-tier.csv
  scripts/
    step-04-cohort-transform.py  # if pandas/python was used
    step-05-forecast.ipynb       # if a notebook was generated
  outputs/
    final-summary.md             # the delivered answer
    charts/                      # any generated visualizations

Rules:
- Save every SQL query to disk BEFORE executing it
- Save query results as CSV (truncate to 1000 rows if larger)
- Save any Python/R scripts, notebooks, or transformation code
- Save the final output in the format delivered to the user
- Never delete artifacts from a completed investigation

This approach has several advantages over trace-file-only logging. You can re-run any individual query to verify it still produces the same result. You can diff the SQL files across investigations to see how the agent's query strategy evolved. When a stakeholder questions a number, you can point them to the exact CSV and the exact query that produced it. And when the agent generates Python scripts or notebooks for statistical analysis, forecasting, or data transformations that go beyond SQL, those scripts become reviewable, testable code rather than ephemeral computations lost to the context window.

The disk footprint is small. A typical investigation produces 5 to 15 query files, a handful of CSVs, and occasionally a script or two. Measured in kilobytes, not gigabytes. The cost of saving everything is negligible; the cost of not having it when you need to debug a wrong answer is significant.

Query tagging for cost and usage monitoring

Saving queries to disk gives you full traceability. But for cost monitoring and usage observability across many investigations, you also need instrumentation at the warehouse level. BigQuery job labels let you attribute every query to the agent and investigation that ran it, which is essential for tracking spend.

CLAUDE.md /query labeling
## Query labels
Every query must include these labels:
  --label=agent:{agent-type}        # e.g. revenue-analyst
  --label=trace:{trace-id}          # e.g. 20260407-q1-revenue-drop
  --label=step:{step-number}        # e.g. 3

The trace-id must match the filename of the trace file for
this investigation.
Terminal / example labeled query
bq query --use_legacy_sql=false \
  --label=agent:revenue-analyst \
  --label=trace:20260407-q1-revenue-drop \
  --label=step:3 \
  --maximum_bytes_billed=2000000000 \
  'SELECT segment, SUM(amount_cents)/100 as revenue
   FROM `my-project.revenue.invoices`
   WHERE date BETWEEN "2026-01-01" AND "2026-03-31"
   GROUP BY segment ORDER BY revenue DESC'

Once queries are labeled, you can query INFORMATION_SCHEMA.JOBS filtered by trace ID to see every query the agent ran for a specific investigation, with bytes scanned and execution time. This closes the loop between the saved artifacts on disk (the exact queries and results) and the warehouse's own record of what executed and what it cost.

Git trace history

With trace files, saved artifacts, and query labels in place, you have the raw material. The next question is where to store it. Committing the entire investigation directory to a git repository gives you a versioned history of every investigation with no additional infrastructure.

Terminal
# After each investigation, commit the full artifact directory
git add traces/
git commit -m "trace: Q1 revenue variance investigation"

This gives you git log traces/ as an audit trail and git diff to compare how the agent approached similar questions over time. You can diff the SQL files between two investigations of the same metric to see whether the agent's query strategy improved. You can review the Python scripts it generated and catch issues like incorrect join logic or missing null handling in transformations. The artifact directory makes every investigation a reviewable, self-contained package.

The review angle matters. A PR review on an investigation's artifacts is a surprisingly effective way to catch systematic errors before they become patterns. Over time, a team can develop shared standards for what good agent investigations look like by reviewing traces the same way they review code. Did the agent validate data freshness before analyzing? Did it check for obvious data quality issues? Did it consider alternative explanations? Did the Python transformation handle edge cases? These become reviewable expectations, not just hopes.

Observability metrics

Traceability gives you depth on individual investigations. You also need breadth: aggregate signals that tell you how the system is performing overall. These five metrics cover the most important dimensions.

Observability framework
Five metrics worth tracking
1
Query count per investigation
How many queries does the agent run? Trending upward suggests inefficient exploration or harder questions. More than 20 queries per investigation is worth investigating itself.
2
Bytes scanned
Total data scanned per investigation. Directly tied to cost. Compare across agent types and question categories to find expensive patterns, usually missing date filters or full-table scans.
3
Time to answer
Wall-clock time from question to final answer. Breakdown by agent type and question tier reveals which domains are fast and which are slow.
4
Error rate
How often does the agent produce a wrong answer, hit a permission error, or fail to complete? Track by agent type. A spike usually means a schema change or permission revocation.
5
Confidence calibration
When the agent says "high confidence," is it actually right more often than when it says "low confidence"? Comparing self-reported confidence against validated outcomes reveals whether the agent's uncertainty is meaningful.

BigQuery native monitoring

Knowing what to measure is one thing; actually measuring it without building a custom observability platform is another. The good news is you don't need a separate observability stack. BigQuery's INFORMATION_SCHEMA views capture everything you need about query execution. Combined with the job labels from your agents, this gives you per-agent cost, latency, and error rate from data BigQuery already collects.

SQL /agent cost and performance
-- Agent cost and performance over the last 30 days
SELECT
  (SELECT l.value FROM UNNEST(labels) l WHERE l.key = 'agent') as agent_type,
  COUNT(*) as total_queries,
  SUM(total_bytes_processed) / POW(1024, 3) as total_gb_scanned,
  SUM(total_bytes_processed) / POW(1024, 4) * 6.25 as estimated_cost_usd,
  AVG(TIMESTAMP_DIFF(end_time, start_time, MILLISECOND)) as avg_query_ms,
  COUNTIF(error_result IS NOT NULL) as error_count
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND EXISTS (SELECT 1 FROM UNNEST(labels) l WHERE l.key = 'agent')
GROUP BY agent_type
ORDER BY total_gb_scanned DESC

If your agents write structured trace files, load them into BigQuery to add the investigation-level metrics: step counts, confidence scores, question categories.

SQL /investigation metrics from trace files
-- Average steps and duration per investigation
SELECT
  COUNT(*) as investigations,
  AVG(JSON_ARRAY_LENGTH(JSON_QUERY(trace, '$.steps'))) as avg_steps,
  AVG(TIMESTAMP_DIFF(
    PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%S', JSON_VALUE(trace, '$.completed_at')),
    PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%S', JSON_VALUE(trace, '$.started_at')),
    SECOND
  )) as avg_duration_seconds,
  COUNTIF(JSON_VALUE(trace, '$.confidence') = 'high') as high_confidence_count
FROM `my-project.observability.agent_traces`
WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)

Schedule both queries as daily jobs and route the results to a simple dashboard or a Slack notification. This is enough to catch most problems before they affect stakeholders.

Alerting

Dashboards are useful for periodic review, but the failure modes that matter most need to interrupt you. Four alerts cover the failure modes that actually happen:

SQL /alert query — runaway investigations
-- Flag investigations with more than 25 queries in the last 24h
SELECT
  JSON_VALUE(trace, '$.question') as question,
  JSON_ARRAY_LENGTH(JSON_QUERY(trace, '$.steps')) as step_count,
  JSON_VALUE(trace, '$.started_at') as started_at
FROM `my-project.observability.agent_traces`
WHERE date = CURRENT_DATE()
  AND JSON_ARRAY_LENGTH(JSON_QUERY(trace, '$.steps')) > 25
ORDER BY step_count DESC

Not all of these alerts deserve the same urgency. Cost spikes and runaway queries need immediate attention because they represent active, escalating problems. Error rate increases are important but can usually wait for a morning review unless the rate is extreme. Stale data warnings should be batched into a daily digest. If you alert on everything with the same priority, you'll get alert fatigue, and a team that ignores alerts is worse off than a team with no alerts at all. Start with fewer alerts at higher thresholds and tighten them as you learn what normal looks like for your agents.

Building an observability practice

Setting up trace files, query labels, and a few alerts is the starting line, not the finish. Observability for analytics agents is an ongoing practice, not a one-time configuration.

The trace files and metrics you collect become the basis for improving the agent over time. After a few weeks of accumulated traces, patterns emerge. You'll see which types of questions the agent handles well and which it struggles with. You'll notice recurring failure modes: the agent consistently fails to check data freshness on one particular dataset, or it over-indexes on recent data when asked about trends. These patterns inform specific, targeted improvements to the agent's instructions, its available tools, or its validation steps.

Observability also pairs naturally with context management. The context you give an agent determines what it can do; observability tells you what it actually did. If your traces keep showing the agent making avoidable mistakes, the fix is often better context (more explicit instructions, better schema documentation, or tighter guardrails) rather than more monitoring.

If you're starting from scratch, the specialized agents guide covers the foundations: how to scope an agent's domain, structure its instructions, and connect it to your data. Add traceability from the beginning. It's far easier to instrument an agent on day one than to retrofit it after it's already running in production and people depend on its outputs.