Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.opper.ai/llms.txt

Use this file to discover all available pages before exploring further.

A support bot needs a natural back-and-forth with the user and the ability to look things up in your systems. Here’s one built on the Chat API with tool calling: it asks for an order ID and email, then calls a get_order_status tool to answer.
python app.py

You › Hi, where is my order?

Bot › I can check that. Please share your order ID and the email you used to place the order.

You › Order 123123, email santa@clau.se

Tool › get_order_status(order_id=“123123”, email=“santa@clau.se”)
→ found · out for delivery · ETA 2024-11-08

Bot › Your order 123123 is out for delivery, arriving around 2024-11-08 to Snowy Mountain 123, Greenland. Items: Large wooden sled and Reindeer harness (x2).

You › Great, what did I actually order?

Bot › Your order 123123 contains a Large wooden sled and a Reindeer harness (x2).

The bot asks for the ID and email, looks the order up once it has them, and still knows the contents on the next turn because the history is kept. Here’s the whole thing.

The bot

import os, json
from openai import OpenAI

client = OpenAI(base_url="https://api.opper.ai/v3/compat", api_key=os.environ["OPPER_API_KEY"])

# A tiny order "database"
ORDERS = {
    "123123": {
        "email": "santa@clau.se",
        "status": "out for delivery",
        "eta": "2024-11-08",
        "items": ["Large wooden sled", "Reindeer harness (x2)"],
        "address": "Snowy Mountain 123, Greenland",
    }
}

def get_order_status(order_id: str, email: str) -> dict:
    order = ORDERS.get(order_id)
    if not order or order["email"].lower() != email.lower():
        return {"found": False, "reason": "No order matches that ID and email."}
    return {"found": True, **{k: order[k] for k in ("status", "eta", "items", "address")}}

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up an order's status and contents by order ID and the email used to place it.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string"},
                "email": {"type": "string"},
            },
            "required": ["order_id", "email"],
        },
    },
}]

system = (
    "You are a friendly customer support agent for a sleigh supply store. "
    "Use the get_order_status tool to answer questions about orders. "
    "Ask for the order ID and email if you need them. Keep replies short."
)

def reply(messages):
    # Loop until the model answers in text instead of calling a tool.
    while True:
        r = client.chat.completions.create(model="openai/gpt-5-mini", messages=messages, tools=tools)
        msg = r.choices[0].message
        messages.append(msg)
        if not msg.tool_calls:
            return msg.content
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            result = get_order_status(**args)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

messages = [{"role": "system", "content": system}]
while True:
    user = input("User: ")
    if user.lower() in {"quit", "exit"}:
        break
    messages.append({"role": "user", "content": user})
    print("Assistant:", reply(messages))
Run it:
pip install openai
export OPPER_API_KEY="your-api-key"
python app.py

How it works

  • The tools array describes get_order_status to the model. It calls the tool only when it needs order data, and asks for the ID and email first when they’re missing.
  • The reply loop runs the model, executes any tool call, feeds the result back, and repeats until the model returns plain text. That’s the standard tool round trip.
  • The whole conversation, including the system prompt and tool results, lives in messages, so the bot remembers the order across turns. See Conversations.
  • Swap model for any of the 300+ models without touching the rest of the code.
Every call is traced in the platform. Add an Observe rule on this bot to score replies and catch regressions.

What’s next

Tool calling

The full tool-use round trip.

Conversations

Multi-turn chat and message history.

Guard

Block or redact sensitive content before it reaches the model.

Observe

Score every reply and watch quality over time.