Walk into a well-run shop and look behind the till. Somewhere there is a laminated sheet: how we do refunds. Step one, check the receipt. Step two, if it is over a certain amount, call the manager. Step three, write it in the book. Nobody thinks the sheet is clever. It is useful because anyone can read it, a new starter can follow it, and when something goes wrong the manager can point at the step that was skipped.
Now picture the other way: “Ask Sam, she knows how we do refunds.” It works while Sam is in. But nobody can see Sam’s procedure or check which step she skipped last Tuesday, and when the policy changes you hope she remembers.
A single long prompt is Sam. A workflow is the sheet on the wall. An AI employee’s procedure should be the sheet: something a person on your team can read, test and change on purpose. For the wider map of tools, workflows, skills and agents, read tools, workflows, skills and agents: the difference; this post stays on one layer.
The short answer
In Wetel, what an AI employee does with a message is written down as a workflow: a graph of steps joined by arrows, which the team builds, tests and publishes. The language model is used inside that graph, at the steps that need language understanding. The decisions about what happens next (which branch, whether to call your order system, when to stop and ask a person) are steps you can see.
A person on your team owns that graph. They decide when a change goes live, and they can read afterwards which steps each conversation went through.
What is a workflow, concretely?
A workflow is a set of nodes (steps) connected by edges (arrows). Each node does one kind of thing, and the edges decide which step runs next. Every workflow has exactly one start node. From there, the documented node types are:
llm: calls the language model, to answer a question, classify what the customer wants, or pull a value out of free text.condition: a yes/no check on a value, with exactly two exits,trueandfalse.router: a multi-way branch that sends the conversation down the arrow whose label matches a value, for example a classified intent.response: sends a reply to the customer. It is the only step that talks back directly.tool,actionandwebhook: call your own systems, through a registered connector, a registered REST endpoint, or a URL set on the step itself.await_reply: asks the customer a question and waits for the answer before carrying on.approval: pauses until a workspace owner approves or rejects.sub_agent: hands the turn to one or more other agents at the same time and collects what comes back.end_session: ends the conversation.
A small order-status procedure looks like this:
flowchart TD S["start"] --> C["llm: what does the customer want?"] C --> R{"router"} R -- order_status --> T["tool: look up the order"] R -- general --> G["response: how I can help"] T --> O["response: the order status"] O --> E["end_session"] G --> EYou can read it top to bottom and say what it will do. That is the whole point.
Where the model works, and where plain rules work
The llm node is the only step that calls a language model. Conditions and routers are plain rules: they compare a value and pick an arrow, the same way every time. That split is the most useful thing a graph gives you.
The model is good at reading a messy message and saying “this is about an order” or “the order number is 48213”. It is not good at being certain. So the graph uses the model to turn language into a value, then hands that value to a rule.
Two documented options make that hand-over sturdier:
matchAnyOfon a classification step: you list the valid labels, and the step stores whichever label appears earliest in the model’s answer, even if the model rambled. If none appears, the raw answer is kept and the router falls back to its default path.extractFirstIntegeron an extraction step: the step keeps the first whole number in the model’s answer, and stores0when there is none. A condition then checksorderId > 0before anything calls your order system. A condition that references a missing value takes thefalsebranch, and the docs recommend writing every gate so that the branch that calls out is thetrueone: when in doubt, nothing goes out.
The best practices add a habit worth stealing: keep extracting a value and writing a reply in separate steps, and tell an extraction step plainly that it is a pipeline step, not the assistant talking to the customer.
A graph also makes memory explicit. Each new message starts a fresh run at start, carrying only the conversation transcript. If the next message must be treated as the answer to one exact question, you say so with an await_reply step. See how continuity between turns works.
Why one long prompt is harder to trust
A long prompt puts every rule in one place that only the model reads, so when it goes wrong you cannot tell which rule it skipped. “Classify the message, find the order number, never quote a delivery date, check the number is valid, ask a manager before any refund, be friendly” is six procedures in a trench coat.
When a reply comes out wrong, the prompt gives you nothing to point at. Was it the classification? The extraction? The refund rule? You tweak a sentence and hope.
Our own guidance says: if the same kind of mistake keeps coming back, change the structure of the workflow, for example by splitting a task into simpler steps, rather than patching the prompt again. A graph is what makes that split possible, because each step has its own output you can inspect.
This is not an argument against prompts; every llm step has one. It is an argument for short prompts with one job each, joined by arrows a person can read.
Draft and published: a person decides when it goes live
Every edit is saved to a draft, and a change reaches customers only when someone on your team publishes it. Saving (updateWorkflow) always writes to the draft. Live conversations run whatever was published most recently. A workflow that has never been published does nothing for real conversations, which is the most common reason a new AI employee seems to ignore its instructions.
Publishing also checks the graph’s shape. It refuses a graph with no start or more than one, an arrow pointing at a step that does not exist, two steps with the same id, a step with no path from start, or a step missing its required settings. These workflow operations need a signed-in person; an API key cannot save or publish them.
One honest limit on versions: each publish increases a version number, but earlier versions are not kept as copies you can fetch. The docs advise keeping your own copy of the graph before each publish, so you can put the old one back yourself if a new version misbehaves.
How do you test it before customers see it?
You run the draft in a test conversation, read what each step did, and replay saved real conversations against your changes. A test message can run the draft instead of the published version. A regression scenario freezes a real, completed run as a baseline and replays it against your current draft; pass or fail compares the path taken (steps visited, branches, calls made, final step), never the wording of the reply. That catches the quiet failure where a new prompt or model makes a classification step start choosing a different branch.
There is no offline simulator: testing means running a real session against the draft, so point steps that call your systems at test data first. See trying a workflow safely before customers see it.
How do you check what it actually did?
Every run leaves a record of each step visited, in order, with what it produced and any error. For steps that call your systems it includes the request actually sent. This is where a graph pays off a second time: the record is written in the same steps you designed, so “it said the order shipped” can be checked against the step that looked it up. See what a run record is and how to read one.
Where does a person step in?
Where you put an approval step, and only there. Approval is not on by default. An approval step pauses the run until a workspace owner approves or rejects it, optionally editing fields you allow. If nobody decides in time (72 hours by default, at most 14 days), the run follows an expired arrow you must draw. Owners get an in-app notice; email notice is not sent yet. Approvers beyond workspace owners are not built.
Because the step sits in a graph, you can see exactly which actions wait for a person and which do not. See what an AI employee should do on its own and designing approval steps people actually read.
Limits that are written down
A workflow and each run have documented ceilings, so a runaway graph stops with a clear reason instead of running forever.
| Limit | Value |
|---|---|
| Steps per workflow | 200 |
| Arrows per workflow | 400 |
| Step executions per run | 250 |
| Time per run | 10 minutes |
| Times one step may run per run | 1 by default, up to 100 if you set it |
The size limits apply when you save a draft, not just when you publish. A run that hits the execution or time ceiling is recorded as failed, with an entry naming the step it stopped in front of. See graph size and run limits and loops and re-entry.
What a graph does not fix
A graph makes the procedure visible; it does not make the model’s answers correct. A classification step can still choose the wrong label. matchAnyOf only helps when the right label appears somewhere in the model’s answer. An answer written from your knowledge base can still be wrong. The graph narrows where a model can go wrong and shows you where it did; it does not remove the model.
We have not published accuracy figures for any workflow, and we will not imply one. What we can say is structural: model steps and rule steps are separate and visible, a person decides when a change goes live, and every run can be read afterwards. Whether the procedure is good enough for your work is something you find out by testing it on your own messages.
The laminated sheet does not make the new starter good at the job. It makes the job checkable. That is what you want from an AI employee too, and from whoever manages it.
Related reference docs
- Workflow overview: node types, arrows and labels, publishing checks, limits and how turns carry over
- Workflow best practices: separating extraction from replies, and regression scenarios before risky edits
- Worked examples: three complete graphs, including an order lookup that checks the number first
- LLM node: the one step that calls a model, with
matchAnyOfandextractFirstInteger - Condition node: yes/no checks, and why a missing value takes the
falsebranch - Router node: branching on a classified value, the default path and the safety net
- Approval node: pausing for a workspace owner, and the three required arrows
- Workflows API: regression scenarios: replaying a saved run against your draft
If you are deciding where to start, tell us which work you’d hand over first and we will help you sketch its procedure as a graph.