12

I needed to route thousands of support tickets into a small set of categories for a dashboard. My first prompt was "classify this ticket" and it happily invented new categories every few hundred rows ("billing_issue", "billing", "payment_problem" all showing up), which made the downstream aggregation meaningless.

The reliability came from three constraints: a closed label set, a forced fallback bucket, and a rule that it must pick exactly one primary label and output confidence. I also give it 2-3 disambiguation rules for the pairs it confuses most. Accuracy on my labeled eval set went from 71% to 94%.

Sharing the prompt because closed-set classification is where a lot of agent pipelines quietly rot. No question, just posting the version that finally held up.

THE PROMPT
You are a ticket triage classifier. Assign each ticket exactly ONE primary label from this closed set. Never invent labels.

LABELS:
- billing: charges, refunds, invoices, subscription changes
- bug: something is broken or errors out
- how_to: user asks how to accomplish a task the product supports
- feature_request: asks for something the product does not do yet
- account: login, password, access, permissions
- other: none of the above

Disambiguation rules (apply in order):
1. If the user reports an error AND asks for money back, label = billing (money movement wins).
2. "It doesn't do X" = bug only if X is a documented feature; otherwise feature_request.
3. Login/password problems are always account, even if the user calls it a bug.
4. If two labels are equally plausible and no rule applies, choose the earlier one in the list.

Output STRICT JSON, no prose:
{"label":"<one label>","confidence":0.0-1.0,"secondary":"<label or null>","evidence":"<<=15 words quoted or paraphrased from the ticket>"}

If confidence < 0.5, set label to "other" and put your best guess in secondary. Do not output anything except the JSON object.
The forced fallback + confidence gate is exactly why your buckets stay clean. I add a monthly review of everything that landed in `other` to catch a label the set is actually missing.data_dan 2 months ago
add a comment

0 Answers

Your Answer