We are going to build an order support agent that sits on top of an existing e-commerce backend. It looks up orders, checks refund eligibility against live policy documents, and answers customer questions without making up data. This pattern works for any internal API you already have running.
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: Scaffold the existing application layer
Treat the legacy system as read-only. We will wrap its functions later, but first we need something to integrate with. Save this as legacy_orders.py.
# legacy_orders.py
# Existing application code we cannot modify directly.
_ORDERS = {
"ORD-1001": {
"customer": "alice@example.com",
"items": ["Wireless Keyboard"],
"total": 89.99,
"status": "shipped",
},
"ORD-1002": {
"customer": "bob@example.com",
"items": ["4K Monitor"],
"total": 299.00,
"status": "delivered",
},
}
def get_order(order_id: str):
"""Return order details or None if not found."""
return _ORDERS.get(order_id)
def calculate_refund(order_id: str):
"""Return refund eligibility and amount."""
order = get_order(order_id)
if order is None:
return {"error": "Order not found"}
if order["status"] != "delivered":
return {"eligible": False, "reason": f"Status is {order['status']}"}
return {"eligible": True, "amount": order["total"]}
Step 2: Define the agent's tools
Map the legacy functions to an OpenAI-compatible tool schema. The LLM will use these definitions to decide when to call our code.
# agent.py
import json
from legacy_orders import get_order, calculate_refund
tools = [
{
"type": "function",
"function": {
"name": "get_order",
"description": "Retrieve order details by order ID.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order identifier, e.g. ORD-1001",
}
},
"required": ["order_id"],
},
},
},
{
"type": "function",
"function": {
"name": "calculate_refund",
"description": "Check whether an order is eligible for a refund and return the amount.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order identifier",
}
},
"required": ["order_id"],
},
},
},
]
# Map names to actual functions for dispatch
TOOL_MAP = {
"get_order": get_order,
"calculate_refund": calculate_refund,
}
Step 3: Write the system prompt
Lock the agent into a narrow role. It must use tools for facts, never hallucinate order data, and ask for missing IDs.
SYSTEM_PROMPT = """You are OrderBot, a support agent integrated with the LegacyOrder API.
You have access to two tools: get_order and calculate_refund.
Rules:
1. Always call get_order to verify an order exists before discussing it.
2. If the user asks about a refund, call calculate_refund after verifying the order.
3. Do not invent order details, prices, or statuses.
4. If the user does not provide an order ID, ask for it.
5. Keep responses concise and professional."""
Step 4: Build the agent loop
Initialize the Oxlo.ai client, send the user message, and handle any tool calls. We run a loop so the model can react to tool results.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
def run_agent(user_message: str) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
]
# First turn: let the model decide if it needs tools
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=tools,
tool_choice="auto",
)
message = response.choices[0].message
# If the model wants to call tools, execute them and send results back
if message.tool_calls:
# Append the assistant's tool request to conversation history
messages.append({
"role": "assistant",
"content": message.content or "",
"tool_calls": [
{
"id": tc.id,
"type": tc.type,
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments,
},
}
for tc in message.tool_calls
],
})
for tc in message.tool_calls:
func = TOOL_MAP.get(tc.function.name)
args = json.loads(tc.function.arguments)
result = func(**args)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result),
})
# Second turn: model processes the tool results
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=tools,
)
return response.choices[0].message.content
Step 5: Ground the agent in existing documentation
Most teams have policy docs that change frequently. Rather than hard-coding rules, load your existing refund policy and prepend it to the system prompt. Because Oxlo.ai charges per request rather than per token, injecting a long policy document does not increase inference cost. This makes it practical to keep the full context in the prompt and avoid stale summaries.
Create refund_policy.txt:
Refund Policy
- Items must be delivered before a refund can be issued.
- Refunds are processed to the original payment method within 5 business days.
- Shipping costs are non-refundable.
Then update the system prompt at runtime:
def load_policy(path: str = "refund_policy.txt") -> str:
try:
with open(path, "r") as f:
return f.read()
except FileNotFoundError:
return "No additional policy documentation available."
policy_text = load_policy()
SYSTEM_PROMPT = f"""You are OrderBot, a support agent integrated with the LegacyOrder API.
You have access to two tools: get_order and calculate_refund.
Current policy documentation:
{policy_text}
Rules:
1. Always call get_order to verify an order exists before discussing it.
2. If the user asks about a refund, call calculate_refund after verifying the order.
3. Base all refund decisions strictly on the policy documentation above.
4. Do not invent order details, prices, or statuses.
5. If the user does not provide an order ID, ask for it.
6. Keep responses concise and professional."""
Run it
Call the agent with a real query and watch it interact with the legacy system.
if __name__ == "__main__":
query = "Can I get a refund for order ORD-1002?"
answer = run_agent(query)
print(answer)
Example output:
Order ORD-1002 exists and has been delivered. It is eligible for a refund of $299.00. Please note that shipping costs are non-refundable, and the refund will be processed to the original payment method within 5 business days.
Try a follow-up without an order ID to confirm it asks for clarification:
query = "I need a refund"
print(run_agent(query))
Expected response:
I can help with that. Please provide the order ID so I can look it up.
Next steps
Wire this agent into your existing stack by exposing run_agent through a FastAPI endpoint or a Slack slash command. You can also switch the model to qwen-3-32b or kimi-k2.6 on Oxlo.ai if you need stronger multilingual reasoning or vision support for invoice images.
Because Oxlo.ai uses flat per-request pricing, adding long policy documents or multi-turn tool loops does not inflate your bill the way token-based providers do. For workflows like this, that pricing model removes the penalty for rich context. You can view the latest plans at https://oxlo.ai/pricing.
Top comments (0)