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

Gate the analytics bot: a pipeline of gates, because errors compound

The third and hardest archetype, because it is the other two stacked. An executable inner stage where a query runs and a number is computed, then a judged outer stage where a chart is drawn and a takeaway is written. Errors do not average across those stages, they multiply - and the last stage produces a confident English sentence that an executive will read as fact.

🟠 Builder track AI engineers · ML engineers · technical PMs 45 min
0-3 · Welcome 3-20 · Compounding, the cascade, the four things you score 20-40 · Build-along: the Insight Bot's pipeline and gate 40-45 · Q&A
Part 0

The archetype that inherits both problems

Beacon's Insight Bot takes a question from an executive, writes a query, computes a figure, draws a chart, and writes a paragraph explaining what it means. Sessions b5 and b6 gated the two halves of that separately. This session gates them together, which is a harder problem than the sum of the two - because a single end-to-end pass rate tells you the pipeline broke without telling you where.

Live - presented in session Self-study - read after class Official sources covered
★ What you walk out with today Per-stage gates instead of one end-to-end number, the validity-legality-readability cascade with the real figures behind it, four things worth scoring that are not accuracy, reproducibility as a metric this archetype uniquely needs, and a gate board on the Insight Bot that only clears with every quality lever on.
The running case: Beacon Insight Bot Analytics bot for executives. Question in, chart and written takeaway out. It cannot send anything by itself, so tier T2 and a bar of 85%. Its blast radius is a sentence in a board pack that nothing in the data supports - and unlike a wrong SQL result, that sentence arrives already argued for.
Part 1 · why it is the hard one

Four stages, four graders, and multiplication 6 min live

The instinct is to score the finished answer, because that is what the user sees. The instinct is wrong on this archetype for one arithmetic reason: an end-to-end number is a product of four stage numbers, and a product tells you nothing about its factors.

1 · Query right rows from the right tables 2 · Compute right denominator, right time window 3 · Chart renders, and encodes the right thing 4 · Takeaway the sentence follows from the numbers Execution rung: run it, compare rows Rule rung: recompute it deterministically Rule, then judge: it renders, but legally? Judge rung only. No rule reads a claim. Errors compound, they do not average Four stages at 95% each is 0.95^4 = 81% end to end. Grade the stages separately or you will keep tuning the wrong one. A pipeline number tells you it broke; a per-stage number tells you where it broke. The first three stages are machine-checkable, so most of this eval belongs on the cheap rungs. Only the last one needs a judge - and the judge is the biased, expensive rung, so keep its share of the set small.
🔍 Click to zoom - four stages, four graders, and the multiplication that makes 95% into 81%
LiveWhy one end-to-end number is the wrong instrument here4 min▶

Suppose Beacon's Insight Bot reports 81% end to end. That single figure is compatible with wildly different products:

  • 95 / 95 / 95 / 95 - a balanced pipeline with no obvious weak spot, where the next improvement is expensive and spread across four teams.
  • 99 / 99 / 84 / 99 - a chart-encoding problem and nothing else. One afternoon of work on the chart-spec validator, and the number moves nine points.
  • 99 / 99 / 99 / 84 - the narrative stage inventing causes. A rail on the takeaway prompt fixes most of it, and no amount of query tuning touches it.

The end-to-end number is identical in all three cases. This is the whole argument for staged grading: the aggregate is the thing you report and the per-stage numbers are the thing you act on. Beacon's team ran the aggregate for two quarters and spent both of them optimising the query stage, because that was the stage they understood.

Self-studyThe one thing this archetype inherits from neither parent2 min read▶

The text-to-query bot returns rows. The chatbot returns prose. The analytics bot returns rows, a picture and prose, and the failure that matters most is a mismatch between them. The chart shows a 4% dip; the takeaway says "sharp decline driven by pricing". Both halves pass their own stage gate. The pair is a lie.

You cannot catch that by grading the chart or by grading the sentence. You catch it by grading the sentence against the numbers actually plotted, which is a groundedness question with the chart data as the source passage. That is exactly the faithfulness metric from b2, pointed at a table instead of a document, and it is the single highest-value judge call on this archetype.

Part 2 · the cascade

Validity, then legality, then readability 7 min live

VisEval's contribution is an ordering, not a score. A chart that does not render cannot be illegal. A chart that encodes the wrong thing does not deserve a readability review. Ask the three questions in order and you stop wasting judge calls on outputs that a rule already disqualified.

Three gates in order. A chart must clear each one before the next is worth asking. 1 · Validity does the code run GPT-4 invalid-code rate is 3.29% with matplotlib but 25.41% with seaborn. Validity is LIBRARY-DEPENDENT. Evaluate in your own chart stack, not theirs. 2 · Legality does it encode right Illegal rate 21.44% even on matplotlib. The chart renders beautifully and encodes the wrong thing. Dominant failure class, and completely silent. 3 · Readability can a human read it Judged 3.80 out of 5, and only on outputs already valid and legal. This is a polish score. Never let it stand in for a correctness score. The overall numbers, and the two gaps inside them Overall VisEval pass rate: GPT-4 75.27%, GPT-3.5 61.79%, Gemini-Pro 51.59%. The gap between models is wide, and the gap between chart libraries inside one model is wide too. Both are yours to control.
🔍 Click to zoom - three gates in order, and the silent middle one that does the damage
Real world

Legality is the failure nobody photographs. Beacon's Insight Bot drew a legal-looking line chart of a categorical breakdown, with the axis unsorted. It rendered. It looked professional. It connected six unordered product categories with a line, implying a trend across things that have no order. The validity gate passed it, the readability judge scored it well because the labels were clean, and it went into a quarterly review. An illegal rate of 21.44% on the safest library is the published figure, and the reason a rule-based spec check belongs between the two.

★ The legality check is a rule, not a judge call # the model proposes a spec; a rule decides whether the spec is legal spec = { "mark": "line", "encoding": { "x": {"field": "category", "type": "nominal"}, "y": {"field": "revenue", "type": "quantitative"} } } assert spec["mark"] in ALLOWED_MARKS[question_type] # line over nominal: illegal assert spec["encoding"]["x"]["field"] == expected_x # wrong field: illegal assert spec["encoding"]["y"]["field"] == expected_y # only what survives this gets sent to the readability judge
Self-studyWhy the library gap is the most actionable number on this page3 min read▶

The same model, the same tasks, the same prompts: 3.29% invalid code with matplotlib, 25.41% with seaborn. Nearly an eightfold difference in the raw failure rate, produced by a choice your team makes for reasons that have nothing to do with evals - somebody preferred seaborn's defaults.

Two consequences. First, published validity figures do not transfer: a paper's number is a number about the library that paper used, and if your stack is plotly or ECharts or a Vega-Lite spec you know nothing yet. Second, and more usefully, the chart library is a lever. It sits in the same family as switching an LLM judge for a rule: a change that removes failures rather than measuring them, available for the cost of a refactor, and never on anyone's eval roadmap because it does not look like eval work.

Part 3 · what else you score

Numbers, insights, refusals, and the same answer twice 6 min live

The chart cascade covers one stage. Three more criteria sit around it, and the fourth of them is unique to this archetype: an executive who gets two different numbers for the same question on two different days stops using the bot, whatever your accuracy figure says.

Numeric correctness DABstep's pattern: 450+ real analysis tasks drawn from operational workloads, scored as binary factoids with format-tolerant matching, so "1,240" and "1240" both pass. The cheapest rung available. Insight faithfulness InsightBench's pattern: 100 end-to-end analytics cases where the generated insight is judged against ground-truth insights. This is the rung-4 job - no rule reads whether a takeaway follows. Refusal correctness Fabricating a trend from three points is the analytics version of hallucination. Seed the set with unanswerable and insufficient-data cases and score abstain against fabricate, explicitly. Reproducibility Unique to this archetype. Ask twice, get the same number, or the executive stops trusting the tool. It is a metric you measure, not a property you assume - and temperature 0 does not supply it. Why temperature 0 is not determinism GPU floating-point addition is not associative, so batching and mixture-of-experts routing change the order of operations run to run. OpenAI documents its seed parameter as best-effort; vLLM documents the same caveat. You cannot fix this in the sampler. You fix it by moving the computation out of the model entirely. The mitigation, and how to test that it worked Push every computation into deterministic SQL or pandas and keep the LLM to orchestration and prose. Then test it: run each case N times and require identical NUMBERS, while allowing the prose to vary. Prose drift is fine.
🔍 Click to zoom - four criteria, one of which no other archetype needs
CriterionGrading rungWhat a miss looks like in production
Numeric correctnessRule: recompute deterministically, format-tolerant matchThe revenue figure in the deck is off by the wrong denominator at step two
Chart validityExecution: render the spec, catch the exceptionA broken image in a board pack. Loud, cheap, embarrassing, harmless
Chart legalityRule on the spec, before any judge sees itA line chart through six unordered categories, implying a trend that cannot exist
Insight faithfulnessJudge, calibrated against human labels (b4)"Sharp decline driven by pricing" under a chart that shows a 4% dip and says nothing about pricing
Refusal correctnessRule on the expected behaviour: abstain or answerThree data points, an arrow, and the word "trend"
ReproducibilityRule: N runs, identical numbers requiredTwo executives quote two different figures for the same question in the same meeting
Readability is not a correctness metric, and it is the one people report A 3.80 out of 5 readability score is easy to produce, easy to put on a slide, and says nothing about whether the chart encodes the right thing - because it is only ever measured on outputs that already passed validity and legality. If the only chart number in your eval report is a readability score, your report is silent on the dominant failure class of this archetype.
Demo 1 of 2

Build the Insight Bot's staged harness ★ 12 min · everyone builds

Instrument the pipeline so every stage reports its own number. This is more plumbing than modelling, and it is the work that makes every later decision cheap.

Split the run into four recorded artifacts per case: the query, the computed figures, the chart spec, and the takeaway text. Store all four, always, including on passes. You cannot grade a stage whose output you threw away, and you will want last month's artifacts the first time a number is disputed.

Grade stages 1 and 2 with rules. Execution accuracy on the query as in b6, then recompute the figures independently in SQL or pandas and compare with format-tolerant matching, following DABstep's binary-factoid pattern so that "1,240" and "1240" are the same answer.

Grade stage 3 as a cascade, in this order: render the spec and catch exceptions (validity), assert mark and encoded fields against what the question requires (legality), and only then send survivors to a judge for readability. Measure validity in your own chart library - a published rate of 3.29% belongs to matplotlib, and seaborn's was 25.41%.

Grade stage 4 with a calibrated judge, using the plotted numbers as the source passage. The question is faithfulness, not fluency: does every claim in the takeaway trace to a figure that is actually on the chart? InsightBench's pattern of judging the generated insight against a ground-truth insight is the reference to copy.

Add the insufficient-data slice by hand: three-point series, a cohort with n=4, a question about a segment your warehouse does not track. Expected behaviour is a refusal with a stated reason. Score abstain against fabricate, and treat a fabricated trend exactly as you would treat a hallucinated policy in b5.

Finally, run twenty cases twenty times each and diff the numbers across runs. Prose is allowed to vary. Numbers are not. Any case where the figures move is a case where computation is still happening inside the model, and it is a bug you can locate exactly.

★ The number is computed here, not generated - and the test that proves it # stage 2: deterministic, outside the model monthly = (orders .assign(month=orders["placed_at"].dt.to_period("M")) .groupby("month")["amount"] .sum() .round(2)) # the reproducibility test: numbers must be identical, prose may vary runs = [answer(question) for _ in range(20)] assert len({tuple(r.figures) for r in runs}) == 1
Why the seed does not save you Setting temperature to 0 constrains the sampler, not the arithmetic. GPU floating-point addition is not associative, so batching and mixture-of-experts routing change the order of operations between runs and the logits move. OpenAI documents its seed parameter as best-effort and vLLM documents the same caveat. The only reliable fix is architectural: every number an executive will quote is computed by SQL or pandas, and the model's job is to decide what to compute and how to describe it.
Demo 2 of 2

Take the Insight Bot to all green ★ 10 min · everyone builds

The compound archetype on the same board. Work it to six green lights and count the levers it took, then compare that count with what the Analyst Bot needed in b6.

Switch on the quality levers one at a time and watch which category each one rescues. Output verification takes the chart category; retrieval context takes the multi-step cohort category; abstention takes the three-points-is-not-a-trend category; grounding takes the written takeaway; action rails take the instruction sitting in a spreadsheet cell.

Now the point of the exercise: this is the only bot on the board that needs all five quality levers to clear its bar. The chatbot did not. The Analyst Bot did not. That is what "the other two stacked" means as a number rather than a phrase - every failure class from both parents is present, so every defence has to be present too.

With everything on, drop the golden set to n=100. It still clears the T2 bar of 85%. Now imagine the same bot at T3, where the bar is 90%: the same evidence misses. Same bot, same run, same number - a different tier gives a different answer, which is why the tier is decided before the run and not after.

Last, switch latency and cost engineering off with every quality lever still on. Performance and cost go red together, and harder here than on either other archetype, because verification on this pipeline means running a query and rendering a chart before you answer.

Read the honesty rail under the board The per-category pass rates are a teaching model of a bot with realistic failure modes - chart legality dominates, because that is what the published analysis shows - and they are not a measurement of any real product. The statistics are not a model: the confidence figure is the lower bound of a real 95% Wilson interval, computed live in your browser from the successes and n shown. Change n and check it against the table in Leader session 4.
Homework

Try it yourself - this week ◐ 60 min total

Source material

Official sources covered

Every figure on this page traces to a primary source - peer-reviewed benchmarks and vendor documentation catalogued in this course's source map, dated 2026-08-13. This page covers:

✓VisEval cascade: validity → legality → readability, as an ordering rather than three separate scoresPart 2 · the ordering is the contribution
✓GPT-4 invalid-code rate 3.29% with matplotlib vs 25.41% with seaborn - validity is library-dependentPart 2 · the most actionable number on the page
✓Illegal rate 21.44% even on matplotlib: renders fine, encodes the wrong thingPart 2 · the dominant and silent failure class
✓Overall VisEval pass rates: GPT-4 75.27%, GPT-3.5 61.79%, Gemini-Pro 51.59%; readability 3.80/5 on valid outputsPart 2 · readability is a polish score, stated as one
✓DABstep pattern for numeric correctness: 450+ real analysis tasks, binary factoid scoring with format-tolerant matchingPart 3 + Demo 1 · copied as a pattern, not as a leaderboard
✓InsightBench pattern for insight faithfulness: 100 end-to-end cases judged against ground-truth insightsPart 3 + Demo 1 · the one genuine judge call here
✓Reproducibility: temperature 0 is not determinism (GPU float non-associativity, MoE routing, batching); OpenAI's seed is best-effort and vLLM documents the samePart 3 + Demo 1 · mitigation is architectural, then tested
◐Judge calibration against 100+ human labels, position swapping, rubric designUsed on stage 4 here · built properly in b4
◐Faithfulness as supported claims over total claimsPointed at plotted numbers here · formula in b2
◐Wilson interval arithmetic behind the confidence figure in Demo 2Used here, derived in a4
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · The same model produces 3.29% invalid chart code with matplotlib and 25.41% with seaborn. What follows for your eval?

A near eightfold difference in failure rate produced by a library choice means the number is a property of the pair, not of the model. Option A is a reasonable engineering move and the library genuinely is a lever - but it is a fix, not a finding, and it does not excuse you from measuring your own stack. Option B is the trap: validity is indeed cheap to catch, which is exactly why the interesting failure is the next gate down, legality, where the chart renders perfectly and encodes the wrong thing 21.44% of the time.

2 · Your analytics bot reports 81% end to end. Why is that number the wrong instrument for deciding what to fix?

Errors compound across query, compute, chart and takeaway rather than averaging, so the aggregate is a product and a product hides its factors. A balanced pipeline and a single broken chart stage look identical from outside. The aggregate is what you report; the per-stage rates are what you act on. Beacon's team spent two quarters optimising the query stage on the strength of an aggregate, because the query stage was the one they understood.

3 · You set temperature to 0 and the bot still returns different numbers for the same question. What is going on?

Determinism is not something the sampler can give you. Floating-point addition on a GPU is not associative, so changes in batching and expert routing shift the logits run to run; OpenAI documents its seed parameter as best-effort and vLLM documents the same caveat. Option C is worth ruling out with a frozen snapshot, but it is not the cause here. The fix is architectural rather than parametric: push every quotable number into deterministic SQL or pandas, keep the model on orchestration and prose, then run each case N times and require identical numbers while letting the prose vary.

Builder session 7 cheat sheet · pin this

The other two stackedExecutable inner stages, judged outer narrative. Every failure class from both parents, so every defence has to be present.
Errors compound0.95^4 = 81%. Grade query, compute, chart and takeaway separately, or you will keep tuning the stage you understand best.
Validity → legality → readabilityAsk them in that order. A chart that does not render cannot be illegal; an illegal chart does not deserve a readability review.
Validity is library-dependent3.29% invalid on matplotlib, 25.41% on seaborn, same model. Measure it in your own chart stack. The library is a lever.
Legality is the silent killer21.44% illegal even on matplotlib. Renders beautifully, encodes the wrong thing. Catch it with a rule on the spec, not a judge.
Faithfulness against the plotted numbersThe chart says 4% dip, the takeaway says "sharp decline driven by pricing". Both stages pass; the pair is a lie.
Refusal is a scored caseThree points and an arrow is the analytics hallucination. Seed the set with insufficient-data cases and score abstain vs fabricate.
Reproducibility is a metricTemperature 0 is not determinism. Push computation into SQL or pandas, then run N times and require identical numbers, prose free to vary.