Skip to content
Original tutorialDocs reviewed

Support Ticket Triage with CSV, Noul and Score

Produce exportable suggestions and a review queue without auto replying to customers.

Use caseRoute multilingual support messages by language, intent, urgency, and human review

Source · JevLog originalIntermediate8 min

Read one fictional ticket from a CSV and ask System One for language, intent, urgency, and a human-review signal. The result is a routing suggestion, never an automatic reply.

Source · JevLog original · Original guide

2026-09-23 update: read the sample CSV directly and combine triage into one request.

Support messages often combine two requests, such as a late delivery and a refund. This fictional example classifies one ticket while keeping its original text and ID.

  • Use Python 3.10+, install typesafe-sdk, and prepare a fictional CSV. Put TYPESAFE_API_KEY in an environment variable before a live request; do not use real customer data.

Ticket triage: labels stay suggestions until checked by a person. No automatic reply. AI concept art.

Ticket triage: labels stay suggestions until checked by a person. No automatic reply. AI concept art.

Keep the sample CSV beside the script. The code finds ticket 7 by ID and retains its original text so you can check the suggestion.

One request returns language, main intent, urgency, and a review signal. Noul gives a 0–1 review probability; Score gives a 0–2 weighted value from your defined scale. Both are suggestions, not proof that a label is correct.

import csv
import os
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
assert os.environ.get("TYPESAFE_API_KEY"), "Set TYPESAFE_API_KEY before a live request"
with open("customer_feedback.csv", newline="", encoding="utf-8-sig") as f:
ticket = next(row for row in csv.DictReader(f) if row["id"] == "7")
with TypeSafeClient() as client:
result = client.system_one(
state={"ticket_id": ticket["id"], "ticket_text": ticket["feedback"]},
questions={
"language": Choice(
instructions="Detect the language used in this support ticket.",
criteria={"zh": "Chinese", "en": "English", "mixed": "Chinese and English", "other": "Other or unclear"},
),
"intent": Choice(
instructions="Choose the main support intent.",
criteria={"billing": "Refund, charge, or invoice", "technical": "Login, bug, or outage", "shipping": "Delivery, tracking, or address", "other": "Other or unclear"},
),
"needs_human": Noul(instructions="Should a person review this ticket before any customer-visible action?"),
"urgency": Score(
instructions="Choose the urgency that best fits the ticket.",
criteria=["Routine", "Soon", "Urgent"],
),
},
)
suggestion = {
"id": ticket["id"],
"original": ticket["feedback"],
"language": result.choices["language"].choice,
"intent": result.choices["intent"].choice,
"human_review_probability": result.nouls["needs_human"].noul,
"urgency_score": result.scores["urgency"].score,
}
print(suggestion)

3. Check the original, then route to a person

Section titled “3. Check the original, then route to a person”

Set routing thresholds using tickets labeled by your team. Send urgent, conflicting, or flagged records to a person; replies, refunds, and order changes stay in your existing workflow.

Practice sample: download customer_feedback.csv (CSV Studio / local practice; not a live run here).

Each suggestion keeps its ticket ID and original text; a person handles the review.

  • The result keeps the ticket ID and original text.
  • Urgent, conflicting, or flagged tickets go to a human queue.

A label can be wrong. Have a person check the original before the existing support workflow sends a reply.