Compiling the next screen…
Compiling the next screen…
Tue Jul 14 2026
David Bleeker, Principal Consultant

Teams usually hit the same problem after the first agent demo that seems promising: the system works often enough to matter, but not consistently enough to trust. The failure is rarely one bad answer. More often, the workflow breaks across retrieval, tool use, planning, handoffs, latency, and user expectations.
That makes evaluation harder than classic model benchmarking. You are not just asking whether one output is good. You are asking whether a multi-step system behaved correctly, safely, efficiently, and predictably under realistic load.
The practical answer is not one metric or one source of truth. Agent teams need an evaluation stack with four inputs:
Each input covers a different kind of failure. Traces explain. Feedback helps you decide what to inspect first. Human labels calibrate. LLM judges expand coverage.
The mistake is to treat these as substitutes. They are complements. If a team uses only traces, it gets observability without a quality judgment. If it uses only thumbs-up signals, it gets noisy product sentiment without root cause. If it relies only on LLM judges, it risks automating its own bias.
How should teams evaluate agent workflows using traces, user feedback, human labels, and LLM judges?
A serious answer has to deal with three constraints.
First, agent behavior is path-dependent. Two runs can produce similar final outputs through very different internal decisions. Output-only evaluation will miss a lot of defects.
Second, production data is messy. Users do not file bug reports in tidy fields. They complain in chat, abandon tasks quietly, or retry until the workflow happens to succeed.
Third, evaluation has to fit an engineering loop. If the process is expensive, slow, or detached from deployment, it turns into a one-off audit instead of an operating practice.
So the real question is how to build a system that is cheap enough to run continuously, rigorous enough to inform roadmap decisions, and legible enough that engineers can act on it.
Teams should evaluate agent workflows as a layered pipeline:
This is less tidy than a single score, but much more useful.
For agents, the final message is not enough. You want a trace that can answer questions like:
A concrete recommendation is to treat the trace as the primary key for evaluation. Every later artifact should attach to a trace or trace segment. That includes user complaints, human annotations, and judge outputs.
Low-cost trace collection matters because teams otherwise sample too aggressively and lose the long tail. A defect that shows up in 0.5% of runs can still dominate support cost if the workflow is business-critical. Cheap observability changes what you can afford to retain and analyze.
Explicit user ratings are sparse. Most users do not click thumbs-down. But they do reveal friction in language and behavior:
These signals should not become quality labels automatically. They should become prioritization signals.
That distinction matters. Feedback tells you where to look, not what the truth is. A user can be wrong about policy or dislike a correct refusal. Still, extracted feedback is one of the best ways to find high-impact slices that your benchmark missed.
A good team will segment feedback by workflow stage. Complaints about a “wrong answer” often start with retrieval mismatch, stale business rules, or a tool side effect that never surfaced in the final answer. If the trace schema is good, you can route each complaint to a likely subsystem.
Human labels are expensive. Use them where ambiguity and business risk are highest.
Good labeled tasks often include:
This is where many teams underinvest in label design. They ask reviewers, “Was this output good?” and get low agreement. A better approach is to break the rubric into observable criteria:
You can still roll these up into a score later. But the atomic labels are what make debugging possible.
A useful pattern is to maintain three labeled datasets:
This keeps evaluation from drifting toward either lab neatness or production chaos.
LLM judges are practical when used for bounded tasks:
They are less reliable as a replacement for human judgment in high-risk cases. They can over-reward style, miss subtle policy issues, or share the same flawed assumptions that produced the output.
The right way to use judges is calibration first.
One useful detail: a judge often performs better when it sees selected trace fields, not just the final response. If the rubric includes “used the correct tool” or “cited retrieved evidence,” the judge needs those artifacts. Output-only judging is usually too lossy for agent workflows.
The operational unit should be an evaluation record like this:
That enables analysis like:
Without this joined record, evaluation breaks into dashboards that do not explain each other.
A concrete architecture recommendation is to build evaluation as a sidecar pipeline around the agent platform, not as logic buried inside the application service.
Runtime path
Evaluation path
This separation has two benefits. Runtime latency is not affected by evaluation work. And you can change rubrics, judges, and sampling logic without redeploying the agent.
Use append-only event tables plus derived materialized views.
Core tables:
agent_runstrace_eventsconversation_messagesuser_feedback_signalshuman_labelsllm_judge_resultseval_aggregatesStore raw trace payloads, but also normalize a few fields aggressively:
tool_nametool_call_statusretrieved_doc_idslatency_msretry_countguardrail_actionmodel_nameprompt_versionThat normalization makes cross-run analysis much easier. It also prevents a common failure where every workflow logs slightly different JSON and nobody can query failures by category.
Do not sample uniformly.
Use a blend of:
This gives you coverage without spending label budget on obvious successes.
Avoid a single top-line “agent quality score.” It compresses away too much.
Track at least:
For management reporting, roll these into a small scorecard. For engineering, keep the per-criterion detail.
Trace-heavy systems create storage and privacy pressure. If you log everything, you may retain sensitive content you do not need. Redaction and field-level retention rules belong in the architecture from the start.
Feedback extraction can confuse frustration with failure. A user may dislike a safe refusal or express anger unrelated to quality. Treat extracted feedback as a routing signal, not a truth label.
Human labels drift. Reviewers pick up changing norms, shortcuts, or local interpretations of policy. You need calibration sessions and inter-rater agreement checks.
LLM judges can become stale. If the product style or policy changes, old judge prompts will score the wrong behavior. Version your judges like code.
Metrics can be gamed by prompt changes. Teams sometimes improve judge-visible formatting while underlying task completion does not improve. This is another reason to inspect traces and business outcomes together.
Evaluation can bias toward easy-to-measure tasks. Hard but high-value workflows often remain under-labeled because they are ambiguous. Engineering and product leadership need to budget for those cases explicitly.
A minimal implementation starts with a canonical evaluation record. The exact storage layer does not matter as much as keeping identifiers stable across traces, labels, and judges.
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
from datetime import datetime
@dataclass
class EvalRecord:
task_id: str
run_id: str
trace_id: str
agent_version: str
prompt_version: str
model_name: str
tool_versions: Dict[str, str]
started_at: datetime
latency_ms: int
retry_count: int
user_feedback_signals: Dict[str, Any] = field(default_factory=dict)
human_labels: Dict[str, Any] = field(default_factory=dict)
llm_judge_scores: Dict[str, Any] = field(default_factory=dict)
production_outcomes: Dict[str, Any] = field(default_factory=dict)
def should_queue_for_human_review(record: EvalRecord) -> bool:
if record.production_outcomes.get("escalated_to_human"):
return True
if record.user_feedback_signals.get("negative_sentiment", 0) > 0.8:
return True
if record.retry_count >= 3:
return True
if record.llm_judge_scores.get("policy_compliance_confidence", 1.0) < 0.6:
return True
return False
The next step is to score a run using both trace-aware features and a rubric-oriented judge prompt. Even if you use an existing evaluation tool, this pattern is worth preserving.
import json
JUDGE_RUBRIC = {
"criteria": [
{
"name": "tool_correctness",
"question": "Did the agent choose and call the correct tool for the task?",
"scale": [0, 1]
},
{
"name": "groundedness",
"question": "Are factual claims supported by retrieved evidence or tool outputs?",
"scale": [0, 1]
},
{
"name": "policy_compliance",
"question": "Did the run comply with the stated policy and avoid disallowed actions?",
"scale": [0, 1]
},
{
"name": "task_completion",
"question": "Did the run complete the user's task with the required fields and actions?",
"scale": [0, 1]
}
]
}
def build_judge_input(trace_summary: dict, final_output: str, policy_text: str) -> str:
payload = {
"rubric": JUDGE_RUBRIC,
"trace_summary": {
"tool_calls": trace_summary.get("tool_calls", []),
"retrieved_docs": trace_summary.get("retrieved_docs", []),
"guardrail_actions": trace_summary.get("guardrail_actions", []),
"retries": trace_summary.get("retries", 0),
},
"final_output": final_output,
"policy": policy_text,
"instructions": (
"Return strict JSON with a score per criterion and short evidence. "
"Do not infer facts not present in the trace summary or output."
)
}
return json.dumps(payload)
A warehouse query can then combine outcome, feedback, and labels for regression checks.
SELECT
agent_version,
prompt_version,
COUNT(*) AS runs,
AVG(CASE WHEN human_labels->>'task_completion' = '1' THEN 1 ELSE 0 END) AS human_task_success,
AVG(CAST(llm_judge_scores->>'policy_compliance' AS FLOAT)) AS judge_policy_score,
AVG(CASE WHEN user_feedback_signals->>'negative' = 'true' THEN 1 ELSE 0 END) AS negative_feedback_rate,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY latency_ms) AS p95_latency_ms
FROM eval_records
WHERE started_at >= NOW() - INTERVAL '7 days'
GROUP BY agent_version, prompt_version
ORDER BY runs DESC;
One practical note: keep the judge prompt and rubric under version control. Store a judge_version on every result. If your metrics move after changing the judge, you need to know whether the product changed or the evaluator changed.
Evaluation for agent workflows should be built as a joined system, not a set of isolated checks.
The implementation detail that matters most is the shared identifier across all four layers. If traces, conversations, labels, and judge outputs cannot be linked reliably, the system turns into disconnected anecdotes.
The engineering risk to watch is false confidence. A polished dashboard can hide weak label design, uncalibrated judges, or traces that omit the decisive step. Reliability comes from overlap between methods. When the four signals disagree, that is usually where the useful work is.
For teams moving from demos to measurable operations, the best next step is simple: instrument every run, define a small rubric for one high-value workflow, label a few hundred examples, and measure judge agreement before automating more of the pipeline.