We are going to build a stateless customer support agent that classifies intent, looks up orders through a simulated tool, and drafts replies. This helps small support teams deflect repetitive tickets without managing a complex state machine. We will run it on Oxlo.ai using the standard OpenAI SDK, so the only change is the base URL.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
Step 1: Bootstrap the Oxlo.ai client
Create a file named agent.py and initialize the client. Oxlo.ai exposes an OpenAI-compatible endpoint, so we import the official SDK and swap the base_url.
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": "Hi, I need help with an order."}],
)
print(response.choices[0].message.content)
Step 2: Write the system prompt
A strict system prompt keeps the agent focused on shipping and order issues. It should refuse unrelated topics and instruct the model to call the tool instead of guessing.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a concise customer support agent for an online electronics store.
Your job is to answer questions about orders, shipping, and returns.
If a user asks about an order, you must call the lookup_order tool with the order_id.
Do not guess order statuses. Do not answer questions outside shipping, orders, or returns.
Keep responses under three sentences."""
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "Do you offer gift wrapping?"},
],
)
print(response.choices[0].message.content)
Step 3: Define the order lookup tool
We simulate a database with a dictionary and describe the lookup function to the model using the OpenAI tools schema. Oxlo.ai supports function calling on Llama 3.3 70B, so the model can request the tool natively.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a concise customer support agent for an online electronics store.
Your job is to answer questions about orders, shipping, and returns.
If a user asks about an order, you must call the lookup_order tool with the order_id.
Do not guess order statuses. Do not answer questions outside shipping, orders, or returns.
Keep responses under three sentences."""
ORDERS_DB = {
"ORD-1001": {"status": "shipped", "eta": "2026-01-15", "item": "USB-C Hub"},
"ORD-1002": {"status": "processing", "eta": "2026-01-20", "item": "Mechanical Keyboard"},
}
TOOLS = [
{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Get the current status and ETA for an order.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID, for example ORD-1001."
}
},
"required": ["order_id"]
}
}
}
]
def lookup_order(order_id: str):
return ORDERS_DB.get(order_id, {"status": "not_found", "eta": None, "item": None})
# Test that the model requests the tool
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "Where is order ORD-1001?"},
],
tools=TOOLS,
tool_choice="auto",
)
tc = response.choices[0].message.tool_calls[0]
print(tc.function.name, tc.function.arguments)
Step 4: Implement the tool calling loop
When the model returns a tool call, we execute the Python function, append the result to the message history, and call the model again so it can write the final answer.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a concise customer support agent for an online electronics store.
Your job is to answer questions about orders, shipping, and returns.
If a user asks about an order, you must call the lookup_order tool with the order_id.
Do not guess order statuses. Do not answer questions outside shipping, orders, or returns.
Keep responses under three sentences."""
ORDERS_DB = {
"ORD-1001": {"status": "shipped", "eta": "2026-01-15", "item": "USB-C Hub"},
"ORD-1002": {"status": "processing", "eta": "2026-01-20", "item": "Mechanical Keyboard"},
}
TOOLS = [
{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Get the current status and ETA for an order.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID, for example ORD-1001."
}
},
"required": ["order_id"]
}
}
}
]
def lookup_order(order_id: str):
return ORDERS_DB.get(order_id, {"status": "not_found", "eta": None, "item": None})
def run_agent(user_message: str) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=TOOLS,
tool_choice="auto",
)
msg = response.choices[0].message
if msg.tool_calls:
messages.append({
"role": "assistant",
"content": msg.content or "",
"tool_calls": [tc.model_dump() for tc in msg.tool_calls]
})
for tc in msg.tool_calls:
if tc.function.name == "lookup_order":
args = json.loads(tc.function.arguments)
result = lookup_order(args["order_id"])
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result),
})
final = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=TOOLS,
)
return final.choices[0].message.content
return msg.content
print(run_agent("Where is order ORD-1001?"))
Step 5: Add intent guardrails
Before we invoke the main agent, we run a cheap classification check to reject off-topic or abusive input. This keeps the support scope clean and prevents wasted tool loops.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a concise customer support agent for an online electronics store.
Your job is to answer questions about orders, shipping, and returns.
If a user asks about an order, you must call the lookup_order tool with the order_id.
Do not guess order statuses. Do not answer questions outside shipping, orders, or returns.
Keep responses under three sentences."""
ORDERS_DB = {
"ORD-1001": {"status": "shipped", "eta": "2026-01-15", "item": "USB-C Hub"},
"ORD-1002": {"status": "processing", "eta": "2026-01-20", "item": "Mechanical Keyboard"},
}
TOOLS = [
{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Get the current status and ETA for an order.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID, for example ORD-1001."
}
},
"required": ["order_id"]
}
}
}
]
def lookup_order(order_id: str):
return ORDERS_DB.get(order_id, {"status": "not_found", "eta": None, "item": None})
def is_on_topic(query: str) -> bool:
prompt = (
"You are a classifier. Respond with ONLY the word YES or NO. "
"Is the following a customer service question about an order, shipping, or return?\n\n"
f"Query: {query}"
)
r = client.chat.completions.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": prompt}],
temperature=0.0,
)
return r.choices[0].message.content.strip().upper() == "YES"
def run_agent(user_message: str) -> str:
if not is_on_topic(user_message):
return "I can only help with orders, shipping, and returns. Please contact sales for other questions."
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=TOOLS,
tool_choice="auto",
)
msg = response.choices[0].message
if msg.tool_calls:
messages.append({
"role": "assistant",
"content": msg.content or "",
"tool_calls": [tc.model_dump() for tc in msg.tool_calls]
})
for tc in msg.tool_calls:
if tc.function.name == "lookup_order":
args = json.loads(tc.function.arguments)
result = lookup_order(args["order_id"])
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result),
})
final = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=TOOLS,
)
return final.choices[0].message.content
return msg.content
if __name__ == "__main__":
print(run_agent("Where is order ORD-1001?"))
print(run_agent("Write me a poem about the moon."))
Run it
Execute the script from your terminal. You should see the agent answer the order query and deflect the off-topic request.
$ python agent.py
Your order ORD-1001 (USB-C Hub) has shipped and is expected to arrive on 2026-01-15.
I can only help with orders, shipping, and returns. Please contact sales for other questions.
Wrap-up and next steps
You now have a working support agent that classifies intent, calls tools, and stays on topic. For a production deployment, persist the message history to Redis or a database so the agent remembers context across sessions. You could also add a second tool to initiate returns, using the same loop on Oxlo.ai.
Top comments (0)