We are building a multilingual support triage agent that reads customer tickets in any language, classifies intent, and drafts localized replies. This helps small teams support global user bases without maintaining separate pipelines per language. I will walk through the exact Python code I run on Oxlo.ai using their OpenAI-compatible API.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Configure the client and verify connectivity
Before processing tickets, I confirm the Python client can reach Oxlo.ai and that Qwen 3 32B correctly identifies a non-English message.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
ticket = "No puedo acceder a mi cuenta después de cambiar mi contraseña. Me sale un error 403 cada vez que intento iniciar sesión."
response = client.chat.completions.create(
model="qwen-3-32b",
messages=[
{"role": "system", "content": "You are a helpful multilingual assistant."},
{"role": "user", "content": f"Detect language and issue: {ticket}"},
],
)
print(response.choices[0].message.content)
Step 2: Lock down output with a system prompt and JSON mode
Ad-hoc parsing breaks in production, so I define a strict schema and use Oxlo.ai's JSON mode to get machine-readable results every time.
import json
SYSTEM_PROMPT = """You are a multilingual support triage agent.
Analyze the user message and return ONLY a JSON object with these keys:
- language: ISO 639-1 code of the user's language
- category: one of [billing, technical, account, other]
- urgency: one of [low, medium, high]
- summary: a one-sentence English summary of the issue
- entities: an array of objects with {type, value} for emails, order IDs, or product names mentioned
Rules:
- Respond in the user's language only inside the JSON values where appropriate.
- Do not include markdown formatting or explanations outside the JSON."""
ticket = "Meine letzte Rechnung wurde doppelt abgebucht. Auftragsnummer #DE-8842, meine E-Mail ist max@example.de."
response = client.chat.completions.create(
model="qwen-3-32b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2, ensure_ascii=False))
Step 3: Batch process a mixed-language queue
Real queues contain many languages. Because Oxlo.ai uses flat per-request pricing, processing a long ticket thread costs the same as a one-liner, which makes long-context multilingual workloads predictable. See https://oxlo.ai/pricing for current plan details.
tickets = [
{"id": "T-101", "body": "Meine letzte Rechnung wurde doppelt abgebucht. Auftragsnummer #DE-8842."},
{"id": "T-102", "body": "パスワードをリセットしてもログインできません。エラーが続いています。"},
{"id": "T-103", "body": "Não recebi o relatório mensal no meu e-mail. O sistema diz 'enviado', mas não está na caixa de entrada."},
]
triage_results = []
for t in tickets:
resp = client.chat.completions.create(
model="qwen-3-32b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": t["body"]},
],
response_format={"type": "json_object"},
)
data = json.loads(resp.choices[0].message.content)
data["ticket_id"] = t["id"]
triage_results.append(data)
for r in triage_results:
print(f"{r['ticket_id']}: {r['language']} | {r['category']} | {r['urgency']} | {r['summary']}")
Step 4: Draft localized replies
Classification alone is not enough. I feed the structured result into a second call to generate a helpful, culturally appropriate response in the customer's language.
REPLY_PROMPT = """You are a support representative. Using the provided triage data, write a concise, helpful reply to the customer in their language.
Tone: polite, professional, and solution-oriented.
Include a specific next step or question if more information is needed.
Do not mention internal ticket IDs or the triage system."""
def draft_reply(triage, original_message):
context = f"Triage: {json.dumps(triage, ensure_ascii=False)}\nOriginal message: {original_message}"
resp = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": REPLY_PROMPT},
{"role": "user", "content": context},
],
)
return resp.choices[0].message.content
for r in triage_results:
original = next(t["body"] for t in tickets if t["id"] == r["ticket_id"])
reply = draft_reply(r, original)
print(f"--- {r['ticket_id']} ({r['language']}) ---")
print(reply)
print()
Run it
Save the complete script as triage_agent.py, export your Oxlo.ai key, and run it. You should see structured JSON for each ticket followed by a localized draft reply.
$ export OXLO_API_KEY="sk-..."
$ python triage_agent.py
T-101: de | billing | high | Double billing for order #DE-8842
T-102: ja | technical | high | Unable to login after password reset
T-103: pt | account | medium | Monthly report not received via email
--- T-101 (de) ---
Sehr geehrte/r Kund/in,
vielen Dank für Ihre Nachricht. Es tut mir leid zu hören, dass Ihre Rechnung doppelt abgebucht wurde. Ich habe die Auftragsnummer #DE-8842 zur Prüfung an unser Billing-Team weitergeleitet. Sie erhalten innerhalb von 24 Stunden eine Rückmeldung.
Mit freundlichen Grüßen
Support
--- T-102 (ja) ---
いつもお世話になっております。
パスワードリセット後もログインできないとのこと、大変申し訳ございません。現在、技術チームでエラーの原因を調査しております。恐れ入りますが、ご利用のブラウザと発生時刻をお教えいただけますでしょうか。
よろしくお願いいたします。
サポート
--- T-103 (pt) ---
Olá,
Agradecemos o contacto. Lamentamos que não tenha recebido o relatório mensal. Verificámos que o estado indica 'enviado', por isso pedimos que confirme a pasta de spam. Caso não o encontre, reenviaremos o documento imediatamente.
Atenciosamente,
Equipa de Suporte
Wrap-up and next steps
From here, you could wire the triage results into a Postgres queue with LangGraph so human agents only handle high-urgency tickets. You could also add Oxlo.ai's vision models, such as Kimi VL A3B, to process screenshots that customers attach to tickets in any language.
Top comments (0)