Why your Agentforce agent keeps picking the wrong topic: designing subagents, actions, and classification descriptions
The refund question routes to the returns subagent every third try, and no amount of instruction-tweaking fixes it. The problem isn't your prompt — it's that two subagents describe overlapping jobs, and the Agent Router can only read what you wrote in the classification. Here's how routing actually works, how to design subagents that don't collide, and the 15-topic ceiling that forces the next decision.
Here’s the failure that lands on every Agentforce builder’s desk eventually. You have an agent with a Returns topic and an Order Status topic. A customer types “I want my money back for the jacket that never showed up,” and the agent cheerfully starts a return — for an order that was never delivered, which should have gone to the shipping-exception path instead. You reopen the topic instructions, add “only start a return for delivered orders,” test again, and it works. Twice. The third time, a slightly reworded utterance routes wrong again.
Nobody misconfigured anything. What you’re fighting is the single most misunderstood thing about how an Agentforce agent works: the agent chose the wrong topic before your instructions ever ran. Instructions govern behaviour inside a topic. They have no vote in which topic gets picked. That decision happens one layer up, in a component that reads almost nothing about your agent except the short descriptions you probably wrote last and thought about least. This post is about that layer — how routing actually works, why semantic overlap is the root cause of most “my agent is dumb” tickets, how to design subagents and actions that don’t collide, and the hard 15-topic ceiling that eventually forces you into a different architecture.
Say the new names out loud, because the docs are mid-rename
First, terminology, because Salesforce changed it in the middle of everyone’s learning curve. Beginning in April 2026, agent topics are now called subagents. Same object, same behaviour, new noun — there’s no functional change, but you’ll see both words in the UI and the docs during the transition. The component that used to be the Topic Selector is now the Agent Router. Throughout this post I’ll say subagent and Agent Router, and treat “topic” as the synonym you’ll still see on screen.
The building blocks haven’t changed, only the labels:
- An agent is the whole assistant a user talks to.
- A subagent (topic) is a job to be done — Returns, Order Status, Account Management. It’s a bounded slice of the agent’s total responsibility.
- Each subagent owns a set of actions — the concrete things it can do (a Flow, an Apex invocable, a prompt template, a standard action).
- Each subagent and each action carries natural-language descriptions — and those descriptions, not your carefully written instructions, are what the router reads to decide where a request goes.
That last point is the whole ballgame, so let’s pull it apart.
The Agent Router reads a summary, not your agent
When a message arrives, the Atlas reasoning engine runs a Reason–Act–Observe loop, and the very first reasoning step is classification: which subagent is this request about? Here is the part that surprises people — the router makes that choice by matching the user’s utterance against the classification description and scope of each subagent. It does not read your topic instructions, it does not read your action logic, and it does not know what your Flow does internally. It sees a list of short descriptions and picks the best semantic match, the way you’d skim a table of contents.
So a subagent has three text fields that matter, and they do different jobs:
- Classification description — a summary of what this subagent covers. This is the field the Agent Router matches against. Get this wrong and the request never reaches your instructions.
- Scope — a statement of the subagent’s purpose and boundaries. It reinforces classification and tells the model what this job is and isn’t.
- Instructions — the guidelines for how to handle the conversation once the request is already inside the subagent. Critical for behaviour, invisible to routing.
Read that list twice, because it explains the bug at the top of this post. Adding “only start a return for delivered orders” to the instructions of the Returns subagent does nothing for routing, because the router never reads instructions. The undelivered-jacket message keeps landing in Returns because the Returns classification description still semantically out-competes the Order Status one for the phrase “money back.” The fix isn’t a better instruction. It’s a sharper boundary between two classification descriptions.
Routing quality is a property of your classification descriptions and their distinctness from each other — not of your instructions, not of the model’s intelligence. If two subagents can plausibly claim the same utterance, the model will sometimes pick the wrong one, forever.
Semantic overlap is the root cause, and it’s almost always self-inflicted
The dominant reason an Agentforce agent routes badly is semantic overlap: two subagents (or two actions within one subagent) whose descriptions occupy the same meaning-space. The Agent Router is doing nearest-neighbour matching in a semantic space. If “I want a refund” sits equidistant between a Returns subagent described as “handles refunds and returns” and a Billing subagent described as “handles refunds, charges, and adjustments,” the router has no principled way to break the tie. It will look decisive and be wrong a predictable fraction of the time.
The discipline that fixes this is to design subagents so they are mutually exclusive and collectively exhaustive over the jobs your agent does. Two rules do most of the work:
- One job per subagent, stated as a job, not a data object. “Returns” is a job. “The Order object” is not — it invites every order-shaped utterance regardless of intent. Name and describe subagents by the outcome the user wants.
- Make the classification descriptions contrast, not just describe. It isn’t enough for each description to be individually accurate. Each one has to be distinguishable from its neighbours. If two descriptions could be swapped without either becoming false, the router can’t tell them apart either.
Concretely, the collision above is resolved not by more words but by drawing a line and writing it into both descriptions:
Subagent: Order Status & Delivery Issues
Classification: Use for questions about where an order is, delivery delays,
missing or undelivered packages, and shipping exceptions. Use this even when
the customer asks for money back BECAUSE a package never arrived — an
undelivered order is a shipping issue, not a return.
Subagent: Returns & Refunds
Classification: Use only for returning an item the customer has RECEIVED and
wants to send back. Do not use for undelivered or missing packages.
Notice what changed: nothing about the actions, nothing about the instructions. We taught the router the boundary by putting the discriminating fact — received vs. never arrived — into the two fields it actually reads, and by naming the exception explicitly in both. This is the single highest-leverage edit in Agentforce agent design, and it’s the one most teams skip because they spend their attention on instructions.
Actions have the same problem one level down
Everything true of subagents is true of actions inside a subagent. Once the router picks a subagent, the reasoning engine chooses an action the same way — by matching intent against each action’s description. So an action’s description is the most important thing about it, more than the Flow or Apex behind it. We’ve argued before that for custom Apex actions, the description is the code that matters most; the same holds for every action type.
Two action-level habits that pay off:
- Describe inputs and outputs in the description, not just the verb. “Looks up an order by order number and returns status, carrier, and estimated delivery” tells the reasoning engine both when to call the action and what it will get back to reason over next. A bare “gets order info” leaves it guessing.
- Keep actions within a subagent semantically distinct too. If a subagent has “cancel order” and “modify order” and both descriptions say “changes an order,” expect the engine to fumble the choice. Contrast them the same way you contrast subagents.
One operational gotcha to design around: the Atlas loop can call an action multiple times in a single turn while it works toward the user’s intent. If your action is an Apex method that runs a SOQL query or a callout, that looping can burn through governor limits fast. Build actions to be idempotent and cheap, and assume the engine may invoke them more than once — the decision of what belongs in Flow, Apex, or a prompt should weigh this.
Standard vs. custom subagents: start from the template, then diverge
When you build from a Salesforce template — a service agent, say — you inherit standard subagents with pre-written classifications and actions. These are genuinely useful starting points, and the Salesforce guidance is right: read the standard topics, their instructions, and their actions carefully before you change anything, so you understand why the agent behaves as it does before you start moving furniture.
The trap is bolting custom subagents onto a template without re-reading the standard ones. You add a “Subscription Changes” subagent, write a reasonable classification for it, and don’t notice it now overlaps with the standard “Account Management” subagent that already claimed “changes to a customer’s plan.” You’ve just manufactured the exact collision this whole post is about. Every time you add a subagent, re-read the classification descriptions of its neighbours and make sure the new boundary is explicit on both sides.
The 15-topic ceiling is an architecture signal, not just a limit
Here’s the constraint that quietly shapes serious agent design: an Agentforce agent is limited to 15 subagents (topics), and Salesforce recommends no more than 15 actions per subagent for reliable performance. (Treat exact ceilings as things to confirm against current release notes for your edition — but plan as though the limit is real, because the performance reason behind it is.)
The performance reason matters more than the number. Even below the ceiling, every additional subagent you add makes the router’s classification job harder — more descriptions to disambiguate means more chances for semantic overlap and more routing errors. A 14-subagent agent isn’t just near a limit; it’s an agent whose router is doing a genuinely hard multi-way classification on every single turn. Cramming is a false economy.
So treat approaching the ceiling as a design signal: your one agent is trying to do too many jobs, and the fix is to split it into a team. This is exactly what multi-agent orchestration is for — an orchestrator agent that delegates to specialised worker agents, each with a tight, non-overlapping set of subagents. When the worker lives on another platform entirely, the delegation crosses the A2A protocol boundary instead. Either way, the mental model is the same as the one that governs a single agent: give each unit one job and a boundary the layer above can read. Overlap is the enemy at every scale.
Test the router, not just the conversation
Because routing and behaviour are separate layers, you have to test them separately — and most teams only test the second. A transcript that produces a good final answer tells you nothing about whether the right subagent handled it; sometimes the wrong subagent stumbles into a plausible answer, which is worse than a clean failure because it hides the bug.
Build a routing test set the way we describe in how to test an Agentforce agent: a batch of utterances, each labelled with the subagent that should handle it, including the adversarial near-misses — the undelivered-jacket phrasings, the “change my plan” variants that sit on a boundary. Run them and score topic-selection accuracy as its own metric, before you ever look at answer quality. Synthetic personas are useful here precisely because they generate the messy, boundary-straddling phrasings your happy-path tests never will. When a test routes wrong, the fix is nearly always a classification-description edit, not an instruction edit — and now you know why.
When natural-language routing genuinely can’t be made reliable enough — a compliance gate that must never be skipped, a hard sequencing rule — that’s the signal to reach for deterministic control instead of more description-tuning. Agent Script exists for exactly the cases where “the model usually picks the right path” isn’t good enough, and knowing that routing is probabilistic is what tells you when you’ve hit that wall.
What to actually do
The reframe that fixes most Agentforce routing problems is small and load-bearing: your agent’s intelligence lives in the descriptions the router reads, not the instructions you spent all your time on. So spend the time where the decision is made.
- Design subagents as mutually exclusive jobs, and write classification descriptions that contrast with their neighbours, not just describe themselves.
- When two subagents fight over an utterance, find the discriminating fact and write it into both classifications — don’t patch it in instructions.
- Treat actions the same way one level down: the description decides when it’s called, so make it precise and distinct, and assume the engine may call it more than once.
- Read the standard subagents before adding custom ones, and re-check boundaries every time you add.
- Watch the 15-subagent ceiling as an architecture signal — approaching it means split into a team, not cram.
- Test topic selection as its own scored metric, with adversarial near-miss utterances, and reach for deterministic control when routing genuinely can’t be made reliable.
Do that and the agent stops “being dumb.” It was never dumb — it was reading a table of contents you hadn’t written carefully enough.
Understanding the basics
What’s the difference between a subagent and a topic in Agentforce?
They’re the same thing. Beginning in April 2026, Salesforce renamed topics to subagents; the object, its fields, and its behaviour are unchanged. A subagent (topic) is a bounded job the agent can do — Returns, Order Status — that owns a set of actions and a classification description. During the transition you’ll see both terms in the UI and docs, and the component that routes to them, formerly the Topic Selector, is now the Agent Router.
Why does my Agentforce agent route requests to the wrong topic?
Almost always because two subagents have overlapping classification descriptions. The Agent Router picks a subagent by matching the user’s utterance against each subagent’s classification description and scope — not against your topic instructions or your action logic. If two descriptions occupy the same meaning-space, the router can’t reliably tell them apart and will pick wrong a predictable fraction of the time. The fix is to sharpen the two classification descriptions so they contrast, writing the discriminating fact into both — not to edit the instructions.
How many topics can an Agentforce agent have?
An agent is limited to 15 subagents (topics), and Salesforce recommends no more than 15 actions per subagent for reliable performance. Confirm the exact figures against current release notes for your edition. More important than the number: every subagent you add makes the router’s classification harder, so treat approaching the ceiling as a signal to split one overloaded agent into a team of specialised agents under multi-agent orchestration rather than cramming jobs into one.
Designing an Agentforce agent whose routing holds up under real, messy user language — or untangling one that keeps picking the wrong topic? Talk to us. Getting the subagent boundaries and classification descriptions right is exactly the work we do.