Introduction to Large Language Models: What You Need to Know
We are going to build a support ticket triage agent that reads incoming customer messages, classifies the issue, looks up account details via a mock tool, and drafts a response. This saves time if you run a help desk and
We are going to build a support ticket triage agent that reads incoming customer messages, classifies the issue, looks up account details via a mock tool, and drafts a response. This saves time if you run a help desk and want to cut first-response latency before a human takes over. I use Oxlo.ai because its OpenAI-compatible API and flat per-request pricing keep the code simple and costs predictable even when ticket histories get long. See https://oxlo.ai/pricing for details.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK. Install it with
pip install openai
Step 1: Verify the connection
Before adding logic, make sure you can reach Oxlo.ai and get a completion back. I start with Llama 3.3 70B because it is a reliable general-purpose model for this workflow.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "user", "content": "How do I reset my password?"},
],
)
print(response.choices[0].message.content)
Step 2: Define the agent's system prompt
A raw model answers generically. We need a system prompt that tells it to act as a triage agent and return structured data. Here is the prompt I use. You can edit the categories or tone to match your product.
SYSTEM_PROMPT = """You are a support ticket triage agent.
Your job is to analyze the customer's message and produce a structured assessment.
Output valid JSON with these keys:
- category: one of Billing, Technical, Account, General
- urgency: Low, Medium, or High
- draft_reply: a brief, empathetic response or escalation note
Be concise. Do not ask follow-up questions."""
Step 3: Enforce JSON output
Parsing free text is fragile. Oxlo.ai supports JSON mode, so we can force valid JSON by setting response_format. This removes the need to beg the model to output JSON inside the prompt.
import json
user_message = "I was charged twice for my subscription this month. Please fix this immediately."
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2))
Step 4: Give the model a tool
For real triage, we need data. We will define a mock function called get_account_status and let the model call it. I switch to Qwen 3 32B here because it handles agent workflows and tool use well.
tools = [
{
"type": "function",
"function": {
"name": "get_account_status",
"description": "Retrieve billing and plan details for a user.",
"parameters": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "The customer user ID.",
},
},
"required": ["user_id"],
},
},
}
]
def get_account_status(user_id: str):
# Mock lookup. In production, query your database.
return {"user_id": user_id, "plan": "Pro", "payment_issue": True}
user_message = "User u-8821 says they were double charged. Can you check?"
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
]
response = client.chat.completions.create(
model="qwen-3-32b",
messages=messages,
tools=tools,
tool_choice="auto",
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if function_name == "get_account_status":
tool_result = get_account_status(**arguments)
messages.append(message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(tool_result),
})
final_response = client.chat.completions.create(
model="qwen-3-32b",
messages=messages,
tools=tools,
)
print(final_response.choices[0].message.content)
else:
print(message.content)
Step 5: Wrap it in a reusable class
Now we tie everything together into a clean Python class that accepts a ticket, runs the tool loop, and returns structured JSON. I use Kimi K2.6 for this final version because its reasoning and agentic coding capabilities make the tool loop reliable.
class SupportTriageAgent:
def __init__(self, api_key: str):
self.client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key=api_key)
self.model = "kimi-k2.6"
self.system_prompt = SYSTEM_PROMPT
self.tools = [
{
"type": "function",
"function": {
"name": "get_account_status",
"description": "Retrieve billing and plan details for a user.",
"parameters": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "The customer user ID.",
},
},
"required": ["user_id"],
},
},
}
]
def get_account_status(self, user_id: str):
return {"user_id": user_id, "plan": "Pro", "payment_issue": True}
def triage(self, user_message: str):
messages = [
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": user_message},
]
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
tools=self.tools,
tool_choice="auto",
response_format={"type": "json_object"},
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if function_name == "get_account_status":
tool_result = self.get_account_status(**arguments)
messages.append(message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(tool_result),
})
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
tools=self.tools,
response_format={"type": "json_object"},
)
message = response.choices[0].message
return json.loads(message.content)
Run it
Here is how I call the finished agent against two sample tickets.
if __name__ == "__main__":
agent = SupportTriageAgent(api_key="YOUR_OXLO_API_KEY")
tickets = [
"User u-9912 cannot log in after the latest update.",
"User u-8821 was charged twice. Please check their account.",
]
for ticket in tickets:
result = agent.triage(ticket)
print(f"Ticket: {ticket}")
print(json.dumps(result, indent=2))
print()
Example output:
Ticket: User u-9912 cannot log in after the latest update.
{
"category": "Technical",
"urgency": "High",
"draft_reply": "We are sorry you are locked out. Our engineering team is investigating the update. I will escalate this to our technical team immediately and follow up within 30 minutes."
}
Ticket: User u-8821 was charged twice. Please check their account.
{
"category": "Billing",
"urgency": "High",
"draft_reply": "I have reviewed your account and confirmed a duplicate charge on your Pro plan. I have issued a refund which will appear in 3 to 5 business days."
}
Next steps
Deploy this agent as a FastAPI endpoint and wire it into your existing help desk via webhook. For tickets that require code-level debugging, swap the model to DeepSeek V3.2 or DeepSeek R1 671B to let the model reason through stack traces before replying.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.