Judgment is now publicly available.Get started

Searching a billion tokens of agent data

How our data agent uses evals-as-indexes for better, faster, cheaper search.

Andrew Li, Abi Rao10 min read
Unlabeled trace corpusEvery trace looks the sameIndexed by evalsEvery trace carries its eval labelsUserfrustratedcorrectedabandonedAgentrepeatedunresolvedhallucinatedTooltool errortimeoutwrong argsOutcomeescalatedthumbs downchurned

Drag the slider to see how evals turn raw traces into searchable indexes.

Searching through agent traces is a new and hard problem

Most agent failures don’t come with a big flashing error. You usually find them by accident, while digging into how users interact with your agent, when you notice it did something unexpected. Then comes the harder question: how often has this happened? Answering it means searching through billions of tokens of production data.

Large-scale data systems have long turned vast amounts of raw data into useful signals. Meta’s ads platform, for example, used tens of thousands of engineered features (e.g. recently clicked ads and page-visit counts) to personalize recommendations. At its core, the recommendation system turns vast amounts of user activity into better insights about people's preferences.

Long-horizon agents now produce data at a much larger scale. Their traces do contain structured events, such as searches, page visits and tool calls, but much of what we care about lives in free-form text across those events. A single run can produce thousands of model calls, tool invocations and intermediate decisions, most of them unstructured text. Whether a run actually succeeded often depends on context spread across many spans: a request the agent quietly dropped, a correction from the user, or a tool call that “succeeded” but did the wrong thing. However, the infrastructure and best practices for making sense of this data are still developing. Reading traces by hand helps you understand your agent’s behavior and discover what to look for. But finding every instance of that behavior across billions of tokens requires a more scalable approach.

The natural next step is a data agent: an agent that answers questions about your production traffic by writing SQL over your traces, reading the relevant spans, and citing the evidence it finds. But pointed at raw traces alone, it hits the same wall we do. The behaviors we care about are often latent, so keyword search can’t reliably find them, and the data agent has to find and evaluate them from scratch on every question.

Luckily, LLMs have made it much easier to semantically parse the traces we’re storing. Compared to earlier BERT-style models, LLMs are more capable of handling arbitrary, complex rubrics without fine-tuning. That lets us break each run down along multiple semantic dimensions:

  • Was the user frustrated?
  • Did the agent follow the specified instructions?
  • What was the action’s outcome?

Each of these is an eval, and many teams already run evals like these as online monitoring, to track quality and catch regressions in production. But the same results can also serve as an index, a column you can filter and search on. That makes your data much easier to understand, and makes it far more likely you’ll catch what’s going wrong.

Evals turn agent behavior intosearchable columnsRecommendation dataFeatures describe user activity and interests.UserClickedan ad?Purchasedrecently?Interestedin sports?user_001YesNoYesuser_002NoYesNouser_003YesYesYesuser_004NoNoYesAgent dataEvals describe behavior within interactions.TraceUserfrustrated?Followedinstructions?Outcometrace_001YesNoFailedtrace_002NoYesCompletedtrace_003NoYesPendingtrace_004NoYesProposed
Features help models rank recommendations; evaluations help data agents find relevant evidence faster.

Why search needs these evals

Without evals, a data agent typically falls back on one of two approaches:

  • Read traces one by one. With no index to narrow the search, it has to inspect trace after trace. It’s slow, and for a data agent it fills the context window with irrelevant results. As the context grows, the agent suffers from context rot, and the evidence it found earlier gets truncated or compacted away, so the search gets worse the longer it runs.
  • Search by keyword. SQL LIKE or grep only finds the words it thinks to try, and some questions have no words to search for. Take “did the agent follow the policy it was given?” It may not know what each agent’s policy says, and breaking it doesn’t leave any particular word behind. To answer, it have to read the policy, read what the agent did, and compare the two.
    • What about vector search? Vector search can find relevant passages even when their wording differs from the query, and a reranker can help prioritize the results. But answering questions like “did the agent repeat a mistake after being corrected?” still requires evaluating the evidence, sometimes across multiple spans. Evals-as-indexes do that work ahead of time for behaviors you already know you want to track. Subsequent searches can filter the stored results and inspect the supporting evidence, rather than evaluate those behaviors from scratch.

Say you run a sales agent and want to find requests it did not complete. Consider the query: “Find email requests that were not completed.”

For this example, we use three evals, some run as standard LLM-as-a-judge and some with Jev:

  • requested_action: what did the user ask the agent to do? For a sales agent: send_email, update_pipeline, research_account, schedule_meeting.
  • action_outcome: what actually happened to it? completed, partially_completed, pending_approval, not_done or failed.
  • failure_recovery: if something failed, did a later attempt fix it? recovered, partially_recovered or unresolved.

Evals can see an entire trace or an individual span. Their results are stored in telemetry.scores, alongside the traces and spans they describe, with the eval name (judge), its result (label) and an explanation (reason). Each result links to the relevant trace and supporting span. In this example, the evals assess whether the email request was completed at the trace level and cite supporting spans within that trace. We assume at most one result per eval per trace.

Hover, focus, or tap a SQL block to explore it. Related blocks highlight in both queries.

Without evals-as-indexes

-- Find evidence via grep-style text matching
SELECT
  trace_id,
  span_id,
  span_name,
  substringUTF8(input, 1, 500) AS input_preview,
  substringUTF8(output, 1, 700) AS output_preview
FROM telemetry.spans
WHERE
  span_name IN ('send_email', 'save_email_draft')
  OR (
    span_name = 'chat_completions'
    AND (
      output ILIKE '%not been sent%'
      OR output ILIKE '%haven''t sent%'
      OR output ILIKE '%did not send%'
      OR output ILIKE '%nothing was sent%'
      OR output ILIKE '%saved a draft%'
      OR output ILIKE '%not yet%'
    )
  )
ORDER BY trace_id, started_at;

Read the evidence

Return trace and span IDs, tool names, and shortened input and output previews. The agent still needs to inspect these candidates.

With evals-as-indexes

-- Find evidence by filtering across three evals
SELECT
  trace_id,
  groupUniqArray(span_id) AS evidence_span_ids,
  anyIf(label, judge = 'requested_action') AS action,
  anyIf(label, judge = 'action_outcome') AS outcome,
  anyIf(reason, judge = 'action_outcome') AS reason,
  anyIf(label, judge = 'failure_recovery') AS recovery
FROM telemetry.scores
WHERE judge IN (
  'requested_action', 'action_outcome', 'failure_recovery'
)
GROUP BY trace_id
HAVING action = 'send_email'
  AND outcome IN (
    'not_done', 'failed',
    'pending_approval', 'partially_completed'
  )
  AND coalesce(recovery, '') != 'recovered';

Read the evaluated evidence

Return each trace ID and collect its supporting span IDs so the agent can inspect the original evidence.

Swipe sideways to compare both queries.

The raw query can find the right trace even when the sales agent tells the user “Done, the follow-up is ready.” A save_email_draft receipt with sent_at: null tells us the message was still a draft at that point. The search can miss the evidence that tells us whether the email was ever sent. A later delivery confirmation, for example, might appear in a span that matches neither the tool names nor the phrases in the query. With evals-as-indexes, it can filter for requests labeled not_done, exclude those labeled recovered, and inspect the supporting spans.

Using evals-as-indexes helps the data agent find relevant evidence more accurately, finish faster, and consume fewer input tokens. The search costs below exclude the upfront cost of generating the evals, which can be reused across subsequent searches.

The walkthrough below uses a simplified SQL schema to make the Sonnet 5.5 run easier to follow.

Indexes narrow the search earlierFind email requests that were notcompletedWithout evals-as-indexes#1 Find mentions of unsent emailSELECT trace_id, span_id, substringUTF8(output, 1, 700) AS output_previewFROM telemetry.spansWHERE output ILIKE '%not been sent%'ORDER BY trace_id, started_atLIMIT 20;Result: Candidate: demo_trace_01Key call: Search wording for candidate evidence1 / 50 search callsCall 1: Search wording for candidate evidenceCall 2Call 3Call 4Call 5Call 6Call 7Call 8Call 9Call 10: Receipt shows the email was not sentCall 11: Later send succeeded: exclude candidateCall 12Call 13Call 14Call 15Call 16Call 17Call 18Call 19Call 20Call 21Call 22Call 23Call 24Call 25Call 26Call 27Call 28Call 29Call 30Call 31Call 32Call 33Call 34Call 35Call 36Call 37Call 38Call 39Call 40Call 41Call 42Call 43Call 44Call 45Call 46Call 47Call 48Call 49Call 50With evals-as-indexes#1 Find traces labeled send_emailSELECT trace_id, span_id, labelFROM telemetry.scoresWHERE judge = 'requested_action' AND label = 'send_email';Result: Email trace IDs → outcome filterRoutine search / evidence inspection1 / 24 search callsCall 1Call 2: Eval labels narrow the candidate tracesCall 3: Check recovery before reading raw spansCall 4Call 5: Receipt shows the email was not sentCall 6: Later send succeeded: exclude candidateCall 7Call 8Call 9Call 10Call 11Call 12Call 13Call 14Call 15Call 16Call 17Call 18Call 19Call 20Call 21Call 22Call 23Call 24
Call 1 of 50

Measured results (Sonnet 5.5)

MetricWithout indexesWith indexes
Search calls5024
Reference traces found2 of 9 (22%)7 of 9 (78%)
Search time8.1 min2.3 min
Input tokens4.3M0.6M
Answer qualityWeighted rubric71.7%80.0%

Benchmarking

To measure whether evals-as-indexes actually help, we built a search benchmark from perturbed internal traffic: 4K+ long-horizon agent traces (1B+ tokens), with 50+ search questions. Each question includes a reference answer, human-reviewed evidence trace IDs, and a rubric that checks whether the agent correctly analyzes the evidence.

We built it with an AutoBenchmark-style loop:

  1. Generate questions. LLMs role-played people who use our platform (PMs, agent engineers, CTOs) to write realistic sets of questions grounded in the agent trace structure.
  2. Collect evidence. A research agent searched the traces to assemble each question’s answer, evidence IDs and rubric, which humans then reviewed.
  3. Test with solver agents. We ran agents of varying strength on every question and rewrote or dropped any that were too vague or had valid alternate answers.
  4. Add adversarial distractors. We inserted near-miss traces (for example, a failure the agent later recovered from) and follow-up turns designed to mislead a search agent that doesn’t verify its evidence.

We measure evidence precision and recall against the reference IDs and grade answer quality with the rubric. We ran every model with and without evals-as-indexes.

Example questionWhich meeting briefs could mislead theperson preparing for the meeting?Compare what the actual brief says andwhat the agent outputs.VQTMOriginal briefThe customer asked for a price comparison.Agent outputThe customer chose the team plan.Why it could misleadThe agent turned a request for pricing into apurchase decision.HXRPOriginal briefThe customer confirmed receiving the samplereport.Agent outputThe sample report is still outstanding.Why it could misleadThe agent repeated an earlier status after thecustomer confirmed receipt.ZKFWOriginal briefThe latest invitation asks for a review ofpilot results.Agent outputPrepare another training walkthrough.Why it could misleadThe agent carried last month’s agenda into ameeting with a different purpose.Answer qualityDoes the answer identify what changedbetween the original brief and the agent’soutput?Does it use those details to distinguishan unsupported assumption from an outdatedclaim, and limit its conclusions to thebriefs reviewed?…
Adapted from a benchmark question. The excerpts and trace IDs are fictional.

Results

Our index reuses 18 online monitoring evals, including requested_action, action_outcome and failure_recovery, for a total of 40,482 evals across the dataset. Each trace is first parsed programmatically to extract the evidence each eval needs, then scored with MiniMax M3.1 Flash and Jev, for a total cost of about $60.

Averaging each of the seven models’ relative changes, indexes reduced input tokens by 23.9%, search time by 21.4%, and estimated search costs by 20.8%. Answer quality improved by 22.7%.

Answer quality versus search cost40%60%80%$0.2$1$5Answer qualityEstimated cost / search (USD, log scale)Baseline (no index)IndexesDeepSeek FlashOpus 5.5GPT-6 SolGPT-6 AstraSonnet 5.5Kimi K3GLM 5.3

In addition to these results, several open-source models saw substantial gains in recall and precision, most of the time because the evals had already surfaced cases the models were less likely to find by searching the raw text. However, stronger retrieval did not always translate into stronger analysis. Some open-source models appeared less likely to challenge the eval results, potentially making them more susceptible to incorrect or incomplete indexes. Across all seven models, recall increased by 54.8%, precision by 43.0%, and SQL calls decreased by 11.8%, averaging each model’s relative change.

Without vs. with evals-as-indexes:
0%25%50%75%100%GPT-6 Astra28.2%46.9% +66%GPT-6 Sol19.0%32.5% +71%Opus 5.539.0%38.7% −1%Sonnet 5.524.6%36.1% +47%Kimi K348.2%85.6% +78%GLM 5.333.1%47.2% +43%DeepSeek Flash23.9%43.3% +81%
Without indexWith evals-as-indexes
GPT-6 Astra
Recall
28.2% → 46.9%
Precision
28.9% → 39.8%
F1
28.5% → 43.1%
Cost per search
$7.696 → $5.541
SQL calls per search
59.4 → 49.3
Time per search
11.2 min → 9.8 min
Input tokens per search
4.33M → 2.73M
GPT-6 Sol
Recall
19.0% → 32.5%
Precision
21.5% → 36.5%
F1
20.2% → 34.4%
Cost per search
$1.665 → $1.264
SQL calls per search
62.2 → 52.5
Time per search
10.6 min → 4.8 min
Input tokens per search
5.21M → 3.62M
Opus 5.5
Recall
39.0% → 38.7%
Precision
26.3% → 28.2%
F1
31.4% → 32.6%
Cost per search
$2.552 → $1.834
SQL calls per search
47.1 → 36.2
Time per search
11.8 min → 7.1 min
Input tokens per search
4.95M → 3.13M
Sonnet 5.5
Recall
24.6% → 36.1%
Precision
23.1% → 35.3%
F1
23.8% → 35.7%
Cost per search
$0.719 → $0.438
SQL calls per search
40.1 → 26.5
Time per search
4.9 min → 3.3 min
Input tokens per search
2.04M → 1.00M
Kimi K3
Recall
48.2% → 85.6%
Precision
36.5% → 52.0%
F1
41.5% → 64.7%
Cost per search
$0.842 → $1.017
SQL calls per search
31.4 → 30.2
Time per search
8.1 min → 7.9 min
Input tokens per search
1.12M → 1.74M
GLM 5.3
Recall
33.1% → 47.2%
Precision
28.0% → 43.2%
F1
30.3% → 45.1%
Cost per search
$0.797 → $0.454
SQL calls per search
36.4 → 26.7
Time per search
6.0 min → 4.2 min
Input tokens per search
2.07M → 1.03M
DeepSeek Flash
Recall
23.9% → 43.3%
Precision
22.3% → 30.3%
F1
23.1% → 35.7%
Cost per search
$0.186 → $0.179
SQL calls per search
45.6 → 62.7
Time per search
4.4 min → 5.4 min
Input tokens per search
13.96M → 11.54M
Without indexWith evals-as-indexes

When the index isn’t worth it

A data agent can always query raw traces with SQL, and evals-as-indexes are an addition on top of that. In two cases, plain SQL are probably all it needs:

  • Your data is small. At low scale, the data agent finds shortcuts. If a preview of the whole trace corpus fits in a single model call, it can skim everything, spot the right keywords and search for them directly. For a small dataset, it can start by reading the 100 most recent spans and follow the relevant trace IDs for more context.
SELECT trace_id, span_id, span_name, input, output
FROM telemetry.spans
ORDER BY started_at DESC
LIMIT 100;
  • Your evals aren’t reliable. Eval results only point the search somewhere, so their quality matters: an eval that over-fires buries real cases in noise, and one that under-fires hides them. Some open-source models take eval results at face value, which likely explains why their recall rose more than their answer quality. Check your evals against hand-labeled examples before relying on them for search.

Conclusion

As agents take on longer and more consequential work, they produce more data than anyone can read manually. Failures like a missed instruction, or a mistake repeated after the user corrected it, span many steps and rarely leave a keyword behind, which makes them hard to find reliably with keyword search at scale.

But most teams already run online monitoring evals to track agent quality, and those results can be reused as indexes. Every search then starts from behavior that’s already been evaluated, and the data agent spends its effort verifying evidence instead of hunting for it.

Our goal is to make agent data as easy to search as any other data: ask anything about what your agents did in production, and get an answer backed by evidence you can check.