Last updated: 2026-11-02 · Written by the editor · API shape per official docs
Build a Support-Ticket Triage with Jev in ~50 Lines of Python
Ticket routing is the canonical first Jev workflow — bounded categories, high volume, and a cost profile where the old options (human triage or an LLM call per ticket) both lose. Here is a complete, working router in about 50 lines: three typed questions, a confidence-threshold policy, a priority lane and a human fallback.
The full script
import os
import requests
API = "https://api.typesafe.ai/v1/systemone" # or your provider's endpoint
KEY = os.environ["JEV_API_KEY"]
QUESTIONS = {
"category": {"type": "choice", "options": ["billing", "technical", "sales", "spam"]},
"urgent": {"type": "noul",
"statement": "The customer is blocked, or losing money or time."},
"mood": {"type": "score", "scale": ["calm", "annoyed", "angry", "furious"]},
}
def decide(state: str) -> dict:
r = requests.post(
API,
headers={"Authorization": f"Bearer {KEY}"},
json={"model": "jev-latest", "state": state, "questions": QUESTIONS},
timeout=10,
)
r.raise_for_status()
return r.json()["answers"] # {name: {value, confidence, ...}}
def route(state: str) -> str:
a = decide(state)
cat, urgent, mood = a["category"], a["urgent"], a["mood"]
# 1. spam: cheap to auto-archive when very confident
if cat["value"] == "spam" and cat["confidence"] > 0.90:
return "archive"
# 2. priority lane: blocked customers or hot tempers skip the queue
if (urgent["value"] and urgent["confidence"] > 0.85) or \
mood["value"] in ("angry", "furious"):
return "priority-queue"
# 3. auto-route: only when the model is sure enough
if cat["confidence"] >= 0.75:
return f"team-{cat['value']}"
# 4. everything else: human review
return "human-review"
if __name__ == "__main__":
for line in open("tickets.txt"):
if line.strip():
print(route(line.strip()))
Fifty lines, and the interesting part — the policy — is about ten of them. Note what the code does not contain: no prompt strings, no output parsing, no schema validation. The response either has your fields or the call failed.
Why three questions in one call
The three questions (choice / noul / score) ride along in a single request. Because Jev charges input only, questions two and three are essentially free — the entire call costs the state plus a rounding error. Compare: three separate LLM calls at $0.25/1M input + $2.00/1M output, each 2–8 seconds, each with a parse failure mode. This is the core economic argument from our Jev vs function calling comparison, in miniature.
The policy is a product decision, not code style
The thresholds (0.90, 0.85, 0.75) are starting points, not recommendations. They encode how much automation risk you accept:
| Threshold | Meaning | Failure mode when wrong |
|---|---|---|
| spam > 0.90 | Auto-archive | A real customer ticket vanishes. Expensive. |
| urgent > 0.85 | Priority lane | False positive: queue-jumping. Cheap. False negative: a furious customer waits. Costly. |
| route ≥ 0.75 | Auto-route | Misrouted ticket; agent re-files. Annoying, survivable. |
Set them with a replay set — 100–500 past tickets labeled by hand — and read the production checklist before trusting any threshold in anger. Jev's confidence is trained to be calibrated (RLCD, not RLHF), but calibration on the vendor's eval is not calibration on your tickets.
Making the state lean
The script above sends whatever state you give it — which is why the companion guide on state design matters: strip signatures, HTML and thread history before calling, and the same routing decision costs ~60% less. At 100k tickets/month that's real money even at Jev's rates; at LLM rates it's the difference between viable and absurd.
Plugging it in
- Webhook trigger: point your helpdesk's outbound webhook (Zendesk, Intercom, Plain…) at a small handler that extracts the message body and calls route(), then writes the result back via the helpdesk API.
- Provider choice: the same request works against Vercel AI Gateway (typesafe-ai/jev), Cloudflare Workers AI (typesafe/jev) or Vivgrid (jev) — see the provider comparison. Running two providers behind a fallback is cheap insurance (also in the checklist).
- Observability: log category/confidence distributions, not just routing counts. A drift in the confidence histogram is your earliest warning that traffic mix or model behavior changed.
Where to go next
Once routing works, the same state can feed a generation step: a chat LLM drafts the reply after Jev has classified, prioritized and spam-filtered — the hybrid pattern from the Jev vs LLMs page. And if you want to test question phrasing before touching code, the Playground runs real decisions with full probability output, free.