DEV Community

shashank ms
shashank ms

Posted on

Building Conversational AI Models with LLM: Best Practices

We are going to build a stateful customer support agent that handles order lookups, return requests, and general store questions. It keeps conversation history, uses tools to fetch data, and stays on topic. I will walk through the exact code I would ship to production, using Oxlo.ai's flat per-request pricing so context length never inflates the bill.

What you'll need

Exact request-based pricing is available at https://oxlo.ai/pricing. Unlike token-based providers, long system prompts and conversation history do not increase the cost per turn on Oxlo.ai.

The system prompt

I treat the system prompt as a contract. It defines the agent's scope, tone, and the one tool it is allowed to call.

SYSTEM_PROMPT = """You are a support agent for TechMart, an online electronics store.
You help customers with order status, returns, and store policies.
You have access to a lookup_order tool that requires a customer email address.
Before retrieving any order details, confirm the user's email.
If the user asks about topics outside orders, returns, or store policies, politely refuse and offer to escalate to a human.
Keep responses concise and friendly."""

Step 1: Initialize the client

We import the OpenAI SDK and point it at Oxlo.ai. I use Llama 3.3 70B because it offers strong general performance and reliable function calling on Oxlo.ai.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.environ["OXLO_API_KEY"]
)

def ask(user_message: str) -> str:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        temperature=0.3,
    )
    return response.choices[0].message.content

if __name__ == "__main__":
    print(ask("What is your return policy?"))

Step 2: Add message history

Conversational AI needs memory. We wrap the client in a class that accumulates messages so context persists across turns.

class SupportAgent:
    def __init__(self):
        self.messages = [
            {"role": "system", "content": SYSTEM_PROMPT}
        ]

    def chat(self, user_input: str) -> str:
        self.messages.append({"role": "user", "content": user_input})
        
        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=self.messages,
            temperature=0.3,
        )
        
        reply = response.choices[0].message.content
        self.messages.append({"role": "assistant", "content": reply})
        return reply

if __name__ == "__main__":
    agent = SupportAgent()
    print(agent.chat("Hi, I need help with an order."))
    print(agent.chat("It should be under alice@example.com."))

Step 3: Implement tool calling

We give the agent access to a mock order database via the function calling schema. When the model emits a tool call, we execute it locally and feed the result back into the conversation.

import json

ORDERS_DB = {
    "alice@example.com": {
        "order_id": "TM-8842",
        "items": ["Wireless Headphones", "USB-C Cable"],
        "status": "shipped",
        "eta": "2025-01-15"
    }
}

tools = [
    {
        "type": "function",
        "function": {
            "name": "lookup_order",
            "description": "Retrieve order details by customer email",
            "parameters": {
                "type": "object",
                "properties": {
                    "email": {
                        "type": "string",
                        "description": "Customer email address"
                    }
                },
                "required": ["email"]
            }
        }
    }
]

def lookup_order(email: str) -> str:
    record = ORDERS_DB.get(email.lower(), {})
    return json.dumps(record) if record else json.dumps({"error": "No order found."})

class SupportAgent:
    def __init__(self):
        self.messages = [{"role": "system", "content": SYSTEM_PROMPT}]

    def chat(self, user_input: str) -> str:
        self.messages.append({"role": "user", "content": user_input})
        
        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=self.messages,
            tools=tools,
            tool_choice="auto",
            temperature=0.3,
        )
        
        msg = response.choices[0].message
        
        if msg.tool_calls:
            self.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["email"])
                    self.messages.append({
                        "role": "tool",
                        "tool_call_id": tc.id,
                        "content": result
                    })
            
            second = client.chat.completions.create(
                model="llama-3.3-70b",
                messages=self.messages,
                temperature=0.3,
            )
            reply = second.choices[0].message.content
            self.messages.append({"role": "assistant", "content": reply})
            return reply
        
        self.messages.append({"role": "assistant", "content": msg.content})
        return msg.content

Step 4: Add guardrails and a REPL

We add a lightweight check for off-topic queries and wrap everything in an interactive loop so we can test the agent in real time.

BLOCKED_TOPICS = ["medical advice", "legal advice", "politics", "competitor"]

def is_off_topic(text: str) -> bool:
    lowered = text.lower()
    return any(topic in lowered for topic in BLOCKED_TOPICS)

class SupportAgent:
    def __init__(self):
        self.messages = [{"role": "system", "content": SYSTEM_PROMPT}]

    def chat(self, user_input: str) -> str:
        if is_off_topic(user_input):
            return "I am not able to help with that. Let me transfer you to a human agent."
        
        self.messages.append({"role": "user", "content": user_input})
        
        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=self.messages,
            tools=tools,
            tool_choice="auto",
            temperature=0.3,
        )
        
        msg = response.choices[0].message
        
        if msg.tool_calls:
            self.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["email"])
                    self.messages.append({
                        "role": "tool",
                        "tool_call_id": tc.id,
                        "content": result
                    })
            
            second = client.chat.completions.create(
                model="llama-3.3-70b",
                messages=self.messages,
                temperature=0.3,
            )
            reply = second.choices[0].message.content
            self.messages.append({"role": "assistant", "content": reply})
            return reply
        
        self.messages.append({"role": "assistant", "content": msg.content})
        return msg.content

if __name__ == "__main__":
    agent = SupportAgent()
    print("TechMart Support Agent. Type 'exit' to quit.")
    while True:
        user = input("> ")
        if user.lower() == "exit":
            break
        print(agent.chat(user))

Run it

Save the full script as support_agent.py, export your key, and run it.

export OXLO_API_KEY="your-key-here"
python support_agent.py

Example session:

TechMart Support Agent. Type 'exit' to quit.
> What is your return policy?
You can return items within 30 days of delivery for a full refund. Just make sure the product is in original condition. Would you like help with a specific order?

> Can you look up my order? It is alice@example.com.
I found your order TM-8842. It contains Wireless Headphones and a USB-C Cable, and the status is shipped with an estimated arrival of 2025-01-15.

> Can you give me medical advice?
I am not able to help with that. Let me transfer you to a human agent.

Next steps

Swap the mock ORDERS_DB for a real database connection or internal API. You can also enable streaming by adding stream=True to the chat.completions.create call and iterating over chunks to reduce perceived latency. If you need deeper reasoning for complex escalation logic, try Kimi K2.6 on Oxlo.ai under the same request-based pricing.

Top comments (0)