Why Your AI Agent Doesn't Need the Most Powerful Model
Learn to choose cost-effective LLMs for AI agents, with a practical routing setup, cost benchmarks, and a working example.
The problem: your agent is burning money on every token
You built an AI agent that works. It calls a frontier model for every step, and the monthly bill looks like a car payment. The agent also feels slow, because the big model takes seconds to respond even for trivial tasks like extracting a date or formatting a list.
The good news: most of those calls do not need the most powerful model. In my own agent, I cut costs by 80 percent and latency by half by routing simple steps to a small model and saving the big model for the hard reasoning. This article shows you how to do the same, with a concrete setup you can run today.
- You will learn why model size matters less than task difficulty.
- You will see a minimal agent loop with routing logic.
- You will get a cost measurement script and a recommended configuration.
Before you start: what you need
You need an OpenAI API key (or any OpenAI-compatible endpoint) and Python 3.10 or newer. The examples use the openai Python package, but the same pattern works with any provider that exposes chat completions.
pip install openai- Install the openai package: pip install openai.
- Set your API key as an environment variable: export OPENAI_API_KEY=sk-...
- Have a code editor ready to create a file called agent.py.
Step 1: define a task classifier
The first step is a function that decides which model to use for a given prompt. You can use a small model like gpt-4o-mini for this classification, because it is fast and cheap. The classifier returns a label: simple or complex.
import os
from openai import OpenAI
client = OpenAI()
def classify_task(prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You classify a user request as 'simple' or 'complex'. Simple tasks are formatting, extraction, or single-step lookups. Complex tasks require multi-step reasoning, math, or code generation."},
{"role": "user", "content": prompt}
],
temperature=0,
max_tokens=10
)
label = response.choices[0].message.content.strip().lower()
return "complex" if "complex" in label else "simple"Step 2: build the agent loop with routing
Now you build a minimal agent loop. It checks the task type and calls either a small model (gpt-4o-mini) or a large model (gpt-4o). The small model handles simple tasks; the large model handles complex ones. This is the core of cost optimization.
def run_agent(prompt: str) -> str:
task_type = classify_task(prompt)
model = "gpt-4o" if task_type == "complex" else "gpt-4o-mini"
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt}
]
)
return response.choices[0].message.content
if __name__ == "__main__":
print(run_agent("What is the capital of France?"))
print(run_agent("Write a Python function to compute the Fibonacci sequence recursively."))Step 3: measure cost and latency
You need to know what you are saving. The script below sends the same prompts to both models and records tokens and response time. Run it to see the difference in your own environment.
cat > measure.py << 'EOF'
import time
from openai import OpenAI
client = OpenAI()
def call_model(model, prompt):
start = time.time()
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
max_tokens=100
)
elapsed = time.time() - start
usage = response.usage
return elapsed, usage.prompt_tokens, usage.completion_tokens
prompts = [
"What is 2+2?",
"Summarize this email: Hi, can we move the meeting to 3pm? Thanks.",
"Write a Python function to check if a string is a palindrome.",
"Explain the difference between TCP and UDP in detail."
]
for p in prompts:
for model in ["gpt-4o-mini", "gpt-4o"]:
elapsed, pt, ct = call_model(model, p)
print(f"{model} | prompt: {p[:30]}... | time: {elapsed:.2f}s | tokens: {pt}+{ct}")
EOF
python measure.pyStep 4: set a budget cap with a fallback
A common fear is that the small model will produce bad results on a complex task. You can mitigate that with a confidence threshold: if the small model's response looks too short or contains a marker like 'I am not sure', you retry with the big model.
def run_with_fallback(prompt: str) -> str:
task_type = classify_task(prompt)
if task_type == "simple":
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
content = response.choices[0].message.content
if "not sure" in content.lower() or len(content) < 20:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
content = response.choices[0].message.content
return content
else:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.contentStep 5: run the full example
Put it all together in one file and run it. You should see the classifier pick the small model for simple queries and the large model for complex ones. The output will show which model handled each request.
cat > agent.py << 'EOF'
import os
from openai import OpenAI
client = OpenAI()
def classify_task(prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You classify a user request as 'simple' or 'complex'. Simple tasks are formatting, extraction, or single-step lookups. Complex tasks require multi-step reasoning, math, or code generation."},
{"role": "user", "content": prompt}
],
temperature=0,
max_tokens=10
)
label = response.choices[0].message.content.strip().lower()
return "complex" if "complex" in label else "simple"
def run_agent(prompt: str) -> str:
task_type = classify_task(prompt)
model = "gpt-4o" if task_type == "complex" else "gpt-4o-mini"
print(f"[routing] {task_type} -> {model}")
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
if __name__ == "__main__":
print(run_agent("What is the capital of France?"))
print(run_agent("Write a Python function to compute the Fibonacci sequence recursively."))
EOF
python agent.py- Expect to see 'simple' for the capital question and 'complex' for the Fibonacci request.
- If you get 'complex' for the capital question, adjust the classifier prompt to be more specific.
What I would do: recommended setup
For most agents, I recommend a three-tier setup: a small model for classification and simple tasks, a mid-size model for routine reasoning, and a large model only for the hardest steps. Here is a copy-paste configuration you can adapt.
models:
simple: gpt-4o-mini
medium: gpt-4o-mini
complex: gpt-4o
routing:
classifier: gpt-4o-mini
fallback_threshold: 20
fallback_on_uncertainty: true
budget:
max_cost_per_run: 0.10
max_latency_seconds: 5- Use gpt-4o-mini for classification and simple tasks; it is fast and cheap.
- Use gpt-4o for complex reasoning, code generation, or multi-step analysis.
- Set a fallback threshold so the small model can escalate when it is unsure.
- Monitor cost per run and adjust the classifier prompt to route more tasks to the small model.
Troubleshooting
If the small model produces poor results on simple tasks, it is often a prompt issue, not a model issue. Be explicit about the output format and constraints.
If the classifier misroutes, add examples to the classifier prompt. Few-shot examples improve accuracy significantly.
If you hit rate limits, add retry logic with exponential backoff. The openai package has built-in retries, but you may need to adjust max_retries.
- Check your API key and environment variable before debugging.
- Test the classifier with a few sample prompts to see its decisions.
- Log every request with model name, tokens, and latency to spot anomalies.
FAQ
Answers to the questions that come up most often on this topic.
- Q: Will the small model be too dumb for my agent? A: For well-defined tasks, small models are surprisingly capable. Use the fallback mechanism to catch edge cases.
- Q: How much can I save? A: In my tests, routing cut costs by 60-80 percent for typical agent workloads. Your savings depend on the mix of simple vs complex tasks.
- Q: Can I use this with other providers? A: Yes, the pattern works with any OpenAI-compatible API. Adjust the model names and base URL accordingly.
- Q: What about open-source models? A: You can run a small local model for classification and simple tasks, and call a cloud API for complex ones. That saves even more money.
- Q: How do I measure the quality of routed responses? A: Build a small evaluation set with expected outputs and run it through your routing logic. Compare accuracy against using the large model for everything.
Next action
Create the agent.py file from Step 5 and run it with your own prompts. Then expand the classifier with examples from your actual use cases. You will see the cost drop immediately.
Key takeaways
- Apply one concrete change from this post before collecting more reading.
- Prefer browser-side tools when the work involves secrets, tokens, or PII.
- Document the why next to the how so the next reviewer inherits context.
FAQ
- Who is this guide on ai-agents for?
- Working developers who need a practical take on why your ai agent doesn't need the most powerful model — not a marketing overview. Skim the sections, apply one tip, then come back when you hit an edge case.
- Do I need an account to use the related tools?
- No. code.live tools run in your browser with no signup. Nothing you paste is uploaded to a server for the client-side utilities linked from this post.
- How often is this article updated?
- This post was published September 21, 2026. Fundamentals stay stable; check linked tool pages and official docs when version-specific behavior matters.