Agent workflows · 2026-09-25
Routing support requests to the right team with Jev
The question set of a flow that routes incoming support messages to teams with Jev: option descriptions, when a message falls to a human queue, messages with more than one topic, and cost, with example code.
Short answer
Routing a support request to a team is at heart a Choice decision: the message goes to one of the defined teams. In a real flow that decision comes with a few small questions: is the message urgent, does it ask for a refund, does it describe a second topic. In Jev all of these are asked of the same message in one request, and each extra question adds only its own tokens to the cost.
Reliable routing depends on three things: the boundary of each option written into its description, a way out for messages that fit no option, and uncertain decisions going to a person.
A question set for routing
The table shows questions a typical support flow can use and what each answer turns into in the flow. Key names are your choice and are not sent to the model.
| Key | Type | What it asks | Its role in the flow |
|---|---|---|---|
| department | Choice | Which team should handle the request | The queue the message lands in |
| is_urgent | Noul | Is there clear time pressure | Priority in the queue |
| refund_request | Noul | Is the customer asking for a refund | A tag added to the ticket |
| frustration | Score | Calm, upset but polite, very angry | Assignment to an experienced agent |
Writing the options
In Choice, what the model sees is the option name together with its description. "billing" on its own can stay vague; the description "Payments, invoices, refunds, subscription charges" draws the boundary. Most errors happen where two teams overlap: a payment taken twice because of a software bug belongs to both billing and the technical team. If the description does not say which one takes priority, the result varies from message to message.
Adding an other option keeps messages about a new product or an unexpected topic from being forced to the wrong team. Because Choice always returns an option from the list, without that way out every message goes to some team.
Connecting the decision to code
In the example below the team choice is applied automatically, but a message falls to the human queue in two cases: the model chose other, or confidence is below the chosen threshold. The threshold is an example; the right value is set with your own messages. Because question texts and the threshold are defined in one place, it is clear where a person reviewing the routing needs to look.
If a message describes a second topic, Choice returns only one. The extra Noul question in the example flags that a message going to billing also describes a technical problem, so the second topic is not lost.
Team choice, human queue and a second-topic flag
import os, requests
# Question texts and the threshold live in one place; a reviewer looks only here.
QUESTIONS = {
"department": {
"type": "choice",
"instructions": "Which team should handle this support request?",
"criteria": {
"billing": "Payments, invoices, refunds, subscription charges",
"technical": "Bugs, outages, API and integration problems",
"sales": "Quotes, new accounts, plan changes",
"other": None,
},
},
"is_urgent": {"type": "noul", "instructions": "Does the message state clear time pressure?"},
"also_technical": {"type": "noul", "instructions": "Does the message also describe a bug or outage?"},
}
AUTO_ROUTE_MIN_CONFIDENCE = 0.7 # example value; set it from your own data
def route(message: str) -> dict:
res = requests.post(
os.environ["LLMTR_BASE_URL"] + "/v1/systemone",
headers={"Authorization": "Bearer " + os.environ["LLMTR_API_KEY"]},
json={"model": "typesafe/jev", "state": message, "questions": QUESTIONS},
timeout=30,
)
a = res.json()["answers"]
team = a["department"]["choice"]
if team == "other" or a["department"]["confidence"] < AUTO_ROUTE_MIN_CONFIDENCE:
team = "human_queue"
return {
"team": team,
"urgent": a["is_urgent"]["noul"] >= 0.8,
"also_technical": a["also_technical"]["noul"] >= 0.8,
}
Ambiguous and incomplete messages
A short message such as "It doesn't work" belongs clearly to no team. Choice still returns an option; confidence stays low and the message falls to the human queue. That is the right outcome, but the first thing the person in the queue usually does is ask the customer for details.
Adding a Noul question such as "Does the message say which product or service it concerns?" to the same request flags this case on its own. Messages with a low probability of yes can get an automatic reply asking for details before they are routed. The human queue is then left for messages that genuinely need a decision.
The limit of routing
In this flow Jev decides where the message goes, not the request inside it. A high probability of yes on refund_request does not mean the refund will be made: a tag is added to the ticket going to billing, and the refund decision is still made under that team's rules. The same split applies to urgency; is_urgent is a priority flag, not a service commitment.
Cost and measuring the routing
Jev charges only for input tokens, at $0.042 per million; output is free. When four questions totalling 200 tokens are asked of a 300-token support message, the request is 500 tokens, about $0.000021. For 10,000 messages a month that is about $0.21. The calculation is an example; the real token count is read from the usage field of the response.
Routing quality is measured by whether the first decision was corrected later. When the chosen team, the confidence and the team that finally resolved the message are recorded for each message, it becomes visible which option description stays vague and where the threshold should sit.
Frequently asked questions
Can one question select a team?
Yes. If the teams are clearly defined, the choice field of a Choice answer is enough. For extra information such as urgency or refunds, Noul questions are added to the same request.
Why is an other option needed?
Choice always returns an option from the list. Without other, messages that fit no team still go to the closest one.
What if a message has two different topics?
Choice returns only one team. To keep the second topic visible, a separate Noul question is asked for each topic and the flow handles that flag on its own.
What does it cost for thousands of messages a month?
Only input is charged: $0.042 per million tokens. If the message and questions total 500 tokens, 10,000 messages cost about $0.21.
What happens when the list of teams changes?
Because the options and their descriptions are kept in one place, the new team is added there. When the option list changes the probability distribution changes too; the threshold needs to be measured again with the new list.