All guides
Build an agent with tool calling
An agent is a loop: the model reads the task, asks for one of your tools, your code runs it and sends back the result, and the model continues until it can answer. The model decides what to do; your code decides what is allowed.
Recommended models
Chosen from models whose abilities we have verified for this job. Cost is for one agent step (about 3K tokens in, 300 out), at current prices.
| Model | Input / 1M | Output / 1M | Context | Per request |
|---|---|---|---|---|
| Our pickDeepSeek V4.1 Flash 1017 deepseek/deepseek-v4.1-flash-1017 | $0.375 | $1.50 | 1.05M | $0.001388 |
| Also strongGLM 5.3 z-ai/glm-5.3 | $1.75 | $5.50 | 1.05M | $0.006025 |
| Lowest costgpt-oss-20b openai/gpt-oss-20b | $0.0625 | $0.5625 | 128K | $0.000325 |
How it works
- 1Write ordinary functions for what the agent may do, and describe each with a name, a description and JSON Schema parameters.
- 2Call the model with tools. If the reply contains tool_calls, run each one and append a tool message with its result.
- 3Repeat until the model answers without tool calls. Always cap the number of steps.
Copy, paste, run
Set AMR_API_KEY to a key from your dashboard, install the OpenAI SDK (pip install openai or npm install openai) and run it. Swap the model for any other in the table.
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.aimodelsrouter.ai/v1", api_key=os.environ["AMR_API_KEY"])
MODEL = "deepseek/deepseek-v4.1-flash-1017"
# 1. Your real functions. The model decides when to call them; your code runs them.
def get_order_status(order_id: str) -> dict:
return {"order_id": order_id, "status": "processing", "carrier": None} # replace with a real lookup
def refund_order(order_id: str, reason: str) -> dict:
return {"order_id": order_id, "refund": "approved", "amount_usd": 49.0} # replace with a real action
FUNCTIONS = {"get_order_status": get_order_status, "refund_order": refund_order}
# 2. Describe them to the model.
tools = [
{"type": "function", "function": {
"name": "get_order_status", "description": "Look up the shipping status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}},
{"type": "function", "function": {
"name": "refund_order", "description": "Refund an order. Only when the customer asks for a refund.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}, "reason": {"type": "string"}},
"required": ["order_id", "reason"]}}},
]
# 3. The agent loop: call the model, run the tools it asks for, send back the results, repeat.
messages = [{"role": "user", "content": "Where is my order 1042? If it hasn't shipped yet, refund it."}]
for _ in range(10): # safety limit on steps
response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = response.choices[0].message
if not message.tool_calls:
print(message.content)
break
messages.append(message.model_dump(exclude_none=True))
for call in message.tool_calls:
result = FUNCTIONS[call.function.name](**json.loads(call.function.arguments))
print(f"-> {call.function.name}({call.function.arguments}) = {result}")
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})Tested 2026-10-28: both versions were run against the live API with each model recommended at the time, and their answers checked.
Tips
- Write tool descriptions as instructions: when to use the tool and when not to. Vague descriptions cause wrong calls.
- Validate arguments and permissions in your code before running an action such as a refund; never trust the model's arguments blindly.
- Return real errors from tools (for example "order not found") so the model can recover instead of guessing.
All 31 models that fit this job
- gpt-oss-20b$0.000325
- Qwen3 30B A3B Instruct 2507$0.000425
- DeepSeek V4 Flash 0423$0.000543
- DeepSeek V4 Flash 0731$0.000543
- gpt-oss-120b$0.000575
- GLM 5.3 Flash$0.000656
- Ministral 3 14B 2512$0.0007
- Gemma 4 31B$0.00075
- Nemotron Nano 12B v2 VL$0.00085
- Qwen3 235B A22B Instruct 2507$0.00085
- Llama 4 Maverick$0.001108
- Nemotron 3.5 Super VL$0.001181
- DeepSeek V4.1 Flash$0.001388
- DeepSeek V4.1 Flash 1017$0.001388
- Beam 1.0 501B A23B$0.0017
- Nemotron 3 Nano Omni$0.0019
- DeepSeek V3.2$0.002163
- Qwen3.8 27B$0.002531
- Qwen3.5 397B A17B$0.003031
- Nemotron 3 Ultra$0.00345
- MiMo-V2.5-Pro$0.003625
- Hermes 4 405B$0.00425
- Kimi K2.6$0.004469
- Kimi K2.7 Code$0.004469
- DeepSeek V4 Pro 0813$0.00561
- GLM 5.1$0.006025
- GLM 5.2$0.006025
- GLM 5.3$0.006025
- DeepSeek V4 Pro 0423$0.006743
- Qwen3.8 Max (open weights, 2.4T A95B)$0.0085
- Kimi K3$0.0150