DEV Community

Mattias chaw
Mattias chaw

Posted on

Building a Multi-Model AI Chatbot with Python ??Route by Task Complexity

Building a Multi-Model AI Chatbot with Python ??Route by Task Complexity

All pricing from AIWave, July 2026. Code is production-ready.

Most AI chatbots use a single model for everything. That's simple to build but expensive to run. A more intelligent approach: route different tasks to different models based on complexity, and let your routing logic handle the cost optimization automatically.

Here's a complete, runnable Python chatbot that uses ERNIE Tiny (budget-tier available, $0.178/1M tokens) for simple queries and DeepSeek V4 Pro ($0.42/$0.84 per 1M tokens, 1M context) for complex tasks.

Why Multi-Model Routing Matters

The cost difference between models isn't marginal ??it's orders of magnitude:

Model Input (1M tokens) Output (1M tokens) Context Use Case
ERNIE Tiny 8K $0.178 $0.178 8K Simple Q&A, greetings
DeepSeek V4 Pro $0.42 $0.84 1M Complex reasoning, long docs

A greeting ("Hi, how are you?") costs ~$0.000024 with ERNIE Tiny. Sending it to DeepSeek V4 Pro costs ~$0.000058. That's 2.4? more expensive for zero quality gain. Multiply by millions of daily requests, and routing becomes a real lever.

The Complete Project

multi_model_bot/
????? bot.py           # Main entry point
????? router.py        # Task complexity classifier
????? models.py        # Model configurations
????? config.py        # API key and settings
????? requirements.txt
Enter fullscreen mode Exit fullscreen mode

config.py

API_KEY = "your-aiwave-api-key"
BASE_URL = "https://aiwave.live/v1"

MODELS = {
    "simple": "ernie-tiny-8k",
    "complex": "deepseek-v4-pro",
}

# Pricing data (USD per 1M tokens)
PRICING = {
    "ernie-tiny-8k": {"input": 0.178, "output": 0.178},
    "deepseek-v4-pro": {"input": 0.42, "output": 0.84},
}
Enter fullscreen mode Exit fullscreen mode

router.py ??The Intelligence Layer

import re
from typing import Literal

RouteDecision = Literal["simple", "complex"]

# Patterns that indicate complex reasoning is needed
COMPLEX_PATTERNS = [
    r"\b(analyze|analysis|compare|evaluate|explain why)\b",
    r"\b(algorithm|architecture|design|refactor|optimize)\b",
    r"\b(debug|troubleshoot|fix|error|exception)\b",
    r"\b(write|implement|create|build|develop)\b",
    r"\b(summarize|extract|translate).{0,20}(long|document|paper)\b",
    r"\b(what if|how would|assuming|given that)\b",
]

# Patterns that are clearly simple
SIMPLE_PATTERNS = [
    r"^(hi|hello|hey|thanks|bye|ok)\b",
    r"^(what is|who is|where is|when is|define)\b",
    r"\b(how do i|how to)\b",
]

def classify_complexity(message: str, message_length: int = 0) -> RouteDecision:
    """
    Classify whether a message needs complex reasoning.
    Uses heuristic pattern matching + length-based thresholds.

    In production, replace with a small classifier model
    (e.g., glm-4.7-flash, which is extremely affordable at $0.03/1M).
    """
    msg_lower = message.lower().strip()

    # Length heuristic: very short messages are rarely complex
    if len(msg_lower) < 30:
        # But check if it's asking something non-trivial
        if any(re.search(p, msg_lower) for p in COMPLEX_PATTERNS):
            return "complex"
        return "simple"

    # Pattern matching for complex tasks
    complex_score = sum(
        1 for p in COMPLEX_PATTERNS if re.search(p, msg_lower)
    )
    simple_score = sum(
        1 for p in SIMPLE_PATTERNS if re.search(p, msg_lower)
    )

    if complex_score >= 1:
        return "complex"
    if simple_score >= 1 and complex_score == 0:
        return "simple"

    # Default: medium-length messages without clear signals
    return "simple" if len(msg_lower) < 200 else "complex"
Enter fullscreen mode Exit fullscreen mode

models.py ??Model Interaction

import openai
from config import API_KEY, BASE_URL, MODELS, PRICING

client = openai.OpenAI(api_key=API_KEY, base_url=BASE_URL)

# Conversation history per model to maintain context
conversation_history: dict[str, list[dict]] = {
    "ernie-tiny-8k": [],
    "deepseek-v4-pro": [],
}

def call_model(model_key: str, message: str, system_prompt: str = "") -> dict:
    """
    Call the specified model and return response + cost info.
    """
    model_name = MODELS[model_key]
    history = conversation_history[model_name]

    if system_prompt and not history:
        history.append({"role": "system", "content": system_prompt})

    history.append({"role": "user", "content": message})

    response = client.chat.completions.create(
        model=model_name,
        messages=history,
        temperature=0.3 if model_key == "complex" else 0.7,
        max_tokens=2048 if model_key == "complex" else 512,
    )

    assistant_msg = response.choices[0].message.content
    history.append({"role": "assistant", "content": assistant_msg})

    # Trim history to prevent context overflow
    if len(history) > 20:
        history[:] = history[-16:]  # Keep system + last 8 exchanges

    # Calculate real cost
    pricing = PRICING[model_name]
    cost = (
        response.usage.prompt_tokens * pricing["input"] / 1_000_000
        + response.usage.completion_tokens * pricing["output"] / 1_000_000
    )

    return {
        "text": assistant_msg,
        "model": model_name,
        "route": model_key,
        "input_tokens": response.usage.prompt_tokens,
        "output_tokens": response.usage.completion_tokens,
        "cost_usd": cost,
    }
Enter fullscreen mode Exit fullscreen mode

bot.py ??Putting It Together

from router import classify_complexity
from models import call_model
import json

SYSTEM_PROMPTS = {
    "simple": "You are a helpful assistant. Keep responses concise and friendly.",
    "complex": (
        "You are a senior software engineer and technical analyst. "
        "Provide thorough, well-reasoned responses with code examples "
        "where appropriate. Think step-by-step."
    ),
}

class MultiModelChat:
    def __init__(self):
        self.total_cost = 0.0
        self.request_count = 0
        self.route_counts = {"simple": 0, "complex": 0}

    def chat(self, message: str) -> dict:
        self.request_count += 1
        route = classify_complexity(message)
        self.route_counts[route] += 1

        result = call_model(
            model_key=route,
            message=message,
            system_prompt=SYSTEM_PROMPTS[route],
        )

        self.total_cost += result["cost_usd"]
        result["running_total_usd"] = self.total_cost
        result["route_distribution"] = dict(self.route_counts)

        return result

    def print_response(self, result: dict):
        route_label = "?? SIMPLE" if result["route"] == "simple" else "?? COMPLEX"
        print(f"\n{'='*60}")
        print(f"Route: {route_label} ??{result['model']}")
        print(f"Tokens: {result['input_tokens']} in / {result['output_tokens']} out")
        print(f"Cost: ${result['cost_usd']:.6f}")
        print(f"Running total: ${result['running_total']:.6f} ({self.request_count} requests)")
        print(f"{'='*60}")
        print(result["text"])


if __name__ == "__main__":
    bot = MultiModelChat()

    # Simulate a realistic conversation
    test_messages = [
        "Hi, what can you help me with?",                    # Simple
        "What is a REST API?",                                # Simple
        "Compare the performance characteristics of ERNIE Tiny vs DeepSeek V4 Pro "
        "for a production chatbot handling 10K daily requests, considering latency, "
        "accuracy, and cost. Provide a recommendation.",      # Complex
        "Thanks, that's helpful!",                            # Simple
        "Write a Python function that implements a concurrent "
        "task queue with priority scheduling, rate limiting, "
        "and retry logic with exponential backoff.",          # Complex
    ]

    for msg in test_messages:
        result = bot.chat(msg)
        bot.print_response(result)

    print(f"\n{'='*60}")
    print(f"SUMMARY: {bot.request_count} requests, ${bot.total_cost:.6f} total")
    print(f"Routes: {bot.route_counts}")
Enter fullscreen mode Exit fullscreen mode

Understanding the Cost Flow

Let's trace a realistic session:

Message Route Model Est. Input Est. Output Est. Cost
"Hi, what can you help me with?" Simple ERNIE Tiny 20 tokens 50 tokens $0.000003
"What is a REST API?" Simple ERNIE Tiny 35 tokens 200 tokens $0.000012
Complex comparison question Complex DeepSeek V4 Pro 80 tokens 800 tokens $0.000137
"Thanks!" Simple ERNIE Tiny 60 tokens 20 tokens $0.000004
Concurrent task queue Complex DeepSeek V4 Pro 70 tokens 1200 tokens $0.000182

Session total: ~$0.000338 for 5 real queries, mixing simple and complex.

If every query went to DeepSeek V4 Pro, the same session would cost ~$0.000355. Not a huge difference for 5 queries ??but at 10,000 daily requests where ~60% are simple, you're looking at $6/day vs $10/day. That's $120/month saved by routing intelligently.

Production Considerations

1. Replace the heuristic router with a classifier. The pattern-matching router works but a small model like GLM-4.7-Flash (budget tier on AIWave) can classify complexity with much higher accuracy:

def ml_classify(message: str) -> str:
    response = client.chat.completions.create(
        model="glm-4.7-flash",  # Budget tier
        messages=[
            {"role": "system", "content": (
                "Classify the user message. Reply ONLY 'simple' or 'complex'. "
                "Simple: greetings, definitions, short factual questions. "
                "Complex: code generation, analysis, comparisons, debugging."
            )},
            {"role": "user", "content": message}
        ],
        max_tokens=10,
        temperature=0.0
    )
    return response.choices[0].message.content.strip().lower()
Enter fullscreen mode Exit fullscreen mode

2. Add caching. Identical or near-identical queries shouldn't hit the API twice. Use a simple hash-based cache with TTL.

3. Monitor your routing distribution. If 90% of queries route to "complex," your complexity threshold is too low and you're spending unnecessarily.

Get Started

All models in this article are available on AIWave with an OpenAI-compatible API. New accounts get $5 free credit ??enough to process thousands of queries and validate your routing strategy before committing.

Check the full model catalog at aiwave.live/models and the pricing page for detailed cost breakdowns.


Sign up | Pricing | Discord

Building production AI systems? Share your architecture in the AIWave Discord.

Top comments (0)