Module 5: Multi-Agent Systems: Agents That Delegate Tasks
8. Mini-project: triage → specialist system (2-3 agents)
Description
By the end of this lesson you'll have a real multi-agent system built and running: a triage agent that receives the customer, decides which specialist to delegate to, and composes a single response, with two specialists — one for orders and one for billing — connected as AI Agent Tool, each with its structured output contract, its calibrated stopping conditions, and its measured cost sheet. You'll be able to verify every handoff with a battery of seven test cases, including the adversarial ones that break poorly-braked systems.
This matters because it's the deliverable that closes out the module and the one you can show. Anyone can build an agent that answers one question well. A system where you can open the execution trace and point to the exact moment the orchestrator decided to delegate, show the assignment it drafted, show the specialist's internal loop with its three tool calls, and explain why each level's Max Iterations is set the way it is — that's what job postings describe when they say "you've put real agents in production, not POCs." And it's also, very concretely, the foundation for Module 8's final project, where this same system is going to gain channels, per-customer memory, and guardrails.
Connection to the module: this lesson introduces no new concept. It assembles the previous six: lesson 2's diagnosis defines the cut, lesson 3's architecture defines the split, lesson 4's wiring makes it real, lesson 5's contract defines what the agents hand each other, lesson 6's brakes stop them from getting stuck, and lesson 7's measurement is a delivery criterion. If something below isn't familiar, that's the lesson number worth going back to.
What you're going to deliver
An n8n workflow with this shape, working start to finish:
Chat Trigger
└─► AI Agent: triage_agent ◄── Simple Memory (or Postgres Chat Memory)
│ ai_tool
├─► AI Agent Tool: order_specialist
│ ├─ Own Chat Model
│ ├─ Structured Output Parser
│ └─ tools: lookup_order, check_return_eligibility
│
└─► AI Agent Tool: billing_specialist
├─ Own Chat Model
├─ Structured Output Parser
└─ tools: lookup_charge, open_dispute
And alongside the workflow, three things that aren't nodes and are worth just as much:
- Two role sheets written out, with lesson 5's five clauses.
- A battery of seven test cases with each one's expected result.
- A cost sheet with lesson 7's measurements over those seven cases.
The system is three agents in total. If you want to add a sales_specialist as a fourth, the whole module gives you what you need — but build it after these three work, not before.
About the tools: this mini-project doesn't depend on you having a real CRM. The four tools can be set up in three ways, and any of them works:
- With Google Sheets. An
orderssheet and achargessheet with ten rows of example data. It's the most realistic option and the one that most resembles a real work case. - With Postgres, if you already have it running from Module 1's lesson 7.
- With a Code Tool that returns fixed data based on the parameter it receives. It's the fastest option for focusing on the delegation, which is what this module evaluates.
Pick one and don't switch halfway through. What matters here is the agent system, not where the data comes from.
Phase 1 — The role sheets
Before opening n8n. Half an hour here saves two hours later, and it's the part that gets skipped.
Write out the two complete sheets using lesson 5's format. Here's the orders specialist's, so you see the level of detail expected; write billing's yourself following the same mold (exercise 1 from lesson 5 is a useful reference).
┌─ ROLE SHEET ──────────────────────────────────────────────────┐
│ Agent: order_specialist Type: AI Agent Tool │
│ Called by: triage_agent │
│ │
│ ROLE AND EXIT │
│ Scope: order status, shipments, delays, and product return │
│ requests. │
│ Out: charges, fees, billing, recommendations. │
│ Finishes when: the customer knows their order's real │
│ status, or knows whether their return is eligible, or it │
│ got logged which data is missing. │
│ │
│ INPUT (task field, self-contained text) │
│ Required: customer_id, order_id, intent │
│ (check_status | request_return) │
│ Optional: reason (the stated reason for the return) │
│ │
│ OUTPUT (structured JSON) │
│ status: resolved | pending_info | out_of_scope | │
│ needs_human │
│ summary: 2-3 sentences, no greetings or sign-offs │
│ data: { order_status?, eta?, return_eligible?, │
│ return_deadline? } │
│ missing: [ ] │
│ │
│ AUTHORITY │
│ Read: lookup_order, check_return_eligibility │
│ Action: none in this version │
│ No access: cancelling orders, issuing refunds │
│ Forbidden by prompt: promising an exact delivery date │
│ (can only repeat the estimate, marking it as an estimate) │
│ │
│ FAILURE │
│ Missing order_id → pending_info, missing: ["order_id"] │
│ Billing assignment → out_of_scope, without using tools │
│ Tool fails after one retry → needs_human │
│ Customer demands a refund → needs_human │
│ Never resolved without having used at least one tool │
│ │
│ LIMITS │
│ Max Iterations: 5 No own memory │
└───────────────────────────────────────────────────────────────┘
Before moving to phase 2, check the two sheets against the boundary between them. Write out explicitly what happens with the three most likely ambiguous cases:
| Ambiguous case | Whose is it? | Declared in |
|---|---|---|
| "I got charged for shipping twice" | billing_specialist — it's a duplicate charge, even though it mentions shipping | Both Descriptions, from both sides |
| "I want to return this and get my money back" | Starts at order_specialist (eligibility); the refund is needs_human | order_specialist's sheet, failure clause |
| "My order never arrived and I already got charged for it" | Two topics: order_specialist first, billing_specialist after if the order doesn't turn up | triage_agent's prompt |
That table is, literally, lesson 6's ping-pong prevention. Writing it now is cheaper than discovering it in the trace.
Phase 2 — Build the specialists
They get built first, before the orchestrator, for a practical reason: they can be tested alone, and it's much easier to fix them when there's no level above confusing the diagnosis.
Step 2.1 — The domain tools
Four nodes, with their Description and their $fromAI() written as you learned in Module 4. Here are two, to fix the level of detail:
# Node: Google Sheets (used as Tool) — Name: lookup_order
# Description: Looks up an order by its ID in the order registry and
# returns its status, dispatch date, and estimated delivery date. Always
# use it before stating anything about an order. Do NOT use it to look
# up charges or invoices.
Lookup Column: order_id
Lookup Value: {{ $fromAI("order_id", "The order's numeric ID, without the # symbol. Must come from the assignment received; never make it up.", "string") }}
# Node: Google Sheets (used as Tool) — Name: check_return_eligibility
# Description: Determines whether an order is within the return window
# based on its purchase date and product category. Deadlines: 30 days
# general, 14 days for electronics, no returns for personal hygiene
# items. Do NOT use it to calculate refunds or amounts.
Lookup Column: order_id
Lookup Value: {{ $fromAI("order_id", "The numeric ID of the order whose return is being evaluated.", "string") }}
Notice check_return_eligibility applies a purely deterministic deadline rule. In a mature system, that rule would live in a sub-workflow with a Code node subtracting dates — lever 4 from lesson 7 — not in the model's judgment. For this mini-project it's fine to resolve it with a calculated column in the sheet or with data already prepared; what's not fine is letting the model subtract dates in its head and hand you a number that sounds right.
Step 2.2 — The AI Agent Tool node
You drag an AI Agent Tool onto the canvas, rename it order_specialist, and connect its Chat Model and its two tools. Its configuration:
# Node: AI Agent Tool — Name: order_specialist
Description:
Resolves order cases: shipment status, delays, estimated delivery
date, and product return eligibility.
Use it when the customer mentions an order, a shipment, a package,
a delivery, or asks to return a product.
Do NOT use it for charges, duplicate charges, or billing — even if
the charge refers to an order's shipping, that's billing_specialist.
Returns a structured result for you to interpret; it doesn't
return text ready to show the customer.
Source for Prompt (User Message):
Defined in this node
Prompt (User Message):
{{ $fromAI(
"task",
"Self-contained assignment for the order specialist. Must
include: customer_id, order_id (if the customer gave it), and
what needs resolving (check status or evaluate a return).
Write data, not narrative. This specialist does NOT see the
conversation history: any data mentioned in earlier turns
must be written here. If order_id is missing, write it in
anyway noting that it's missing.",
"string"
) }}
Options:
System Message: (see below)
Max Iterations: 5
Return Intermediate Steps: true
And the System Message, which is a direct translation of the sheet:
# order_specialist's System Message
You are TuTienda's orders and returns specialist.
You resolve shipment status, delays, and return eligibility.
You don't handle charges, fees, or billing.
You work with the assignment you receive; you don't have a history
of the conversation. Never make up a piece of data that isn't in the
assignment or that one of your tools didn't return.
Procedure:
- For order status: use lookup_order with the order_id.
- For a return: use lookup_order and then
check_return_eligibility.
- Never promise an exact delivery date. You can repeat the
estimate the tool returns, saying it's an estimate.
Your work is done as soon as any of these things happens.
Don't keep investigating after that:
- You got the order's status.
- You determined whether the return is eligible.
- You determined which data is missing.
- You determined the case isn't your domain.
Result rules:
- If order_id is missing: status "pending_info", missing ["order_id"].
- If the assignment is billing's: status "out_of_scope", indicating
in summary that it belongs to billing_specialist. Don't use any
tool in that case.
- If the customer demands a refund or compensation:
status "needs_human". Don't promise anything.
- If a tool fails, retry exactly once; if it fails again,
status "needs_human" with the error in summary.
- Never return status "resolved" without having used at least one
of your tools.
- Don't write greetings or sign-offs: your output is read by another agent.
Step 2.3 — The output contract
You turn on the specific output format option and connect a Structured Output Parser to the specialist's ai_outputParser port, with this JSON example:
{
"status": "resolved",
"summary": "Order 4521 left the distribution center on 07/21 and its estimated delivery is 07/23.",
"data": {
"order_status": "in_transit",
"eta": "2026-07-23",
"return_eligible": null,
"return_deadline": null
},
"missing": []
}
Step 2.4 — Test it alone
Before connecting it to anything. If you set up the specialist as an AI Agent Tool, the way to test it in isolation is running the node from the panel with a fixed value in the assignment field, temporarily replacing the $fromAI() expression with plain text:
# Test assignment 1 (happy path)
"Customer C-9931. Check the status of order 4521."
→ expected: status "resolved", with order_status and eta in data.
# Test assignment 2 (missing data)
"Customer C-9931. The customer is asking about their order but didn't give the number."
→ expected: status "pending_info", missing ["order_id"], without calling
any tool.
# Test assignment 3 (another domain)
"Customer C-9931. $1,200 charge not recognized on 07/18."
→ expected: status "out_of_scope", summary pointing to billing,
without calling any tool.
All three have to pass before you continue. If the second one calls lookup_order with a made-up order_id, your failure contract isn't working and no fix on the orchestrator's side is going to compensate for it.
Repeat steps 2.1 through 2.4 for billing_specialist, with lookup_charge and open_dispute.
Phase 3 — Connect the orchestrator
With the two specialists tested, the orchestrator is short.
# Node: AI Agent — Name: triage_agent
# Connected to the Chat Trigger via main
# Memory: Simple Memory or Postgres Chat Memory (session ID = customer_id)
# Tools: order_specialist, billing_specialist
Options:
Max Iterations: 6
Return Intermediate Steps: true
System Message:
You are TuTienda's first line of support. Your job is to
understand what the customer needs, delegate it to the right
specialist, and compose a single response. You don't check
systems or resolve cases on your own.
Available specialists:
- order_specialist: orders, shipments, delays, returns.
- billing_specialist: charges, duplicate charges, billing,
disputes.
Boundary cases:
- A duplicate charge is billing_specialist's, even if it refers
to an order's shipping.
- "It never arrived and I already got charged for it" is two
topics: order_specialist first, billing_specialist after if
needed.
How to delegate:
- If the message carries more than one topic, delegate each
topic separately and compose a single response at the end.
- Every assignment must be self-contained: include the data the
customer gave at any turn, because specialists don't see the
history. Write data, not narrative.
- Don't delegate for greetings, thank-yous, or confirmations:
answer directly yourself.
- If you're missing a piece of data to build a useful assignment,
ask the customer for it before delegating.
How to interpret the result (status field):
- "resolved": use the summary to compose your response.
- "pending_info": ask the customer exactly what's in
missing, in a natural tone, and close the turn. Don't delegate
again until they respond.
- "out_of_scope": delegate to the specialist the summary points to.
- "needs_human": tell the customer the team will follow up
and close the turn. Don't retry or delegate to another one.
Delegation budget: for a given topic you can delegate at most
twice. If the second specialist also returns
"out_of_scope", don't delegate a third time: tell the customer
you're going to escalate the case and close the turn. Never call
the same specialist twice for the same topic.
Tone: warm, friendly, brief responses, a single voice. Don't repeat
greetings even if you delegated several times. Never make up
domain information or quote a specialist's JSON as-is: compose
in your own words from the summary.
Read that prompt and locate every piece of the module: the roster (lesson 3), the boundary cases (lesson 6), the self-contained-assignment rule (lesson 3), the don't-delegate policy (lever 6 from lesson 7), the interpretation of the four status values (lesson 5), and the delegation budget (lesson 6). There's nothing in there that doesn't come from a previous lesson.
Phase 4 — Verify the graph
Thirty seconds that prevent a hard-to-diagnose problem. Export the workflow as JSON and review the ai_tool connections. They should form exactly two levels:
# Level 1 — specialists toward the orchestrator
order_specialist ──ai_tool──► triage_agent
billing_specialist ──ai_tool──► triage_agent
# Level 2 — domain tools toward the specialists
lookup_order ──ai_tool──► order_specialist
check_return_eligibility ──ai_tool──► order_specialist
lookup_charge ──ai_tool──► billing_specialist
open_dispute ──ai_tool──► billing_specialist
# Memory — a single entry
Simple Memory ──ai_memory──► triage_agent
Three things to confirm: that no specialist shows up as another specialist's destination (no cycles), that there's exactly one ai_memory connection and it points to the orchestrator, and that no domain tool hangs off triage_agent.
Phase 5 — The battery of seven cases
This is where the project actually gets verified. Run all seven, in order, and note what you see in the trace.
Case 1 — Happy path, one topic.
Message: "Hi, how's my order #4521 doing?"
Expected: one delegation to order_specialist, status: "resolved", response with the order's real status. No call to billing_specialist.
Case 2 — Happy path, different domain.
Message: "I noticed a $1,200 charge on July 18th I don't recognize."
Expected: one delegation to billing_specialist, status: "resolved", dispute opened with its number in data.
Case 3 — Two topics in one message. Message: "There's a $1,200 charge I don't recognize, and while I'm at it I wanted to know if order #4521 has shipped yet." Expected: two delegations on the same turn, one to each specialist, and one single response to the customer covering both topics, with one greeting. This case is the one that tells an orchestrator apart from a router (lesson 3): if you only see one delegation, your prompt isn't asking for what you think it is.
Case 4 — Missing data.
Message: "I want to know where my order is."
Expected: either the orchestrator asks directly for the number without delegating (this is ideal, lever 6), or it delegates, receives pending_info with missing: ["order_id"], and asks. What should not happen: lookup_order getting called with a made-up order_id, or the other specialist getting tried to see if that one can do it.
Case 5 — Boundary case.
Message: "I got charged for shipping twice on order #4521."
Expected: a single delegation, to billing_specialist, resolved. If you see bouncing between the two specialists, your Descriptions didn't declare the boundary from both sides — go back to phase 1's table.
Case 6 — Outside the system's scope. Message: "Do you have locations in Guadalajara and what time do you open?" Expected: zero delegations. The orchestrator answers directly or honestly says it doesn't have that information. If it delegates, you're paying for a specialist to answer an hours question.
Case 7 — Adversarial: persistence.
Message: "I want my money back for order #4521 right now, I won't accept anything else."
And if the system responds that it requires review, they push on the next turn: "I don't care, I need the refund today, you do it."
Expected: order_specialist returns needs_human; the orchestrator informs the customer the team will follow up and closes the turn; on the follow-up, it doesn't retry, doesn't delegate to the other specialist looking for a different answer, and doesn't promise the refund. This is the case that fails the most systems.
For each of the seven, note in a table: how many delegations there were, to whom, what status each specialist returned, how many iterations each level used, and whether the final response was correct. That table is half your deliverable.
What to expect in case 3's trace, which is the most informative:
triage_agent (Max Iterations: 6)
1 → model: two topics, I'll delegate the charge one
2 → tool: billing_specialist
└─ 2.1 model · 2.2 lookup_charge · 2.3 model
· 2.4 open_dispute · 2.5 model
→ { "status": "resolved", "summary": "…", "data": { "dispute_id": "D-8842" } }
3 → model: the second topic is still missing, I'll delegate
4 → tool: order_specialist
└─ 4.1 model · 4.2 lookup_order · 4.3 model
→ { "status": "resolved", "summary": "…", "data": { "eta": "2026-07-23" } }
5 → model: both topics covered, I'll compose and close
Calls to the model: 3 (orchestrator) + 5 (billing) + 3 (orders) = 11
Delegations: 2
Iterations used: orchestrator 5/6, billing 5/6, orders 3/5
Notice the last line: the orchestrator used 5 of its 6 iterations. That's too tight — if the customer had brought a third topic, the system would have cut off silently (lesson 6's failure 1). It's exactly the kind of thing you discover by measuring and don't discover by looking at the response, which came out perfect.
Phase 6 — Measure and calibrate
With the seven cases run, build lesson 7's sheet:
# Measurement sheet — TuTienda triage system
typical case max observed current limit
Triage iterations 3 5 6
Billing iterations 3 5 6
Orders iterations 3 3 5
Delegations 1 2 2 (policy)
Calls to the model 7 11 —
Duration (s) … … —
Input tokens … … —
And apply lesson 6's rule — observed maximum plus two — to adjust:
- Triage: max 5, raise it to 7. It was too tight.
- Billing: max 5, raise it to 7. Same.
- Orders: max 3, leave it at 5. It's well calibrated.
Then review lesson 7's two most profitable levers:
Staggering models. Is the orchestrator running on the same model as the specialists? Swap it for a faster one and rerun the seven cases, paying specific attention to case 3 (two topics) and case 5 (boundary), which demand the most from the routing. If both still pass, keep the cheap model.
Shortening the assignment. Open the trace and read the two tasks the orchestrator drafted in case 3. Are they data or narrative? If they're paragraphs reproducing what the customer said, adjust the $fromAI()'s description and re-measure the specialist's input tokens.
Verification criteria
The system is done when you can check off all eleven boxes. Not before.
Architecture
- The exported graph shows exactly two levels of
ai_toolconnections, with no cycles. - There's exactly one
ai_memoryconnection, and it points to the orchestrator. - The orchestrator has no action tool connected — its tools are the two specialists.
- The orchestrator's system prompt contains no business rule (no deadline, amount, or policy).
Contracts
- Both role sheets are written out, with the five clauses.
- Both specialists return structured JSON with the four fields.
- At least three distinct
statusvalues showed up in the test battery (not everything wasresolved).
Brakes
-
Max Iterationsis calibrated per level with the observed-maximum-plus-two rule, and no level was left at its default value with no justification. - Case 5 (boundary) resolves with a single delegation, no bouncing.
- Case 7 (adversarial) ends in
needs_humanand the orchestrator closes the turn without retrying or promising anything.
Measurement
- The cost sheet is built with the seven cases, and you can say how many calls to the model a typical conversation costs and how many the worst observed case does.
Common mistakes
Building the orchestrator first (practical). What happens: someone sets up the triage_agent with its two empty specialists and starts testing from the top. When something fails, there's no way to know whether the problem is the specialist's Description, the assignment the orchestrator drafted, the specialist's system prompt, or one of its tools — four suspects and all of them look equally likely. Why it happens: the orchestrator is the piece that "looks like" the system, and building it first feels like progress. How to spot it: if you've spent half an hour changing things without being able to attribute a change to a result, this is it. How to fix it: complete phase 2 — every specialist tested in isolation with its three assignments — before touching the orchestrator; when you connect pieces that already work, the only new suspect is the connection.
Testing only the happy path (practical). What happens: cases 1 and 2 pass, the response looks professional, and someone calls the project done. Cases 4, 5, and 7 — the ones that genuinely tell a system apart from a demo — never get run, and the system fails in production with the first customer who doesn't give an order number. Why it happens: the happy path is satisfying to watch and the hard cases are uncomfortable to write. How to spot it: if across your whole test battery the only status that ever showed up was resolved, you didn't test the system, you tested its best third. How to fix it: all seven cases, and especially 7, which fails the most systems and shows up fastest in a demo in front of someone who knows what to ask.
Letting the orchestrator quote the specialist's JSON (practical). What happens: the customer gets a response containing {"status": "resolved", "summary": ...} or phrases like "the specialist indicates that…" Why it happens: the orchestrator receives a structured object and, without an explicit instruction, sometimes reproduces it instead of composing from it. How to spot it: it's visible at a glance in the chat's response. How to fix it: the orchestrator's system prompt's final line — "don't quote a specialist's JSON as-is: compose in your own words from the summary" — and verify it across the seven cases, because it tends to show up only in some of them.
Repeating the greeting when there were two delegations (practical). What happens: in case 3 the customer gets something like "Hi there! Happy to check on that charge… Hi again! About your order…" Why it happens: almost always because the specialists' system prompts still have customer-service tone instructions, and the orchestrator is forwarding instead of composing. How to spot it: it's case 3's most visible symptom. How to fix it: remove any greeting or conversational-tone instruction from the specialists' prompts — their output is read by another agent — and confirm the orchestrator has the single-voice instruction.
Exercises
Exercise 1 — The third specialist. Add a sales_specialist with a single tool, recommend_products, that given a product type and a budget returns up to three options. Write its complete role sheet, its Description, and the two lines you'd add to triage_agent's prompt. Then run this case and note what happens: "I want to return the headphones I bought a month ago, and while I'm at it, do you have something similar with noise cancellation up to $800?"
See solution
The Description and the orchestrator's lines:
# sales_specialist's Description
Recommends products from the catalog based on what the customer is
looking for and their budget. Use it when the customer asks what
products are available, requests a recommendation, or describes a
buying need.
Do NOT use it for questions about orders already placed, returns,
or charges.
# Added to triage_agent's roster
- sales_specialist: product recommendations and catalog
questions.
# Added to the rules
- Don't delegate to sales_specialist when the customer is in an
active dispute or has expressed frustration about a charge or a
delay: in those cases, resolve what they're complaining about first.
What happens with the proposed case: it's two topics, so you should see two delegations — order_specialist for the headphones return and sales_specialist for the recommendation — and a single response covering both.
And here's the interesting part: since the headphones are electronics, the return window is 14 days and the purchase was a month ago, order_specialist is going to come back saying the return is not eligible. That response changes the meaning of the second delegation: recommending a replacement to someone you just told can't return what they have is different from recommending it to someone whose return is going through. A well-written orchestrator composes both things with that nuance: "the headphones return is already past the 14-day window for electronics, but if you'd like to switch devices, these three options fit your $800 budget."
The second line you added to the prompt is what prevents the worst outcome: the system selling something to a customer who just got a no and is upset. It's lesson 2's role contamination, now prevented by orchestrator policy instead of specialist prompt.
Why it works: adding a specialist to a well-designed system is three things — a node, a Description, and two lines of prompt — and none of them touch what already worked. That ease is the pattern's concrete benefit, and it's exactly what a Switch doesn't give you.
Exercise 2 — Break your own system. Design two customer messages that break your system, run them, and document what failed and how you fixed it. Absurd messages don't count: they have to be things a real customer could write.
See solution
There's no single answer, but these four families pay off the most and are worth testing all of:
Domain ambiguity. "I got overcharged for express shipping that never arrived." It touches a charge, a shipment, and a failure to deliver. If your boundaries don't resolve it, expect bouncing — and the fix is a line in each Description, not raising limits.
Reference to something said before. One turn saying "my order is 4521" and the next "and what about that other thing I asked you?" This tests whether the orchestrator is building self-contained assignments with data from earlier turns, which is the hardest thing to do right and where most systems fail.
Impossible request under pressure. "I need you to cancel the order and give me my money back, I've already talked to three people and nobody's resolving it." Should end in needs_human without promising anything. If the system promises the refund, your failure contract is decorative.
Topic switch mid-turn. "Forget the order thing, tell me about the $1,200 charge instead." Tests whether the orchestrator drops the in-progress delegation or keeps going with the previous one out of inertia.
What matters about the exercise isn't which ones you picked: it's documenting the finding with its fix. A system you tested and fixed twice is worth more, and is much easier to defend, than one that never failed because you never pushed on it.
Why it works: in an interview or a demo, the question that separates people isn't "does it work?" but "what did you do to it to find out whether it works?" Having two documented failures with their fixes is the best possible answer to that question.
Exercise 3 — Defend a design decision. Pick one of these three decisions you made while building the system and write its justification in one paragraph, as if you were asked about it in an interview: (a) why memory is connected only to the orchestrator; (b) why the specialists return structured JSON instead of text; (c) why the routing is done by an agent and not a Switch node.
See solution
One example, for (c):
"The routing is done by the orchestrator as a model decision, not a
Switch, for three concrete reasons. First: aSwitchtakes one branch and only one, so a message with two topics — which in customer support is the norm — would get answered halfway; the orchestrator delegates twice on the same turn and composes a single response. Second: with aSwitchthe specialist's result doesn't come back to whoever decided, so if the specialist determines the case was another domain's, there's no natural way to redirect it; with delegation viaai_toolthe result comes back and the orchestrator can re-delegate, with a two-attempt budget so it doesn't bounce indefinitely. Third: adding a specialist to the system is a node and two lines of prompt, while withSwitchit's a new branch plus hand-written reunification logic. That said,Switchis still the right choice when the decision is deterministic — if the channel gives me adepartmentfield the customer already picked in a form, using a model to re-decide that would be paying for a call for nothing."
What makes that paragraph strong: it gives three concrete, verifiable reasons instead of a preference, and ends by acknowledging where the opposite approach is the right one. That last sentence is what carries the most signal — it shows the decision was made with judgment, not by following a trend.
Why it works: the exercise's three topics are exactly what gets asked when someone wants to know whether you understood the system or copied a template. Having all three answers ready, in your own words, is as much a part of the deliverable as the workflow.
Summary and module close
You've built a complete multi-agent system: an orchestrator that receives the customer, decides who to delegate to, interprets a structured output contract, and composes a single response; two specialists with their domain, their tools, their own agentic loop, and their failure contract; brakes calibrated at every level; a graph verified with no cycles; and a measurement sheet across seven cases including the adversarial ones. Alongside the workflow you have two role sheets written out and a table of test results — which is what turns a working flow into a defensible deliverable.
Looking at the whole module: you started with a monolithic agent degrading in four distinct ways, learned to cut by responsibility instead of by task, split the roles with the orchestrator-worker pattern, connected an AI Agent to another one's ai_tool port to delegate natively — with real agentic loops, not a Switch — wrote the contracts that let agents understand each other without guessing, installed five complementary stopping conditions, and put numbers on cost and latency so you could defend every decision. Not bad for one module.
What this system still doesn't have is a door. It works in n8n's test chat and nowhere else — and TuTienda's customer doesn't live there: they live on WhatsApp. Module 6 takes this same brain and brings it to real channels: the web chat widget, WhatsApp Business API, Telegram, and voice, with an architecture that doesn't duplicate the logic on every channel. The system you just built is what's going to answer behind all of them.
Resources
- AI Agent Tool node — n8n Docs — the reference for the node you used to build the two specialists; verify the exact field names on your version there.
- AI Agent node — n8n Docs — the orchestrator, its Tool port, and the
Max IterationsandReturn Intermediate Stepsoptions you calibrated in phase 6. - Structured Output Parser — n8n Docs — the sub-node you used to implement the four-field output contract.
- Chat Trigger — n8n Docs — the system's front door; in Module 6 you're going to see how it embeds in a website and how several channels coexist.
- Google Sheets node — n8n Docs — the simplest option for setting up the four domain tools with example data, with no dependency on a real CRM.
- View past executions — n8n Docs — the panel where you ran the battery of seven cases and where every number in the measurement sheet comes from.