DEV Community

shashank ms
shashank ms

Posted on

Building Chatbots with LLM and Dialogue Management: Best Practices

Building production chatbots requires more than prompting a large language model. A robust conversational system separates dialogue management, business logic, and generation into distinct layers that can be tested, versioned, and scaled independently. Without explicit state tracking and context orchestration, even the most capable model will lose thread, hallucinate constraints, or bleed user data across sessions.

Architecture Patterns for LLM Chatbots

Most production chatbots use one of three architectures. The first is a retrieval-augmented generation (RAG) pipeline where the LLM answers from a knowledge base but does not maintain dialogue state beyond the prompt context. The second is a finite-state machine where the LLM generates natural language responses within rigidly defined turns, slots, and transitions. The third, increasingly common, is the LLM-as-agent pattern where the model itself proposes actions, updates state, and decides when to hand off to human operators.

For customer support and task-oriented bots, a hybrid approach works best. Start with an explicit state manager written in code. Let it track session variables, user intents, and required slots. Pass this state to the LLM as a structured system prompt or JSON context, then parse the model output to update the state for the next turn. This keeps logic deterministic while letting the LLM handle language variation.

Model Selection and Inference Economics

Chatbots are multi-turn by nature. A single session can accumulate thousands of tokens of system instructions, retrieval context, and conversation history. Under token-based billing, costs grow with every additional message and every extra document you inject into the context window. This makes long-context and agentic chatbot workloads disproportionately expensive on token-based providers.

Oxlo.ai offers a request-based pricing model: one flat cost per API request regardless of prompt length. For chatbots, this means a ten-turn conversation with a full history and retrieved documents costs the same as a single-turn greeting. You can use larger context windows for memory and retrieval without watching token meters spin. Oxlo.ai hosts 45+ models across seven categories, fully OpenAI SDK compatible, with no cold starts on popular models.

For general-purpose dialogue, Llama 3.3 70B provides a strong balance of instruction following and latency. If your bot serves multilingual users, Qwen 3 32B handles agent workflows across dozens of languages. When the bot must reason through complex user constraints before calling an API, DeepSeek R1 671B MoE or Kimi K2.6 offer advanced chain-of-thought capabilities. Because Oxlo.ai uses the standard OpenAI client, switching between these models is a one-line change.

import os
import openai

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

response = client.chat.completions.create(
    model="llama-3.3-70b",  # or qwen3-32b, deepseek-r1-671b, kimi-k2.6
    messages=[
        {"role": "system", "content": "You are a helpful booking assistant. Current state: {...}"},
        {"role": "user", "content": "I need to change my reservation to next Friday."}
    ],
    tools=[...],  # function definitions
    stream=True
)
Enter fullscreen mode Exit fullscreen mode

Dialogue State Management

An LLM has no intrinsic memory between API calls. Every turn is stateless unless you explicitly pass the history and session state back into the prompt. A dedicated state manager prevents the model from inventing facts or ignoring business rules.

Use a Pydantic model to define your dialogue state. Track confirmed slots, pending clarifications, and user intent. After each LLM response, validate the output against the schema before updating the state.

from pydantic import BaseModel
from typing import Optional, Literal

class BookingState(BaseModel):
    intent: Optional[Literal["book", "modify", "cancel"]] = None
    destination: Optional[str] = None
    date: Optional[str] = None
    confirmation_sent: bool = False

def build_system_prompt(state: BookingState) -> str:
    return (
        f"You are a travel assistant. The current booking state is: {state.model_dump_json()}. "
        "Ask for missing required fields. Do not confirm until all fields are set."
    )
Enter fullscreen mode Exit fullscreen mode

Keep the state machine in application code, not in the prompt. The LLM should read the state and generate text, but your code should decide when a booking is finalized.

Context Windows and Long-Term Memory

As conversations lengthen, you eventually hit context limits or degrade response quality through attention dilution. A common pattern is to maintain a summarization buffer. After every N turns, summarize the conversation into a running abstract, then replace the raw history with that summary plus the most recent K turns.

For chatbots that reference large documents, choose a model with a long context window. On Oxlo.ai, DeepSeek V4 Flash supports 1M tokens for near state-of-the-art open-source reasoning, and Kimi K2.6 handles 131K tokens with advanced agentic coding and vision. Because Oxlo.ai charges per request rather than per token, filling a long context with a full knowledge base or extensive conversation history does not inflate your inference costs. You can explore the exact economics on the Oxlo.ai pricing page.

def trim_messages(messages, max_turns=10):
    # Keep system prompt, then last max_turns exchanges
    if len(messages) <= max_turns + 1:
        return messages
    return [messages[0]] + messages[-max_turns:]
Enter fullscreen mode Exit fullscreen mode

Tool Use and Structured Outputs

Real chatbots do more than talk. They query databases, check calendars, and trigger transactions. Use function calling to let the model declare intent, but execute the tool in your own code and feed the result back as an assistant message.

Oxlo.ai supports function calling, JSON mode, and streaming across its chat models. Define your tools with JSON Schema, then handle the tool_calls in your dialogue loop.


Enter fullscreen mode Exit fullscreen mode

Top comments (0)