Paste a call transcript. The agent splits it into six coaching categories, checks each one against a 36 point rubric, matches it to the closest shape in a library of excellent calls, and tells a manager the one thing worth coaching. Then the rep answers the same real objection again, out loud, and watches the score move.
The model reads the language. Every score is computed in code from observable criteria, with the quote that proves each one.
Speaker labels matter. Start each line with Rep: or Buyer:, because the talk ratio and the question count are counted from them, and only the rep's words are graded.
Across a rep's recent calls, ranked by the size of the gap to the model standard and how often the category comes up, not by the lowest score. This goes to the manager. The system never sends feedback to the rep.
Aggregating stored grades...A real moment from a graded call, not an invented scenario. Play the customer, answer it again, and the new answer runs through the identical grading path so the two scores are comparable.
A criterion earns its place by being checkable from the transcript by a person who knows nothing about the deal. "Built rapport" is not a criterion. "Asks what the problem costs, in money, time or units" is. Weights are relative within a category, and the category weights below produce the single headline score.
Presence criteria must be quoted to pass. Absence criteria pass by default and fail only when the model can quote the rep doing the thing, so a criterion phrased as a negative cannot fail a rep on a silence.
A coaching score gets said out loud to the person it is about, so it has to survive them disagreeing with it. That single constraint decided everything below.
Every model here is open weights running on Cloudflare Workers AI. There is no OpenAI or Anthropic key anywhere in this demo, and no model vendor is involved at any point.
| Job | Model | Why this one |
|---|---|---|
| Split the call | llama-3.3-70b-instruct-fp8-fast | Returns line numbers, so it cannot reword the rep |
| Answer the checklist | llama-3.3-70b-instruct-fp8-fast | Smaller models were measured and agreed with it on only 64% of criteria |
| Write the note | llama-3.1-8b-instruct-fast | Prose, not judgement. It cannot move a single check |
| Retrieve model answers | bge-large-en-v1.5 | Embeddings, matched by cosine inside one library |
| Hear the rep's answer | whisper | The drill is spoken out loud, like the real thing |
| Voice the customer | deepgram aura-1 | Generated once at build time, not per visit |
One honest limit. Speech-to-text strips disfluencies, Whisper included. So a transcript with no um or uh at all is reported as unassessable rather than clean, and a spoken practice answer is never credited with dropping fillers it may never have lost. The tool says so rather than taking the compliment.
That matters beyond the bill. Deflection economics are mostly model cost, and a system that grades every call a team makes has to survive being run on every call a team makes.
Thirty working nodes and four modes in one workflow, because four workflows would be four copies of the piece that must not drift. Two graders that quietly disagree about what "acknowledges the objection" means produce two scores that both look reasonable.
Webhook ─ Guard ─ Accepted? ─ Load rubric ─ Route by mode ─┬─ ingest ─┐
├─ grade ─┤
├─ coach ─┤
└─ drill ─┘
all four reach ONE Respond node
Every node on the canvas carries a sticky note explaining what it does and why, including the failures that shaped it. Retrieval calls a Worker route rather than a vector database, because a Cloudflare token cannot be scoped to one index: a token that let n8n read this library would read every index on the account.
Measured per node, not guessed. Grading is 99% model round trips and 1% code.
| Stage | Time |
|---|---|
| Rubric checks, run in parallel across categories | 4.6s |
| Splitting the call | 2.6s |
| Coaching note | 1.0s |
| Retrieval and loading the rubric | 0.4s |
| Every line of code in the workflow | 0.1s |
A faster model was the obvious fix and the wrong one: the 8b is 2.4 times quicker and agrees with the 70b on only 64% of criteria, which is not a faster grader but a different one. So the time came out of the structure instead. Grades are cached against the transcript and the prompt version, the sample calls are graded once after each deploy, and the mechanical measures run in your browser the moment you press the button, because they never needed a model at all.
A cached answer says so, and says how long the original grading took. Changing a prompt or a rubric weight changes the cache key, so it can never serve a result from rules that no longer exist.
Within a category, strong answers cluster into a few distinct valid shapes rather than one. A price objection answered well after discovery produced a number does not look like the same objection answered cold. Grading against a single nearest neighbour teaches reps to imitate one call. Grading against the nearest valid shape teaches the move. The library declares two to four shapes per category, each demonstrated by a real segment, and the model standard is measured: the library is graded by the same grader the reps get, and the mean becomes the standard.
Every call, rep, company and customer voice here is fabricated. Before this runs on real recordings it needs a consent and retention policy for rep calls, a decision about who can read transcripts and for how long, and production access control. That is legal, HR and infrastructure work, not prototyping work.
The production call recording system is never queried live or written to. Transcripts land read only. And practice scores from the drill stay in the rep's own browser, because a practice score that gets filed centrally stops being practice.
Open weights on Cloudflare Workers AI: llama-3.3-70b for reading, bge-large-en-v1.5 for retrieval, whisper-large-v3-turbo for the spoken answer, aura-1 for the customer voice. No model key in the stack. Rate limited, and every figure recomputed in code.