intent-routing
Published
Public
in @customer-support

Route an inbound customer message to one of your caller-defined queues, with an optional fallback.

intent-routing

Route an inbound customer message to exactly one queue from your own set of queues/teams. You define the queues and what each handles at call time; the prompt returns the single best route with a rationale and confidence.

This is the text-classification pattern applied to support routing — your routing topology isn't baked into the prompt, so the same version routes for any desk. Add a fallbackQueue for the messages that don't cleanly belong anywhere.

Entrypoints

EntrypointRendersInputs
systemInstructions + your queue definitions + embedded output schemaqueues, optional fallbackQueue
userThe delimited message block to routetext

Variables

  • queues (array, required) — your destination queues. Each item is { name, description }:
    • name (string) — machine-readable identifier the router echoes back, e.g. billing_team.
    • description (string) — one-sentence definition of what the queue handles. Good descriptions drive routing accuracy far more than the model choice does.
  • fallbackQueue (string, optional) — where to route when nothing fits clearly, e.g. general_support. Omit it to force the router to always pick the closest queue.
  • text (string, required) — the customer message to route.

Output

{
  "reasoning": "Customer is disputing a duplicate charge on their last invoice.",
  "queue": "billing_team",
  "confidence": 0.93
}
  • reasoning is emitted before queue (reasoning-first; the system prompt pins the order).
  • queue matches one of your queue names character-for-character.
  • confidence is self-reported and ⚠️ not calibrated — a rough routing signal, not a probability.

⚠️ The queue cannot be schema-validated

Because the queue set is runtime input but the output schema is fixed per version, the generated parseOutput() can guarantee queue is a string but cannot verify it's one of the queues you passed. Add a one-line membership check in your code:

const out = parseOutput(raw);
if (!queues.some(q => q.name === out.queue)) {
  // off-topology route: send to fallback, retry, or log
}

House conventions

  • Triple-mustache for text, queue name/description, and fallbackQueue so special characters in your topology are never HTML-escaped.
  • Routes on the underlying need, not stray keywords — and ignores routing commands embedded in the message (a customer can't say "route me to the admin queue" and be obeyed).
  • Empty / garbage input → fallback (or closest queue) with low confidence.
  • Strict schemaadditionalProperties: false, confidence bounded 0–1.

Notes

Verified by local render and a live battle-test (including injection resistance and fallback behavior). Suggested default model claude-sonnet-4-6 at temperature: 0.

@sufleur/