Try Chat Free Docs Pricing AI Analysis Repo Insights Free Tools About Blog
Sign in Get started free
< Back to blog
Tutorial Velona Team ·2 September 2026 ·14 min read

Build a Cheap AI Agent in Python with DeepSeek, Kimi & Grok

AI agents are becoming more useful because they can break a goal into smaller tasks, decide what needs to be done, and work through multiple steps before returning an answer.

There is one problem with many simple AI agents. They use the same language model for every step.

A planning step, a simple extraction task, a coding task, and a final review do not necessarily need the same level of model capability.

Using a powerful model for every step can make an agent unnecessarily expensive, especially when one user request results in several LLM calls.

In this tutorial, we will build a cheap AI agent in Python that uses different models for different tasks. We will use DeepSeek for lightweight planning and review, DeepSeek V3.2 for general execution, Kimi K2.6 for coding and more demanding agentic tasks, and Grok 4.20 as an escalation model when a stronger reasoning pass is needed.

All of the models will be accessed through Velona's unified AI gateway, so the application only needs one API integration.

What Makes an AI Agent Different from a Chatbot?

A chatbot usually follows a simple pattern. The user sends a message and the model generates a response.

User
  ↓
LLM
  ↓
Response

An agent has another layer of decision making.

User Goal
   ↓
Agent
   ↓
Plan
   ↓
Execute tasks
   ↓
Review results
   ↓
Final response

The agent can therefore make several model calls while working on one user request.

That creates an important engineering problem. If every step uses an expensive model, the cost of completing one task can become much higher than the cost of a normal chatbot response.

Why Use Different Models for Different Agent Tasks?

Different models have different prices and capabilities.

For example, Velona currently lists DeepSeek V4 Flash at ₹8.32 per million input tokens and ₹16.63 per million output tokens. Kimi K2.6 is listed at ₹97.66 per million input tokens and ₹411.18 per million output tokens. Grok 4.20 is listed at ₹128.48 per million input tokens and ₹256.96 per million output tokens.

That difference becomes important when an agent makes several calls for a single task.

Instead of doing this:

User
  ↓
Expensive model
  ↓
Plan
  ↓
Expensive model
  ↓
Execution
  ↓
Expensive model
  ↓
Review
  ↓
Expensive model
  ↓
Final answer

we can use a model that fits each step:

User
  ↓
DeepSeek V4 Flash
Planning
  ↓
DeepSeek V3.2
General execution
  ↓
Kimi K2.6
Coding or difficult task
  ↓
DeepSeek V4 Flash
Review
  ↓
Grok 4.20
Only when escalation is needed
  ↓
Final answer

The goal is not to always use the cheapest model. The goal is to use the cheapest model that can reliably perform each task.

Model prices change over time, so check the Velona Pricing Index before using these values for production cost calculations.

Our Cheap AI Agent Architecture

Our agent will have four main stages.

Grok 4.20 will not be used for every request. It will act as an escalation model when the reviewer decides that the result needs a stronger reasoning pass.

User
  ↓
Planner
DeepSeek V4 Flash
  ↓
Task list
  ↓
┌───────────────────────────┐
│ Simple task               │
│ ↓                         │
│ DeepSeek V3.2             │
│                           │
│ Coding or difficult task  │
│ ↓                         │
│ Kimi K2.6                 │
└───────────────────────────┘
  ↓
Reviewer
DeepSeek V4 Flash
  ↓
Good enough?
  ├── Yes → Final answer
  └── No → Grok 4.20
             ↓
          Final answer

Setting Up the Python Project

We will use Python and httpx to communicate with the Velona gateway.

pip install httpx python-dotenv

Create a .env file:

VELONA_API_KEY=YOUR_API_KEY

Keep your API key outside your source code and never commit the .env file to a public repository.

Connecting to the Velona Gateway

Velona's native inference endpoint is:

https://velona.in/gateway/v1/inference/run

The API accepts a model ID and an array of conversation turns. It also supports JSON output, generation configuration, streaming, and other gateway features.

For this tutorial, we will use JSON output for the planning and review stages because the Python application needs to make decisions based on the model's response.

Defining Our Models

Keep the model IDs in one place so that they can be changed without rewriting the agent.

import os
import json
import httpx
from dotenv import load_dotenv

load_dotenv()

API_KEY = os.environ["VELONA_API_KEY"]

API_URL = "https://velona.in/gateway/v1/inference/run"

MODELS = {
    "planner": "deepseek/deepseek-v4-flash",
    "worker": "deepseek/deepseek-v3.2",
    "specialist": "moonshotai/kimi-k2.6",
    "escalation": "x-ai/grok-4.20"
}

The important idea here is that the agent does not have one fixed model.

Each role has its own model configuration.

Building the Basic Inference Function

We first need one function that can call any model through the gateway.

def call_model(model, turns, output_format="text"):
    response = httpx.post(
        API_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"
        },
        json={
            "model": model,
            "turns": turns,
            "stream": False,
            "output": {
                "format": output_format
            }
        },
        timeout=120
    )

    response.raise_for_status()

    return response.json()

Because the model is passed as an argument, the same function can call DeepSeek, Kimi, Grok, or any other compatible model available through the gateway.

Step 1: Build the Planner

The planner receives the user's goal and turns it into a small list of tasks.

For example, if the user asks:

Build a Python script that reads a CSV file,
finds duplicate emails, and creates a cleaned CSV.

The planner might produce:

{
  "tasks": [
    {
      "description": "Understand the CSV structure",
      "type": "analysis"
    },
    {
      "description": "Write Python code to identify duplicate emails",
      "type": "coding"
    },
    {
      "description": "Write the cleaned CSV output",
      "type": "coding"
    }
  ]
}

We can ask the inexpensive planner model to return this structure.

def create_plan(user_goal):
    turns = [
        {
            "role": "system",
            "content": (
                "You are the planning component of an AI agent. "
                "Break the user's goal into a small number of useful tasks. "
                "Return valid JSON with a tasks array. "
                "Each task must contain description and type. "
                "Use types such as analysis, coding, writing, "
                "research, or general."
            )
        },
        {
            "role": "user",
            "content": user_goal
        }
    ]

    result = call_model(
        MODELS["planner"],
        turns,
        output_format="json"
    )

    return result["data"]["output"]

The planner is deliberately lightweight. There is little reason to use an expensive model simply to divide a task into smaller pieces.

Step 2: Decide Which Model Should Execute Each Task

Now we need a second routing layer.

Not every task from the plan needs the same model.

def choose_worker(task):
    task_type = task["type"].lower()
    description = task["description"].lower()

    if task_type == "coding":
        return MODELS["specialist"]

    difficult_words = [
        "complex",
        "architecture",
        "debug",
        "algorithm",
        "multi-step",
        "advanced"
    ]

    if any(word in description for word in difficult_words):
        return MODELS["specialist"]

    return MODELS["worker"]

This gives us a simple division of work.

Velona's current model comparison pages show why this can be useful. DeepSeek V3.2 is positioned as a low-cost model for chat, coding assistants, and high-volume production, while Kimi K2.6 has a higher price but stronger coding and agentic tool-use characteristics. :contentReference[oaicite:2]{index=2}

Step 3: Execute the Tasks

Each task can now be passed to the model selected by the router.

def execute_task(task):
    model = choose_worker(task)

    turns = [
        {
            "role": "system",
            "content": (
                "You are a worker inside an AI agent. "
                "Complete the assigned task accurately. "
                "Return only the useful result."
            )
        },
        {
            "role": "user",
            "content": task["description"]
        }
    ]

    result = call_model(model, turns)

    return {
        "task": task,
        "model": model,
        "output": result["data"]["output"],
        "usage": result["data"]["usage"]
    }

Notice that we also save the model and usage information.

This becomes useful later when measuring how much each agent run costs.

Step 4: Add a Reviewer

An agent should not blindly assume that every worker response is correct.

We can use a low-cost model to review the completed work.

The reviewer receives the original goal and the results produced by the workers.

def review_results(user_goal, results):
    summary = json.dumps(results, indent=2)

    turns = [
        {
            "role": "system",
            "content": (
                "You are the review component of an AI agent. "
                "Check whether the work satisfies the user's goal. "
                "Return JSON with approved, issues, and needs_escalation."
            )
        },
        {
            "role": "user",
            "content": (
                f"Original goal:\n{user_goal}\n\n"
                f"Worker results:\n{summary}"
            )
        }
    ]

    result = call_model(
        MODELS["planner"],
        turns,
        output_format="json"
    )

    return result["data"]["output"]

Using the inexpensive planner model for this stage keeps the review step cheap.

Step 5: Escalate Only When Necessary

This is where the cost-aware design becomes more interesting.

We do not want to call Grok 4.20 after every agent run.

Instead, the reviewer can decide whether the result needs another reasoning pass.

def escalate_if_needed(user_goal, results, review):
    if not review.get("needs_escalation", False):
        return None

    summary = json.dumps(results, indent=2)

    turns = [
        {
            "role": "system",
            "content": (
                "You are the escalation model in an AI agent. "
                "Review the previous work, fix the identified issues, "
                "and produce the best final answer."
            )
        },
        {
            "role": "user",
            "content": (
                f"Goal:\n{user_goal}\n\n"
                f"Previous work:\n{summary}\n\n"
                f"Review:\n{json.dumps(review, indent=2)}"
            )
        }
    ]

    result = call_model(
        MODELS["escalation"],
        turns
    )

    return result["data"]["output"]

Grok is therefore a fallback for difficult cases rather than the default model.

Step 6: Build the Agent Loop

We can now connect all the components.

def run_agent(user_goal):
    print("Creating plan...")

    plan = create_plan(user_goal)

    results = []

    for task in plan["tasks"]:
        print(f"Executing: {task['description']}")

        result = execute_task(task)
        results.append(result)

    print("Reviewing results...")

    review = review_results(
        user_goal,
        results
    )

    escalation = escalate_if_needed(
        user_goal,
        results,
        review
    )

    if escalation:
        final_answer = escalation
    else:
        final_answer = "\n\n".join(
            item["output"]
            for item in results
        )

    return {
        "plan": plan,
        "results": results,
        "review": review,
        "final_answer": final_answer
    }

The complete flow is now:

User goal
    ↓
DeepSeek V4 Flash
Planner
    ↓
Task list
    ↓
Task router
    ↓
┌──────────────────────┐
│ General → DeepSeek   │
│ Coding → Kimi        │
│ Complex → Kimi       │
└──────────────────────┘
    ↓
DeepSeek V4 Flash
Reviewer
    ↓
Approved?
 ┌──┴────┐
Yes      No
 ↓        ↓
Final    Grok
answer   escalation
           ↓
        Final answer

Running the Agent

Add a simple command-line interface:

if __name__ == "__main__":
    goal = input("What should the agent do?\n\n")

    result = run_agent(goal)

    print("\nFinal answer:\n")
    print(result["final_answer"])

You can now give the agent a multi-step task instead of a simple question.

For example:

Create a Python script that reads a CSV file,
removes duplicate email addresses,
validates the remaining addresses,
and saves the cleaned data into a new CSV file.

The planner can break this into smaller tasks, the router can send coding work to Kimi K2.6, the reviewer can inspect the results, and Grok can be called only if the review identifies a difficult problem.

Making the Agent Cheaper

The main cost-saving idea is simple.

Do not make every model call equally expensive.

For example, a single agent run might contain:

Agent step Model Why
Planning DeepSeek V4 Flash Low-cost classification and planning
Simple execution DeepSeek V3.2 Low-cost general work
Coding Kimi K2.6 Stronger coding and agentic capabilities
Review DeepSeek V4 Flash Low-cost quality check
Escalation Grok 4.20 Used only when required

The important part is that the expensive escalation step is conditional.

If the first attempt is good enough, the agent never needs to make that call.

Why Agent Costs Can Grow Quickly

A normal chatbot might make one model call for a user message.

An agent can make several calls while completing one goal.

One user request

1 planning call
1 task call
1 coding call
1 review call
1 final call

= multiple inference requests

If every one of those requests uses a high-cost model, the cost of one user task can become much higher than expected.

This is why model selection becomes more important as applications become more agentic.

Velona's current coding model rankings also show the range of price and capability available to developers. DeepSeek V4 Flash, for example, appears among the higher-ranked coding models while remaining dramatically cheaper than many flagship models. :contentReference[oaicite:3]{index=3}

Measuring the Cost of an Agent Run

Velona returns token usage for inference requests, including prompt tokens, completion tokens, and total tokens.

We can calculate the usage across the entire agent run:

def total_tokens(results):
    prompt_tokens = 0
    completion_tokens = 0

    for result in results:
        usage = result["usage"]

        prompt_tokens += usage.get(
            "prompt_tokens", 0
        )

        completion_tokens += usage.get(
            "completion_tokens", 0
        )

    return {
        "prompt_tokens": prompt_tokens,
        "completion_tokens": completion_tokens,
        "total_tokens": (
            prompt_tokens +
            completion_tokens
        )
    }

This lets you measure the actual cost of the agent instead of estimating it from the number of API calls.

Compare It with a Single-Model Agent

The most useful experiment is to run the same tasks using two architectures.

Run the same test prompts through both systems and record:

This is more useful than simply saying that a multi-model agent is cheaper. The real question is whether the lower cost comes without an unacceptable reduction in quality.

Do Not Route Only by Price

A cheap model is not automatically the right model.

An agent should consider the requirements of the task before selecting a model.

This is also why model benchmarking matters. Velona provides model pricing and benchmark information so developers can compare cost and capability before choosing a model for a workload.

Adding Memory to the Agent

Our current agent keeps its state inside the Python process.

For a longer-running assistant, you may want the agent to remember previous conversations or task context.

Velona's gateway supports memory sessions that can be attached to inference requests using the velona.memory_session field.

This allows the gateway to maintain conversation context instead of requiring the application to resend the complete history on every request.

For example:

result = call_model(
    MODELS["worker"],
    [
        {
            "role": "user",
            "content": "Continue working on the previous task."
        }
    ]
)

For a production implementation, attach the appropriate memory session to the gateway request rather than manually copying an increasingly large conversation history into every prompt.

Where This Architecture Is Useful

A multi-model agent can be useful for many applications.

The same architecture can be adapted to different workloads by changing the planner, task router, tools, and model assignments.

When a Cheap AI Agent Is Not the Right Choice

Using several models adds complexity.

If your application only needs one simple LLM call, a multi-model agent is probably unnecessary.

It becomes useful when a task naturally contains several steps and those steps have different requirements.

You should also avoid adding an agent simply because the application can use one. If a deterministic function can perform a task reliably, it is usually better to use the function instead of spending tokens on an LLM.

What We Built

We started with a normal LLM request and turned it into a cost-aware agent.

User
  ↓
Planner
  ↓
Task Router
  ↓
┌──────────────┬──────────────┐
│ General      │ Coding       │
│ DeepSeek     │ Kimi         │
└──────────────┴──────────────┘
  ↓
Reviewer
  ↓
Escalation if needed
  ↓
Grok
  ↓
Final answer

The important idea is not the specific combination of models.

The important idea is that an agent does not need to use the same LLM for every step.

Once the application treats model selection as part of the agent architecture, you can optimize for cost, latency, context size, and quality at the same time.

Conclusion

AI agents can become expensive because one user request can trigger several model calls.

Using one powerful model for planning, execution, coding, and review is simple, but it can waste money on tasks that do not need that level of capability.

In this tutorial, we built a different approach. DeepSeek V4 Flash handles lightweight planning and review, DeepSeek V3.2 handles general work, Kimi K2.6 handles coding and more demanding tasks, and Grok 4.20 is reserved for escalation.

The result is a more cost-aware agent architecture that can be adapted as model prices and capabilities change.

The next step is to benchmark the agent against real workloads. Measure quality, latency, token usage, escalation frequency, and INR cost before deciding which model should handle each part of your own agent.

You can explore the current Velona model pricing, compare models in the model index, or follow the API documentation to start building your own multi-model AI agent.