multi-agent-cost-attribution.mdx
3 min read
---
title: "Multi-Agent Cost: Make the Dominant Agent Visible"
author: Aaron Gasperi
date: May 23, 2026
category: tutorials
tags: ["agent evals", "observability", "cost", "multi-agent"]
---

When a manager-researcher-writer scaffold spends $24 a week instead of $17, the question isn't 'which arm' — it's 'which agent'. Winnow's B7 agent rollup turns per-span agent_id tags into one cross-trace cost table and one per-trace span tree, both colored by the same agent palette.

Multi-Agent Cost: Make the Dominant Agent Visible

A cost alert fires on agent-pricing-rollout-v2: $24.18 this week, $17.04 last. The arm-level chart doesn't help — every arm is up. The model-level breakdown doesn't help either — same model across the board. The actual answer is researcher is dumping every web_search result verbatim into context, but that fact lives buried in the span trees of 1,247 traces.

The fix is one cross-trace rollup table and one per-trace span tree, both colored by the same agent palette.

Where it lives

Winnow's B7 agent rollup ships as two surfaces that share one data source:

  • Scorecards → Agents tab (cross-trace). A table reading GET /api/v1/experiments/{id}/agents. One row per agent, sorted by total cost descending. The dominant agent (≥50% of cost share) gets a red row tint and a DOMINANT chip so the eye lands on it without scanning.
  • Traces → Group by Agent (per-trace). The existing span tree on /traces/{id} already had a Nesting / Agent toggle from the P4 trace-detail page; this slice makes the Agent mode read real numbers from GET /api/v1/traces/{id}/agents — each agent bucket header shows span count, total cost, sum latency, and mean score for that agent on this trace.

Both surfaces use the same color hash on agent_id, so an agent's red badge on the cross-trace table is the same red badge on every span it emitted in any trace.

What it answers

Three questions, each in one click:

  1. Which agent dominates cost? Cross-trace table, sorted desc. Top row.
  2. Why is that agent expensive on this trace? Click into a trace, switch to Group by Agent, read the per-agent bucket header for span count + total cost. Inside the bucket, the individual spans show their own cost / model / latency.
  3. Is this an outlier or a pattern? Compare per-trace cost (bucket header) vs cross-trace mean (Agents tab). If a trace's agent cost is 3× the cross-trace mean, it's a single-trace outlier; if it tracks the mean, the agent's prompt itself needs a rewrite.

Honesty about what isn't built yet

This first slice ships the rollup tables and the per-span colored badges. Four follow-ups are explicitly tracked in docs/UNBUILT-FEATURES.md P2:

  • A typed pass_count / fail_count / error_count on the rollup row so the Agents tab can render a real pass-rate column (today it shows mean score with sample count — honest, but missing from the mockup's four-column shape).
  • An additive agent_rollups field on ScorecardData.metrics so the existing BreakdownToggle on the Overview tab can grow a fourth agent pill alongside Arm / Model / Harness.
  • An ?agent_id= filter on the experiment-scoped trace list so each agent row on the Scorecard tab is a one-click jump into a filtered trace list, not a tab-switch + manual scan.
  • A cost_by_agent_threshold_crossed PR-comment renderer so cost concentration becomes visible to reviewers in the same place they review code.

The per-span agent_id tagging is the SDK contract the rollup reads — record_observation(..., agent_id=...) was shipped 2026-05-19 in the storage migration that added the indexed observations.agent_id column. The cross-trace rollup endpoint shipped 2026-05-21. This slice is the UI consumer for both.

#agent evals#observability#cost#multi-agent