Derived measures
Most business numbers need something from you first: an outcome feed from your helpdesk, a label from a classifier, or a definition of what “escalated” means. Derived measures need none of that. They are computed straight from the traces you already ingest — no external data, no LLM, no configuration — so they have a value the moment your agent sends its first traces.
They are the answer to “what can I measure on day one?”. Turns per case, how long a case takes, what a turn costs, whether your tools succeed or thrash — all of it is already in your spans, and Neens reads it back to you as first-class Business measures you can chart, alert on, and promote to a KPI.
At a glance
| What | Measures computed purely from your ingested traces — a new provenance tier: derived. |
| Setup | None. They work as soon as you send traces. No feed, no definition, no LLM. |
| Where | The Business group in the dashboard widget gallery and the metrics catalogue; promotable on the Business KPIs page. |
| Grain | Per case (a conversation), per tool call, per span, or per trace — one row per measure below says which. |
| Provenance | Always Derived — reproducible arithmetic over your spans, badged so nobody mistakes it for a system-of-record fact. |
| Honesty | When there isn’t enough signal, the value reads —, never a misleading 0. See how a derived number stays honest. |
The four provenance tiers
Every business measure in Neens carries a provenance badge that says where its number came from — and derived is the newest of the four. The badge is derived from the source, never chosen, so it can never claim a number is stronger than the evidence behind it.
| Provenance | Where the number comes from | Needs from you |
|---|---|---|
| Measured | Your system of record reported it — a business outcome from your helpdesk, CRM or warehouse. The strongest claim available. | An outcome feed. |
| Emitted | Your agent asserted it about itself, in the trace metadata. Useful, but nothing outside the agent confirmed it. | Your agent to write the claim onto its traces. |
| Inferred | An LLM classifier read the transcript and decided. A directional signal when you have nothing better yet. | A classifier. |
| Derived (new) | Neens computed it from your traces with a deterministic rule — no external system, no LLM, no configuration. | Nothing. Just send traces. |
Derived is the zero-setup tier. The other three each depend on something arriving — an outcome,
an agent claim, a classifier label — before they can show a number. Derived measures depend only on
the traces you’re already sending to observe your agent, so a brand-new agent has real business
numbers on its first day. cost_per_case on the Business KPIs
page is zero-setup in the same spirit — computed straight from your traces — and this release brings
that day-one, no-configuration treatment to the whole family of measures below.
The derived measures
All of them live in the Business category and carry the Derived badge. They group by the grain they’re computed at — the “thing” each row counts.
Case-level — the shape of a conversation
One case is a whole conversation (conversation_id when the trace carries one, the trace’s own
id when it doesn’t) — the same grain the Business KPIs
use. These measure what a case cost you to handle. You can slice them by the case’s first-trace
agent, status, source and metadata, plus time.
| Measure | Unit | What it means | Watch for |
|---|---|---|---|
Turns per case (turns_per_case) | count | Average number of conversation turns it took to handle a case. | Rising — the agent is taking more back-and-forth to get to the same place. |
Traces per case (traces_per_case) | count | Average number of traces (agent runs) that make up one case. | A climb often means retries or re-runs stacking up inside a single conversation. |
Multi-trace case rate (multi_trace_case_rate) | ratio | Share of cases that needed more than one trace — a cheap “came back” / re-contact proxy. | Rising — more customers are having to re-engage to finish. |
Case duration (p50) (case_duration_p50) | ms | Median wall-clock time from a case’s first activity to its last. | The everyday experience drifting slower. |
Case duration (p90) (case_duration_p90) | ms | The slow tail — the 10% of cases that take longest. This is the number your unhappiest customers feel. | A p90 pulling away from p50: a subset of cases is getting badly stuck. |
Cost per turn (cost_per_turn) | usd | LLM spend across the window divided by conversation turns. | Rising — each turn is getting more expensive (bigger prompts, a pricier model, more tool chatter). |
Tool-level — is your agent’s tooling healthy
Computed per tool call. Slice them by tool name (plus time) to find the one tool dragging the average down.
| Measure | Unit | What it means | Watch for |
|---|---|---|---|
Tool call volume (tool_call_volume) | count | How many tool calls your agent makes. | A jump with no matching rise in traffic — the agent is working harder per case. |
Tool success rate (tool_success_rate) | ratio | Share of tool calls that completed without an error. | Falling — a dependency is flaky, or the agent is calling a tool wrong. |
Tool retry rate (tool_retry_rate) | ratio | Share of tool calls that immediately repeated the same tool — a thrash / retry-loop signal. | Rising — the agent is stuck re-trying instead of moving on. |
Span & latency — the mechanics of a run
Computed over spans (the individual steps in a trace). Span error rate slices by span kind and status; first-response latency is a per-trace figure.
| Measure | Unit | What it means | Watch for |
|---|---|---|---|
Span error rate (span_error_rate) | ratio | Share of spans that errored. Slice by kind/status to see which step. | Rising — a step in the run is failing more often, even if the case still finishes. |
First response latency (p50) (first_response_latency_p50) | ms | Median time from the start of a trace to the agent’s first model response — how long a customer waits before anything happens. | A climb: the agent is slower to say its first word, which reads as unresponsive. |
Ratios are fractions, not percentages. A ratio measure like tool success rate reads 0.98,
not 98. Durations (case_duration_*, first_response_latency_p50) are in milliseconds. These
are the units you’ll set a target in when you promote one.
Promote a derived measure to a KPI
A derived measure is a number you can watch. A KPI is a number you’ve made a promise about — a target, a direction that says which way is good, an owner, and a daily history so you can see the trend. Because a derived measure already has a value with no setup, promoting one is the fastest way to a tracked commitment: there’s no feed to wire up and no definition to declare first (unlike the measured and inferred paths, which need an outcome feed or a classifier before they can show anything).
The mechanics — the fields, the one-live-KPI-per-measure rule, reading the value back — are exactly the same as for any other measure, and are documented in full under Promote a measure to a KPI. The short version:
Find the derived measure in the promotable catalogue
The catalogue lists every measure you can promote, each marked whether the agent can already get a number out of it. A derived measure reads ready with no setup, alongside a proposed direction you can keep or flip.
export NEENS_BASE_URL="https://your-neens-host"
export NEENS_API_KEY="nk_live_..." # your agent API key
curl -sf "$NEENS_BASE_URL/api/kpis/options" -H "Authorization: Bearer $NEENS_API_KEY"{
"projectId": "your-project",
"measures": [
{
"key": "tool_success_rate",
"label": "Tool success rate",
"unit": "ratio",
"category": "business",
"provenance": "derived",
"defaultDirection": "higher_is_better",
"promoted": false,
"ready": true,
"unavailable": null
}
]
}Set a target and a direction
Send the measure key, a label your team uses, a target in the measure’s own unit, and the direction that says which way is good. Everything else takes a conservative default.
It starts tracking, with daily history
Once the KPI is active, Neens records its value once per completed day on its own, so it grows a
trend without you starting anything. See History and trends.
Worked example — a tool-health KPI
You want your agent’s tools to succeed at least 98% of the time, so you promote Tool success
rate with a target of 0.98. Higher is better, which is the proposed direction, so you keep it:
curl -sf -X POST "$NEENS_BASE_URL/api/kpis" \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"measureKey": "tool_success_rate",
"label": "Tool reliability",
"description": "Tools must succeed 98% of the time. If this slips, the agent starts failing cases it could handle.",
"direction": "higher_is_better",
"target": 0.98,
"owner": "Agent Platform (@rota-agents)",
"status": "active",
"reviewCadence": "weekly"
}'The tile now reads its live value, judged met at or above 0.98 and missed below it, and starts
building a daily line you can watch for erosion.
Worked example — a re-contact KPI, direction flipped
You want at most 15% of cases to need a second trace — a cheap proxy for customers coming back.
Multi-trace case rate is proposed higher_is_better by default, but for this measure lower is
what you want, so you override the direction and set target: 0.15:
curl -sf -X POST "$NEENS_BASE_URL/api/kpis" \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"measureKey": "multi_trace_case_rate",
"label": "Re-contact rate",
"direction": "lower_is_better",
"target": 0.15,
"status": "active"
}'The proposed direction is a starting point, not a verdict. Neens pre-fills a direction from the
measure’s name — a cost or latency or error measure is proposed lower_is_better, a success
rate higher_is_better — but you always decide. For measures like turns per case, tool retry rate
and multi-trace case rate, where less is better, set lower_is_better yourself. Whatever you save
is what every later read judges against; nothing re-guesses at render time.
How a derived number stays honest
A derived measure follows the same honesty rule as every other number in Neens: when there isn’t
enough signal to answer, it shows —, never a misleading 0. A dash means we couldn’t measure
this, which is a different fact from this is zero, and Neens keeps them apart.
| Situation | What you see |
|---|---|
| A case whose last activity has no end time | It’s excluded from the duration percentile and counted in coverage — never treated as a zero-length case. |
| A window with no tool calls at all | Tool success and retry rates read —, not a perfect 1.0 or a bogus 0. |
| A window with no cases | Every per-case measure reads —, never $0.00 cost per turn or 0 turns. |
| Not enough data yet | The measure reads — with the reason, and fills in as traffic arrives. |
A dash is a result, and it never renders as zero. “We have no tool calls this window” and “our
tools failed every time” are opposite facts — collapsing the first into a 0 would manufacture a
crisis out of a quiet window. When you promote a derived measure to a KPI, that same rule carries
through: a window with no signal reads targetStatus: unknown, never missed. Nobody can miss a
target nobody could measure. See
Met, missed, and the answer most dashboards get wrong.
Related
- Business KPIs — promote any measure to a commitment, and the full KPI lifecycle, history and trends.
- Metrics catalogue — the measure × dimension model these join, and everything else you can chart.
- Custom measures — define a measure in your own vocabulary when these don’t cover it.
- Cost & model pricing — where the dollars in cost per turn come from.
- Dashboards and Alert rules — chart a derived measure, or get paged on it.