How to Auto-Categorize IT Tickets With Cohere Command
A service desk with a hundred new tickets a day doesn't have a categorization problem, it has a first-hour problem. Someone has to read each one, guess the right queue, and set a priority before anything useful happens. Cohere Command can do that first pass for you, and with structured outputs it will hand back a clean JSON object instead of a paragraph you have to parse.
This walkthrough sets up Cohere Command IT tickets classification end to end: define a taxonomy, call the model, and route the result into your queues. By the end you'll have a script that takes a raw ticket and returns a category, a team, and a priority, ready to plug into whatever ITSM tool you run.
Get a Cohere API key and install the SDK
Sign up at dashboard.cohere.com and grab a trial or production API key. Then install the Python SDK, which speaks the v2 Chat API used below.
pip install cohere
export COHERE_API_KEY="<your-api-key>"
Define your ticket taxonomy as a JSON schema
Decide the categories, teams, and priority levels your desk actually uses, then lock them into a JSON schema with enum constraints. This is the step that keeps the model from inventing new categories on a bad day.
TICKET_SCHEMA = {
"type": "json_object",
"schema": {
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["access", "hardware", "network", "software", "account", "other"]
},
"team": {
"type": "string",
"enum": ["helpdesk", "network-ops", "identity", "field-support"]
},
"priority": {"type": "string", "enum": ["P1", "P2", "P3", "P4"]},
"confidence": {"type": "integer", "minimum": 1, "maximum": 5}
},
"required": ["category", "team", "priority", "confidence"]
}
}
The confidence field costs nothing extra and gives you a lever for step 6.
Call Command with structured outputs to classify a ticket
Use response_format with your schema so the Cohere Chat API returns valid JSON every time instead of free text you'd have to regex out.
import json
import cohere
co = cohere.ClientV2(api_key="<your-api-key>")
def classify_ticket(subject: str, description: str) -> dict:
response = co.chat(
model="command-a-03-2025",
messages=[
{
"role": "system",
"content": (
"You triage IT service desk tickets. Read the subject and "
"description, then return only JSON matching the schema. "
"P1 is a full outage or security incident, P4 is a request "
"with no urgency."
),
},
{
"role": "user",
"content": f"Subject: {subject}\nDescription: {description}",
},
],
response_format=TICKET_SCHEMA,
)
return json.loads(response.message.content[0].text)
A ticket like "VPN drops every few minutes since this morning" comes back as {"category": "network", "team": "network-ops", "priority": "P2", "confidence": 4} in under a second.
Batch-classify your open ticket queue
Most desks don't need real-time classification on day one, a batch job over the existing backlog proves the taxonomy works before you wire it into intake.
import csv
with open("open_tickets.csv") as f, open("classified.csv", "w", newline="") as out:
reader = csv.DictReader(f)
writer = csv.DictWriter(out, fieldnames=["id", "category", "team", "priority", "confidence"])
writer.writeheader()
for row in reader:
result = classify_ticket(row["subject"], row["description"])
writer.writerow({"id": row["id"], **result})
Run this against last month's closed tickets first and spot-check the output against what a human agent actually assigned.
Route tickets based on the model's output
Once you trust the labels, call classify_ticket at intake and push the result into your ITSM tool's API, most (ServiceNow, Jira Service Management, Zendesk) expose a REST endpoint for updating fields on ticket creation.
import requests
def route_ticket(ticket_id: str, result: dict, itsm_base_url: str, token: str):
requests.patch(
f"{itsm_base_url}/tickets/{ticket_id}",
headers={"Authorization": f"Bearer {token}"},
json={
"category": result["category"],
"assignment_group": result["team"],
"priority": result["priority"],
},
timeout=10,
)
Add a confidence gate for low-certainty tickets
Don't let the model silently misroute an ambiguous ticket. Send anything below your confidence bar to a human review queue instead of auto-assigning it.
result = classify_ticket(subject, description)
if result["confidence"] < 3:
route_ticket(ticket_id, {"category": "other", "team": "helpdesk", "priority": result["priority"]}, ITSM_URL, TOKEN)
flag_for_human_review(ticket_id, result)
else:
route_ticket(ticket_id, result, ITSM_URL, TOKEN)
Gotchas
- Enums beat free text. Without a constrained schema, Command will occasionally invent a category that doesn't exist in your queue system, and your integration breaks silently.
- PII in ticket bodies. Users paste passwords, employee IDs, and screenshots-as-text into tickets. Redact or mask sensitive fields before they hit the API if your data policy requires it.
- Priority is the riskiest field. A model has no way to know your outage is affecting the CEO's laptop specifically. Keep P1 assignment reviewable for the first few weeks.
- Costs scale with volume. Batch nightly for a backlog, but budget for real-time calls once you're classifying every inbound ticket, check current pricing on the Cohere pricing page.
This is a two-hour setup that turns the worst part of every service desk shift, the triage pile, into something that's already sorted by the time an agent sits down, which matters the moment you're running AI in front of a queue someone actually depends on.