Cost and limits
Everything so far was about making it work. This page is about what it costs to run, where it gets less accurate as it grows, and what to watch once real employees are using it.
Worth reading before you scale this to a second department, because two of the three limits below only appear at size.
What each turn actually pays for
A turn isn't billed by how much the employee typed. It's billed by everything the agent had to be told in order to answer — and most of that is things you attached, not things they said.
| What you attached | What it costs |
|---|---|
| Tools on the node | Every tool's name, description and input schema goes into the prompt on every turn, whether or not it's called. The collect-and-validate node with six validators pays for six on every turn |
| Global tools | Attached to every applicable agent. Escalation belongs here; a validator does not |
| Conversation history | Necessary for Policy Q&A, where follow-ups depend on context. Near-useless on a validator node that only reads one answer |
| Variables you declared | Every declared variable is a prompt input each turn. The employee object earns it; a field nobody reads doesn't |
| A large tool result | getEmployeeDetails returns a whole record. Left to come back to the agent, that record sits in context for the rest of the step |
| Each agent's trigger | Every agent's trigger enters the routing prompt on every turn. Ten agents means ten triggers weighed before anything happens |
The three that pay best here
Store the employee record, don't return it. getEmployeeDetails returns identity, region, entitlements and eligibility flags. The gate node needs to know it succeeded; it doesn't need to read the payload aloud. Set Store output in and the value stays available to every later node without riding in the conversation. See Store output in.
Turn conversation history off on the validator nodes. collect-and-validate asks for one field and reads one answer. Prior turns change nothing about whether a date is valid, and they're the largest single input on that node.
Don't make the validators global. They're needed by two flows, not by every agent. A global tool is weighed by every agent on every turn — that's the right trade for escalation and the wrong one for validateCity.
Where this design degrades
Three limits, in the order you'll hit them.
The service menu, as the catalogue grows
offer-services fans out to four destinations today. Exits are capped at five per node, and accuracy falls before you reach the cap — a node choosing between three clearly different outcomes is far more reliable than one choosing between five similar ones.
This is why the design puts menu contents in a variable and menu destinations in exits. Adding "payslip download" as a service the lookup returns costs nothing. Adding it as a fifth branch costs you accuracy on the other four.
When you genuinely need more destinations, group them: one node picks the category, a second picks within it. See when the branches really do go ten different places.
Policy Q&A, as the handbook grows
The failure here isn't a wrong answer, it's a confident one. Two things hold it:
- Match strictness. Loosen it and the agent starts answering from a neighbouring policy — the UK carry-over rule offered to an employee in India. Tighten it and it says "not covered" too often. Balanced is the right starting point; move deliberately, one step at a time, against a fixed set of real questions.
- Scope by region. Where a policy differs by region, the answer has to be scoped to this employee's region. This is why the identity lookup runs before anything, including the questions that feel like they don't need it.
Policy in the handbook, never in the prompt. A rule written into an agent's instructions goes stale with no warning and no version history — nobody reviews a prompt when the leave policy changes. The handbook is a single place that gets updated, and the agent reports what it says.
Identity, as more journeys are added
Every transactional journey opens with the same access check. The identity lookup doesn't repeat — it runs once in the session-start hook and every journey reads employee — but that makes it the one call standing between an employee and everything they came for.
Two consequences. Its latency is felt on the very first turn, before anything else can happen, so if it's slow the employee is watching silence at the worst possible moment. And its failure is silent: nothing has been said yet, so an agent that only sees an empty employee cannot tell an outage from an unknown employee.
Both are why the workflow returns a status alongside the record, and why the gate node handles the empty case explicitly rather than assuming the hook succeeded. If a fifth journey is coming, this is the tool to make fast — not the one to copy into another node.
What to watch once it's live
Three signals tell you more than a satisfaction score:
- Fallback rate on policy questions. A spike usually means a handbook document is missing or badly tagged, not that the agent got worse.
- Where people ask for a human. The most honest map of what's missing or mistrusted. Pay and eligibility questions cluster here.
- Requests that stall mid-procedure. Usually a collect step asking for something people don't have to hand — an employee code, a document number. Move it, default it, or look it up.
Each of those points at a change, and each change goes back through the regression set before it ships.
What we deliberately didn't do
The alternatives worth knowing about, and why they were rejected:
No leave application. It's the most-requested HR journey and it's not here, because Northwind's HRMS owns the write path. Building it in the assistant would create a second source of truth for balances. Deep-link to the HRMS instead, and answer questions about leave from the handbook.
No access rule in a prompt. "Only issue letters for the employee's own record" would read perfectly and hold most of the time. Self-vs-manager access is a node so the wiring enforces it, because "most of the time" is the wrong reliability for one employee seeing another's data.
No single agent for the letter journey. It would be quicker to build and would usually work. But the access check must gate the generate step, and a reasoning agent can be talked past a step it's merely been told to take.
No shared retry budget. Each collect step owns one retry count with its own max_retry branch. Counting attempts across a whole flow in prose is how nodes start re-asking a fourth time, or giving up on the second.
No real systems during the build. Every workflow returns realistic sample data. It means the whole assistant is testable on day one, and swapping in the real HRMS later doesn't touch a single agent.
Next: Templates.