We are building a customer support dialogue agent that handles order lookups across multiple turns without losing context. It helps teams automate repetitive support workflows without maintaining brittle state machines. Because conversation histories grow quickly, Oxlo.ai's flat per-request pricing keeps costs predictable even when transcripts get long.
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: Verify the connection
Before adding state, make sure the Oxlo.ai endpoint responds. A single call confirms your key works and that latency is acceptable for real-time dialogue.
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": "system", "content": "You are a helpful customer support agent."},
{"role": "user", "content": "Hi, I need help with my order."},
],
)
print(response.choices[0].message.content)
Step 2: Define the system prompt
The system prompt is the agent's script. It sets the persona, boundaries, and escalation rules. Keep it in its own variable so non-engineers can edit it later.
SYSTEM_PROMPT = """You are a support agent for TechFlow, an electronics store.
Your job is to help users with order status, returns, and basic troubleshooting.
Rules:
- Always ask for the order ID if the user mentions an order but does not provide one.
- If the user asks for a refund, verify the order ID and confirm eligibility before proceeding.
- If the user is frustrated or explicitly asks for a human, offer to escalate to a human agent.
- Keep responses under 100 words unless explaining technical steps.
- Do not invent order details. Use the lookup_order tool when you need data.
"""
Step 3: Add conversation memory
Dialogue systems need to remember prior turns. A lightweight class stores the message history and appends new exchanges so the model sees the full context on every call.
class SupportAgent:
def __init__(self, client):
self.client = client
self.history = [{"role": "system", "content": SYSTEM_PROMPT}]
def chat(self, user_message):
self.history.append({"role": "user", "content": user_message})
response = self.client.chat.completions.create(
model="llama-3.3-70b",
messages=self.history,
)
assistant_message = response.choices[0].message.content
self.history.append({"role": "assistant", "content": assistant_message})
return assistant_message
Step 4: Add order lookup with function calling
Agents hallucinate facts less when they can call a tool. We give the model a lookup_order function and feed the JSON result back into the conversation before generating the final reply.
import json
def lookup_order(order_id):
db = {
"ORD-1234": {"status": "shipped", "item": "USB-C Cable", "eligible_for_return": True},
"ORD-5678": {"status": "processing", "item": "Mechanical Keyboard", "eligible_for_return": False},
}
return db.get(order_id, {"error": "Order not found"})
class SupportAgent:
def __init__(self, client):
self.client = client
self.history = [{"role": "system", "content": SYSTEM_PROMPT}]
def chat(self, user_message):
self.history.append({"role": "user", "content": user_message})
response = self.client.chat.completions.create(
model="llama-3.3-70b",
messages=self.history,
tools=[{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Retrieve order status and return eligibility",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "The order ID"}
},
"required": ["order_id"]
}
}
}],
tool_choice="auto",
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
if tool_call.function.name == "lookup_order":
args = json.loads(tool_call.function.arguments)
result = lookup_order(args["order_id"])
self.history.append({
"role": "assistant",
"content": None,
"tool_calls": [{
"id": tool_call.id,
"type": tool_call.type,
"function": {
"name": tool_call.function.name,
"arguments": tool_call.function.arguments
}
}]
})
self.history.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
second = self.client.chat.completions.create(
model="llama-3.3-70b",
messages=self.history,
)
reply = second.choices[0].message.content
self.history.append({"role": "assistant", "content": reply})
return reply
self.history.append({"role": "assistant", "content": message.content})
return message.content
Step 5: Trim history to control context length
Real conversations can exceed dozens of turns. To avoid slowing down responses, we cap the history to the most recent exchanges while always preserving the system prompt at index zero.
import json
def lookup_order(order_id):
db = {
"ORD-1234": {"status": "shipped", "item": "USB-C Cable", "eligible_for_return": True},
"ORD-5678": {"status": "processing", "item": "Mechanical Keyboard", "eligible_for_return": False},
}
return db.get(order_id, {"error": "Order not found"})
class SupportAgent:
def __init__(self, client, max_turns=10):
self.client = client
self.max_turns = max_turns
self.history = [{"role": "system", "content": SYSTEM_PROMPT}]
def _trim(self):
if len(self.history) > (self.max_turns * 2) + 1:
self.history = [self.history[0]] + self.history[-(self.max_turns * 2):]
def chat(self, user_message):
self._trim()
self.history.append({"role": "user", "content": user_message})
response = self.client.chat.completions.create(
model="llama-3.3-70b",
messages=self.history,
tools=[{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Retrieve order status and return eligibility",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "The order ID"}
},
"required": ["order_id"]
}
}
}],
tool_choice="auto",
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
if tool_call.function.name == "lookup_order":
args = json.loads(tool_call.function.arguments)
result = lookup_order(args["order_id"])
self.history.append({
"role": "assistant",
"content": None,
"tool_calls": [{
"id": tool_call.id,
"type": tool_call.type,
"function": {
"name": tool_call.function.name,
"arguments": tool_call.function.arguments
}
}]
})
self.history.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
second = self.client.chat.completions.create(
model="llama-3.3-70b",
messages=self.history,
)
reply = second.choices[0].message.content
self.history.append({"role": "assistant", "content": reply})
return reply
self.history.append({"role": "assistant", "content": message.content})
return message.content
Run it
The script below simulates a short session. The first query triggers a tool call, and the second builds on that context to answer a follow-up.
agent = SupportAgent(client)
session = [
"Hi, where is my order ORD-1234?",
"Can I return it?",
"Thanks, that is all for now.",
]
for query in session:
print(f"User: {query}")
print(f"Agent: {agent.chat(query)}")
print()
Example output:
User: Hi, where is my order ORD-1234?
Agent: Your order ORD-1234 for the USB-C Cable has already shipped. Is there anything else I can help you with?
User: Can I return it?
Agent: Yes, that order is eligible for a return. Would you like me to start the return process for you?
User: Thanks, that is all for now.
Agent: You are welcome. Feel free to reach out if you need anything else.
Next steps
Swap in qwen-3-32b or kimi-k2.6 if you need stronger multilingual or reasoning skills for complex troubleshooting flows. For pricing that stays flat regardless of how long your transcripts grow, see https://oxlo.ai/pricing.
Top comments (0)