We are going to build a support ticket triage agent that ingests raw customer emails, classifies priority and product area, and returns structured JSON. This kind of agentic workload is where Oxlo.ai shines, because its flat per-request pricing does not balloon when customers paste long logs or conversation histories. If you already use the OpenAI Python SDK, you only need to change the base URL.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from portal.oxlo.ai
Oxlo.ai is fully OpenAI SDK compatible, so no new abstractions are required. For this tutorial I will use llama-3.3-70b, Oxlo.ai's general-purpose flagship. If your tickets arrive in multiple languages, qwen-3-32b is a strong alternative.
Step 1: Configure the client
Create a new file named triage.py and initialize the client. Pointing base_url to Oxlo.ai is the only change needed.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
Replace YOUR_OXLO_API_KEY with your production key. Oxlo.ai has no cold starts on popular models, so the first request after import returns immediately.
Step 2: Define the system prompt
The system prompt constrains the model to emit only valid JSON with the fields our downstream tools expect.
SYSTEM_PROMPT = """
You are a support ticket triage agent.
Read the customer's message and output strictly JSON with these keys:
- "priority": one of "low", "medium", "high", "critical"
- "product_area": one of "billing", "api", "dashboard", "integrations", "other"
- "summary": a one-sentence summary of the issue
- "reply_draft": a brief, empathetic acknowledgment to send the customer
Rules:
1. Return only the JSON object, with no markdown fences.
2. If the message is vague, use "other" for product_area and "medium" for priority.
3. Keep reply_draft under 120 words.
"""
Step 3: Call the model
We pass the raw ticket text as the user message and request JSON mode. On Oxlo.ai, JSON mode works exactly like OpenAI's, so you can parse the output with standard library calls.
import json
def triage_ticket(raw_text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": raw_text},
],
response_format={"type": "json_object"},
temperature=0.2,
)
content = response.choices[0].message.content
return json.loads(content)
Because Oxlo.ai charges a flat rate per request, a ticket containing a thousand-word error trace costs the same as a one-line question. That predictability matters when you run this on a queue every minute.
Step 4: Validate the output
Even with JSON mode, it is worth guarding against missing keys before you write to a database. This wrapper normalizes the result.
REQUIRED_KEYS = {"priority", "product_area", "summary", "reply_draft"}
VALID_PRIORITIES = {"low", "medium", "high", "critical"}
def safe_triage(raw_text: str) -> dict:
result = triage_ticket(raw_text)
for key in REQUIRED_KEYS:
if key not in result:
result[key] = "unknown" if key != "priority" else "medium"
if result["priority"] not in VALID_PRIORITIES:
result["priority"] = "medium"
return result
Step 5: Run a batch
Here is a short list of realistic tickets. We loop through them and print the structured result.
if __name__ == "__main__":
tickets = [
"I was charged twice this month. My account ID is 48192. Please fix this immediately.",
"The /v1/batch endpoint returns a 500 error whenever I send more than 1000 items. I attached the curl output below...",
"How do I reset my password? I can't find the link.",
]
for ticket in tickets:
result = safe_triage(ticket)
print(json.dumps(result, indent=2))
print("-" * 40)
Run it
Set your key and run the script.
export OXLO_API_KEY="YOUR_OXLO_API_KEY"
python triage.py
Expected output:
{
"priority": "high",
"product_area": "billing",
"summary": "Customer reports a duplicate charge for account 48192.",
"reply_draft": "Thanks for reaching out. I have flagged the duplicate charge on account 48192 and our billing team will review it within two hours."
}
----------------------------------------
{
"priority": "high",
"product_area": "api",
"summary": "Batch endpoint returns 500 error for payloads over 1000 items.",
"reply_draft": "Thank you for the detailed report. We are investigating the 500 error on the batch endpoint with large payloads and will update you shortly."
}
----------------------------------------
{
"priority": "low",
"product_area": "dashboard",
"summary": "Customer needs help locating the password reset link.",
"reply_draft": "No problem. You can reset your password by clicking 'Forgot password' on the login screen. Let us know if you need further help."
}
Next steps
This agent is already useful, but you can extend it in two directions. First, add function calling so the model can create a Jira issue or Slack alert automatically when priority is critical. Oxlo.ai supports tool use on models like qwen-3-32b and kimi-k2.6. Second, wrap the script in a FastAPI endpoint and process tickets from a webhook. Because Oxlo.ai uses request-based pricing, long payloads from webhooks do not inflate your bill the way token-based providers would. You can review current plan details at Oxlo.ai/pricing.
Top comments (0)