Agent with tools
You'll end up with an agent: the model decides on its own when to check the weather, calculate or search the web, and your code runs those actions and hands the results back.
You need: a separate fetch_... key with a spend limit and an allowed-models list (create one), Python 3.10+ and pip install openai.
- 1Save the code
File
agent.py. Tools:get_weather(a stub instead of a weather service) andcalculate(a calculator).agent.py""" Agent with tools: the model decides which function to call. pip install openai python agent.py "What is the weather in London and in Madrid? How much warmer is Madrid?" """ import ast import json import operator import os import sys from openai import OpenAI MODEL = "deepseek-v4.1-flash" # or "claude-haiku-5-5", "gpt-6-luna" - 2Run itbash
export ZUKKO_API_KEY="fetch_your_key" python agent.py "What is the weather in London and in Madrid? How much warmer is Madrid?"The model asks for the weather in both cities, then for the difference, then answers. Every call is printed.
- 3Add web search (optional)
Paste the code into
agent.pybeforeif __name__ == "__main__":, and add "call web_search for fresh facts" toSYSTEM.pythonimport urllib.error import urllib.request def web_search(query: str) -> dict: request = urllib.request.Request( "https://api.zukko.pro/v1/web-search", data=json.dumps({"query": query, "max_results": 5}).encode(), headers={ "Authorization": f"Bearer {os.environ['ZUKKO_API_KEY']}", "Content-Type": "application/json", }, ) try:Up to 10 results, about $0.0003–0.0005 per search, counts toward the key's limits. Parameters: POST /v1/web-search.
1The agent loop
- Send the conversation with the
toolsparameter. - Got
tool_calls? Run each call and return the result as a message with thetoolrole and the matchingtool_call_id. Go back to step 1. - No
tool_calls—contentholds the final answer.
MAX_STEPS and MAX_COST_USD stop the agent if it goes in circles. To add your own tool: a function in TOOL_FUNCTIONS and a description in TOOLS.
2Models
| Model | Price per 1M tokens, input / output |
|---|---|
deepseek-v4.1-flash | $0.03 / $0.10 |
claude-haiku-5-5 | $0.05 / $0.20 |
gpt-6-luna | $0.04 / $0.21 |
Tested through /v1/chat/completions. With the Anthropic SDK and /v1/messages, tools are passed the same way as in the Anthropic API.
3If it doesn't work
| What you see | What to do |
|---|---|
| The model answers with text and never calls a tool | Sharpen the description and the instruction; use a model from the table above |
400 after answering a call | Answer every call in tool_calls with a tool message carrying its tool_call_id |
| The agent calls the same thing in circles | Return a clear error message from the tool |
| The model invents arguments | Validate them in the function and return an error — the model will fix it |
429 key_daily_limit_reached | The key limit kicked in — check whether the agent got stuck in a loop |