learn-agent-launch-with-phoebe / Builder session 3 of 10
Learn Agent Launch with Phoebe · Builder track · Session 3 of 10

Operational metrics: the percentile where your unhappiest users live

Yesterday's session was about whether the answer is right. This one is about whether anyone waited long enough to read it, and what it cost you to produce. Two gates, two numbers, and one habit that ruins both: reporting an average. By the end you will have Beacon's latency and cost table with p50, p95 and p99 columns, and you will have priced every quality lever from b2 in milliseconds and cents.

🟡 Builder track AI engineers · ML engineers · technical PMs 45 min
0-3 · Welcome 3-22 · Latency anatomy, percentiles, the money 22-40 · Build-along: the ops table, then price the levers 40-45 · Q&A
Part 0

Two gates that nobody argues about until launch week

Quality gets all the meeting time. Then the bot ships, the p99 turns out to be eleven seconds, finance sees the first full month of inference spend, and both of those become somebody's emergency. Operational metrics are unglamorous, cheap to instrument and almost always measured too late - and unlike quality metrics, they have the decency to be objective.

Live - presented in session Self-study - read after class Official sources covered
★ What you walk out with today The difference between time-to-first-token and total response time and why users only feel one of them; percentile discipline with the arithmetic to prove why an average lies; starter latency SLOs you can adopt on Monday; the cost anchors that make an ROI argument, including the per-outcome pricing shift; and a priced list of your own quality levers, in milliseconds and cents.
The key teaching point of this session, stated once up front Every quality lever you switched on in b2 costs milliseconds and cents. Strict claim checking means a second model call. Better grounding means a longer context. Retries for reliability multiply everything. Quality and operational gates are coupled, which is why in b9 you will watch performance and cost go red together the moment you take quality seriously. Nobody warns you about this, and it is the trade that decides most launches.
Part 1 · latency anatomy

Users feel the first token, not the last 6 min live

When an answer streams, the perceived wait ends at the first token and the reading begins. Total response time is still real - it caps how fast a conversation can move, and it is the whole story for anything non-streaming - but it is not the number the user is judging you on.

One streamed answer, illustrative timings - the two numbers that are not the same number Server side TTFT 600 ms inter-token latency (TPOT), one small gap per token 320 tokens x 10 ms = 3,200 ms of streaming User side a blank screen text appearing, faster than anyone can read it TTFT is what they feel; total time is what they forgive full response time = 3,800 ms - the number on your dashboard, and the wrong one to gate on Gate on TTFT, at p95 p95 TTFT under 500 ms is a common interactive bar; 200-500 ms is achievable when well tuned. A looser starting SLO: p95 TTFT under 1 s plus p95 inter-token under 50 ms. Voice is its own regime: ~800 ms. Never gate on the average An average TTFT of 400 ms is compatible with one user in twenty waiting three seconds. Averages hide the tail, and the tail is where the people who quit actually live. Report p50, p95 and p99, or nothing. TTFT and total time move for different reasons. A bigger model raises both; a longer prompt raises TTFT alone; a chattier answer raises total time alone. Two numbers, two different fixes.
🔍 Click to zoom - the blank-screen wait, the streaming phase, and the number to gate on
LiveWhy TTFT and TPOT need separate gates4 min▶

The two halves of the timeline are produced by different work, so they fail independently and they get fixed differently.

  • TTFT is queueing plus reading the whole prompt before a single token comes back. It grows with prompt length, with retrieval that runs before the model, with any pre-flight guardrail call, and with load. Every one of those is a lever you added in b2 for quality reasons.
  • Inter-token latency (TPOT) is the per-token cost of generation. It is mostly a property of the model and the serving stack, and it barely cares how long your prompt was. It sets the ceiling on how fast the answer can finish.

A useful starting SLO if you have nothing today: p95 TTFT under one second and p95 inter-token latency under 50 ms. That is deliberately loose - it is a floor to detect regressions against, not a target to be proud of. Well-tuned interactive systems land in the 200 to 500 ms TTFT range, and p95 TTFT under 500 ms is a common target for anything that feels like a chat.

Conversational voice is a different regime entirely, because there is no partial output to look at while you wait. The working budget there is roughly 800 ms of round-trip for the whole loop, which has to cover speech recognition, the model and speech synthesis. If Beacon ever puts its support bot on a phone line, none of today's numbers survive the move.

Self-studyWhat to instrument, and the units that make it comparable3 min read▶

Record five fields per request and you can compute everything on this page later: ttft_ms, total_ms, output_tokens, input_tokens, and an attempt number so retries are visible rather than folded silently into a single latency figure.

Inter-token latency is then derived, not measured: (total_ms - ttft_ms) / max(1, output_tokens - 1). Deriving it rather than logging per-token timestamps keeps the instrumentation cheap and gives you a number that is comparable across models with different tokenizers, as long as you say which tokenizer produced the count.

One trap worth naming now: log one row per request, not one per user session. A percentile computed over sessions weights a chatty user the same as a quiet one and quietly flatters your tail. Session a4 makes the same point about golden sets, where it shows up as the cluster standard error gotcha - and it can widen a real confidence interval by up to about three times.

Part 2 · percentile discipline

The average is the summary that flatters you most 7 min live

Latency distributions are not symmetric. They have a long right tail made of cache misses, cold starts, retries, long prompts and unlucky queueing - and the mean sits well to the left of that tail, in a place where nothing bad is visible.

One hour of Beacon support-bot traffic, 100 requests - illustrative distribution requests average 548 ms p50 460 ms p95 1,300 ms p99 1,700 ms 0 500 1,000 1,500 2,000 TTFT in milliseconds. Amber bars are the 5% beyond p95. The same 100 requests, four honest summaries Average 548 ms - comfortably inside a 1 s SLO. p50 460 ms - most people have a fast bot. p95 1,300 ms - five in every hundred wait more than a second and a third. p99 1,700 ms - one in a hundred waits nearly two seconds. Only one of those four numbers describes the users who are about to stop using your bot. Report all three. If your dashboard shows one number and it is the mean, you have chosen the summary that flatters you most. The p95 is the percentile where your unhappiest users live - gate on that one.
🔍 Click to zoom - one distribution, four summaries, and only one of them is a gate
★ Percentiles, and the row you compute them over
lat = sorted(ttft_ms)          # one row per request, not per session
def pct(q):  return lat[max(0, ceil(q * len(lat)) - 1)]
print(mean(lat), pct(.50), pct(.95), pct(.99))   # report all four
MetricStarting SLOWell-tuned targetNotes
TTFT, streamed chatp95 under 1 sp95 under 500 ms; 200-500 ms achievableThe number users actually feel. Grows with prompt length and pre-flight guardrails
Inter-token latencyp95 under 50 msModel and serving stack dependentSets the ceiling on how fast an answer can finish. Derive it, do not log per token
Full response timeReport, do not gateFalls when the answer gets shorterDominated by output length, so it is really a verbosity metric in disguise
Voice round trip~800 ms end to end for conversational voiceA different regime. No partial output to look at, so the whole loop is the wait
The percentile that hides inside a percentile A p95 computed over all traffic is still an average across your categories. If 20% of Beacon's traffic is multi-turn conversations with long histories, those requests have systematically longer prompts and therefore systematically worse TTFT - and they can sit entirely inside a healthy-looking global p95. Slice latency by the same categories you used to slice your golden set in b1. The slice that is slow is usually the slice that is also hardest to answer, which means your worst quality and your worst latency land on the same users.
Part 3 · the money

Cost per task, and the shift to cost per outcome 6 min live

A cost number is meaningless without a denominator and a comparison. The denominator is the unit somebody actually cares about - a resolved conversation, a completed analysis, a query answered - and the comparison is what that unit costs when a human does it.

The denominator you are compared against, and the numerators you control Human contact Gartner-attributed $13.50 median per US assisted-channel contact - secondary Chatbot interaction per turn, not per fix ~$0.50-0.70 per interaction - the number vendors quote Intercom Fin billed per resolution $0.99 per RESOLVED conversation - you pay when it worked Sierra per outcome (secondary) ~$1.50 per resolution - another vendor, the same pricing idea $0 $2 $4 $6 $8 $10 $12 $14 The pricing model is moving from per-interaction to per-outcome Billing per resolution only works if resolution is measurable, and the definition is the product. Fin counts a hard resolution on explicit confirmation, a soft one on customer exit plus 24 hours of quiet, and reverses it if the customer comes back to the thread. Your cost metric now depends on your resolution definition. Read the two ends together. A human contact costs about $13.50 and a bot interaction about 60 cents, so you can afford roughly twenty bot turns per contact deflected. That is your real retry budget for b8.
🔍 Click to zoom - four cost anchors on one scale, and the denominator that dwarfs them
Real world

Label the sourcing, because these numbers do a lot of work in a business case. The $13.50 median per US assisted-channel contact is Gartner-attributed and reaches us through third parties, and the same is true of the ~$1.50 Sierra figure. Intercom's $0.99 is different in kind: it is a published price on Fin's own billing documentation, which also spells out exactly what counts as a resolution. Treat the first two as order-of-magnitude anchors for an ROI conversation and never as a line item, and be the person in the meeting who says which is which.

★ Cost per outcome, in three lines
cost_turn = (in_tok * price_in + out_tok * price_out) / 1e6
cost_conv = cost_turn * turns * retry_factor   # retries are not free
cost_res  = cost_conv / resolution_rate        # the billable unit

The third line is the one that surprises people. If a conversation costs 30 cents and the bot resolves 50% of them, the cost per resolution is 60 cents, not 30 - you paid for the failures too, and then a human handled them anyway. Improving the resolution rate is therefore a cost lever as much as a quality lever, and halving your unresolved traffic does more for cost per outcome than any amount of prompt trimming.

LiveRetry amplification, and why reliability is a budget line4 min▶

Retries are the most common way a cost model goes wrong, because they are usually invisible in the instrumentation. If your agent retries a failed tool call up to three times, your worst-case cost for that task is three times the happy path, and your average sits somewhere between depending on a failure rate you probably have not measured.

The metric that governs this is the one b8 builds properly. pass@k asks whether at least one of k attempts succeeds, and it is how retries buy you reliability - you pay k times for a better chance of success. pass^k asks whether all k attempts succeed, and it is the metric that matches what production actually demands, because the same user asks the same thing again on Tuesday. They pull in opposite directions, and the arithmetic is unforgiving: a task the bot passes 75% of the time succeeds three times running only about 42% of the time.

What this means for today's gate: your cost number must include the retry factor, and your retry factor comes from your reliability, not from your config file. A budget built on the happy path is a budget that assumes a bot you do not have.

Self-studyR-VES: the one published metric that prices correctness by runtime3 min read▶

Almost every benchmark scores correctness and ignores what the correct answer cost to produce. The text-to-SQL world is the exception: BIRD's official R-VES weights execution accuracy by the runtime of the generated query relative to the gold query. A correct query that takes forty seconds where the reference takes two does not score the same as a correct query that takes two.

That is worth borrowing even if you never touch SQL, because it encodes the honest position on this whole page: a right answer that is too slow or too expensive is a partially wrong answer. Most teams hold quality and efficiency in two separate documents owned by two separate people, and R-VES is the field's clearest example of putting them in one number. Beacon's Analyst Bot inherits it directly in b6; for the other two bots you get the same effect the cruder way, by running a quality gate and a cost gate side by side and refusing to trade them.

Demo 1 of 2

Build Beacon's operational table ★ 10 min · everyone builds

Same idea as the golden set in b1: one sheet you will keep. Rows are your bots or your traffic slices, columns are the numbers you will gate on in b9. Fill it with real logs if you have them and with honest blanks if you do not - the blanks are the useful part.

Make eight columns: slice · requests · TTFT p50 · TTFT p95 · TTFT p99 · inter-token p95 · cost per task · cost per outcome. One row per bot to start, then split the busiest bot by the categories you defined in b1.

Pull one hour of production logs, one row per request. If your logs only have averages, write "average only" in the cell and stop - you have found the most valuable finding of this session and it costs a day of instrumentation to fix.

Compute the three TTFT percentiles. Then put the average next to them, in a column you will delete before anyone else sees the sheet. Look at the gap once. On most real traffic the average sits closer to the p50 than to the p95, which is why it is such a comfortable number to report.

For cost per task, use the three-line formula above and be honest about retry_factor. If you do not know it, put 1.0 and write "unmeasured" beside it. An unmeasured retry factor is a known unknown in your budget rather than a hidden one.

Now add the row that makes the table an argument rather than a report: the human baseline. For Beacon's support bot that is the assisted-channel contact cost. Your cost per outcome is only interesting relative to what the outcome costs today.

Finally, write the SLO you intend to gate on into the header of each column, before you look at your numbers. Same discipline as the threshold in b1 - nobody ever failed a latency SLO they set after seeing the p95.

Demo 2 of 2

Price every quality lever from b2 ★ 8 min · everyone builds

This is the exercise that makes b9 make sense. Take the levers you switched on last session for quality reasons, and put a millisecond figure and a cent figure next to each one. Nothing here is free, and most of it is paid for in TTFT.

Quality lever from b2What it costs in latencyWhat it costs in money
Retrieve more context for groundingTTFT only - a longer prompt to read before the first tokenInput tokens on every single call, including the easy ones
Strict claim-level faithfulness checkingOffline in eval; online it is a second model call on the critical pathRoughly a second inference per checked response
Pre-flight injection or policy guardrailPure TTFT, paid on 100% of traffic to catch a small sliceSmall per call, large in aggregate because it never skips
Citations attached to every claimTotal response time - more output tokens to streamOutput tokens, the expensive side of the price sheet
Retries for reliabilityOnly on the retried requests, which is exactly where p99 livesMultiplies the whole task cost by the retry factor
A larger model for the hard sliceBoth TTFT and inter-token latency get worse togetherThe single biggest line, and the easiest to route around

Copy that table and fill the two right-hand columns with your own measured numbers, by running your eval once with each lever off and once with it on. Ten minutes of work per lever, and the result is the only version of this table anyone should believe.

Rank the levers by cost per point of quality gained. The ordering is almost never what the team expected, and there is usually one lever that is buying nothing measurable and paying for it on every request.

Find the levers that only cost you on part of the traffic. Routing the easy 70% of turns to a smaller model, or running the strict grounding check only on the policy slice, buys most of the quality for a fraction of the bill. This is the fix behind almost every red cost gate in b9.

Now switch every quality lever on at once and re-measure p95 TTFT and cost per outcome. Watch both gates go red together. That is the coupling this session exists to teach, and in b9 you will see the same thing happen on the scorecard.

The trade nobody schedules time for Teams treat quality work and performance work as sequential: get it right, then make it fast. In practice the quality levers are the reason it is slow and expensive, so the two pieces of work are the same piece of work. If your launch plan has a quality phase and then a performance phase, the second phase will spend its time removing things the first phase added, and somebody will have to decide which quality you are giving back. Decide that consciously now, in this table, rather than under deadline pressure in launch week.
Homework

Try it yourself - this week ◐ 45-60 min total

Source material

Official sources covered

Every figure on this page traces to a primary source or is labelled as secondary where it reaches us through a third party. This page covers:

✓TTFT and inter-token latency as separate measurements, with percentile reporting rather than averagesParts 1-2 · inference-latency engineering documentation
✓p95 TTFT under 500 ms as a common interactive target; 200-500 ms achievable when well tunedPart 1 · applied as the performance gate in b5 and b9
✓Starter SLO: p95 TTFT under 1 s plus p95 inter-token under 50 ms; ~800 ms round trip for conversational voicePart 1 · a floor to detect regressions, not a target
✓Intercom Fin billed at $0.99 per resolution, with the hard, soft and reversed resolution definitionsPart 3 · published pricing; the 67% average is secondary
◐Cost anchors: median $13.50 per US assisted-channel contact, ~$0.50-0.70 per chatbot interaction, ~$1.50 Sierra per resolutionPart 3 · Gartner-attributed and third-party, labelled secondary throughout
✓BIRD R-VES: execution accuracy weighted by runtime efficiency against the gold queryPart 3 self-study · applied to the Analyst Bot in b6
◐pass@k versus pass^k, and the retry arithmetic behind the retry factorNamed here as a cost multiplier · measured properly in b8
◐Cluster standard errors, and why one row per request beats one row per sessionPart 1 self-study · derived in a4
◐Vertex pointwise verbosity judge as the quality-side view of the same tokensIntroduced in b2 · costed here
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Your dashboard reports an average TTFT of 548 ms against a 1 second SLO, so the gate is green. Why is that not good enough to launch on?

The mean is dragged only slightly by a thin tail, so it sits close to the median and reports the experience of your typical user. Your unhappiest users are the tail, and they are the ones who churn, escalate and complain. Report p50, p95 and p99 and gate on p95 - and if you slice by category you will usually find the slow slice is also the slice your bot answers worst.

2 · You add a retrieval step that pulls twice as much context, purely to improve grounding. Which operational number moves most?

The two halves of the timeline fail for different reasons, which is why they need separate gates. Prompt length lands almost entirely on time-to-first-token, while inter-token latency is mostly a property of the model and the serving stack. That makes this a particularly expensive quality lever in UX terms: you pay for it in the one phase where the user has nothing to look at, and you pay it on every request rather than only on the hard ones.

3 · A conversation costs 30 cents to run and the bot resolves half of them. What is your cost per resolution, and why does it matter?

Cost per outcome divides total spend by successful outcomes, so every failure is paid for twice: once in inference and once by the human who picks it up. This is exactly why the pricing model is shifting from per-interaction to per-outcome - Fin bills $0.99 per resolved conversation and publishes a detailed definition of what resolved means, including reversing a resolution if the customer comes back. If you are going to be billed on an outcome, you had better be measuring the same outcome.

Builder session 3 cheat sheet · pin this

TTFT is what users feelWhen answers stream, the wait ends at the first token. Total response time is real but forgiven.
Percentiles or nothingReport p50, p95, p99. Gate on p95. The mean sits near the median and hides the entire tail.
Starter SLOsp95 TTFT under 1 s plus p95 inter-token under 50 ms. Tighter: p95 TTFT under 500 ms; 200-500 ms is achievable.
Voice is a different regime~800 ms round trip for the whole conversational loop. No partial output, so nothing hides the wait.
Prompt length hits TTFT onlyOutput length hits total time. A bigger model hits both. Three symptoms, three different fixes.
Cost needs a denominatorPer task, per conversation, per resolution. ~$13.50 per human contact vs ~$0.60 per bot turn (both secondary).
Per-outcome pricingFin bills $0.99 per resolved conversation. If you are billed on an outcome, you must measure that outcome.
Quality is bought with ms and centsEvery b2 lever costs both. Retries multiply the bill. Performance and cost go red together in b9.