Most teams do not need to fine-tune a foundation model. They need to transfer its general reasoning into a specific domain. In this guide we will build a support-ticket classifier that adapts Llama 3.3 70B to a custom company taxonomy using few-shot prompt transfer. No training clusters, no weight updates, just an Oxlo.ai API key and a handful of labeled examples.
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: Set Up the Oxlo.ai Client
I start every project with a thin wrapper around the OpenAI SDK pointed at Oxlo.ai. Because Oxlo.ai is fully OpenAI-compatible, the only difference is the base URL.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY", "YOUR_OXLO_API_KEY"),
)
Step 2: Curate the Domain Examples
Transfer learning needs a signal. I collected eight real support tickets and mapped them to our internal categories: billing, integration, bug, and feature_request. These examples teach the model our vocabulary.
EXAMPLES = [
{"text": "I was charged twice for the Pro plan this month.", "label": "billing"},
{"text": "Your webhook keeps returning 403 to our staging server.", "label": "integration"},
{"text": "The export button crashes when I select CSV format.", "label": "bug"},
{"text": "Can you add dark mode to the dashboard?", "label": "feature_request"},
{"text": "My invoice shows the wrong VAT number.", "label": "billing"},
{"text": "How do I rotate my API key inside Terraform?", "label": "integration"},
{"text": "Notifications are sent twice for the same event.", "label": "bug"},
{"text": "It would be great to have SSO via OIDC.", "label": "feature_request"},
]
Step 3: Define the System Prompt
The system prompt anchors the model. It restricts output to our taxonomy and prevents the model from adding conversational filler.
SYSTEM_PROMPT = """You are a support-ticket classifier for a B2B SaaS platform.
Your job is to read the user's message and return exactly one label from this list:
billing, integration, bug, feature_request.
Rules:
- Return only the label, no punctuation, no explanation.
- If a ticket matches multiple categories, pick the dominant one.
- Base your decision on the examples provided in the conversation."""
Step 4: Assemble the Few-Shot Prompt
Now I wire the examples and the new ticket into a single message list. Because Oxlo.ai charges per request rather than per token, I can pack all eight examples into the context window without worrying about input length driving up cost. That is the main reason I reach for Oxlo.ai when prototyping transfer-learning workflows.
def build_messages(ticket_text: str) -> list[dict]:
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
for ex in EXAMPLES:
messages.append({"role": "user", "content": ex["text"]})
messages.append({"role": "assistant", "content": ex["label"]})
messages.append({"role": "user", "content": ticket_text})
return messages
Step 5: Run Inference
Finally, I send the assembled conversation to Llama 3.3 70B. I keep temperature low because classification is a deterministic task.
def classify_ticket(ticket_text: str) -> str:
messages = build_messages(ticket_text)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
temperature=0.1,
max_tokens=20,
)
return response.choices[0].message.content.strip()
Step 6: Batch Test
I run a small holdout set to verify the transfer worked. Here are three unseen tickets.
TEST_TICKETS = [
"We need an invoice for last quarter for our finance team.",
"The Python SDK throws a KeyError on line 42 when parsing the response.",
"Please support SCIM user provisioning.",
]
for t in TEST_TICKETS:
label = classify_ticket(t)
print(f"Ticket: {t}\nLabel: {label}\n")
Run It
Putting it all together, the script looks like this. Save it as classify.py, export your key, and run python classify.py.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY", "YOUR_OXLO_API_KEY"),
)
EXAMPLES = [
{"text": "I was charged twice for the Pro plan this month.", "label": "billing"},
{"text": "Your webhook keeps returning 403 to our staging server.", "label": "integration"},
{"text": "The export button crashes when I select CSV format.", "label": "bug"},
{"text": "Can you add dark mode to the dashboard?", "label": "feature_request"},
{"text": "My invoice shows the wrong VAT number.", "label": "billing"},
{"text": "How do I rotate my API key inside Terraform?", "label": "integration"},
{"text": "Notifications are sent twice for the same event.", "label": "bug"},
{"text": "It would be great to have SSO via OIDC.", "label": "feature_request"},
]
SYSTEM_PROMPT = """You are a support-ticket classifier for a B2B SaaS platform.
Your job is to read the user's message and return exactly one label from this list:
billing, integration, bug, feature_request.
Rules:
- Return only the label, no punctuation, no explanation.
- If a ticket matches multiple categories, pick the dominant one.
- Base your decision on the examples provided in the conversation."""
def build_messages(ticket_text: str) -> list[dict]:
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
for ex in EXAMPLES:
messages.append({"role": "user", "content": ex["text"]})
messages.append({"role": "assistant", "content": ex["label"]})
messages.append({"role": "user", "content": ticket_text})
return messages
def classify_ticket(ticket_text: str) -> str:
messages = build_messages(ticket_text)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
temperature=0.1,
max_tokens=20,
)
return response.choices[0].message.content.strip()
TEST_TICKETS = [
"We need an invoice for last quarter for our finance team.",
"The Python SDK throws a KeyError on line 42 when parsing the response.",
"Please support SCIM user provisioning.",
]
for t in TEST_TICKETS:
label = classify_ticket(t)
print(f"Ticket: {t}\nLabel: {label}\n")
Expected output:
Ticket: We need an invoice for last quarter for our finance team.
Label: billing
Ticket: The Python SDK throws a KeyError on line 42 when parsing the response.
Label: bug
Ticket: Please support SCIM user provisioning.
Label: feature_request
Wrap-Up
This is the cheapest form of transfer learning: no gradients, no infrastructure, just structured context. If the volume grows, the next step is to swap the static example list for dynamic retrieval from a vector store, or to move to a longer-context model on Oxlo.ai such as Kimi K2.6 so you can include larger example banks. You could also pipe the output directly into a webhook to route tickets in real time.
Top comments (0)