Claude or GPT for a tool-using agent — how to choose
Both lineups have vision, extended thinking and a 1M context window — the real difference is how each API shapes tool calls and what happens when a loop step fails.
4 min · · Updated · models · агенты
Behind one fetch_... key sit both text-model lineups: claude-opus-5-5 and claude-sonnet-5, plus gpt-5.6-sol and gpt-5.6-luna — and also glm-5.3 and glm-5.3-flash (current list: GET https://api.zukko.pro/v1/models). The Claude and GPT models accept images and have a 1,000,000-token context window (GLM has 128K and no vision). So picking a model for a tool-using agent isn't really about capability specs — it comes down to how each API shapes tool calls and what your code does when a step in the loop fails.
Two tool-calling shapes behind one key
The Anthropic-compatible path — POST /v1/messages with the anthropic-version: 2023-06-01 header — describes tools as a tools array in the request body, and the model replies with tool_use content blocks. The OpenAI-compatible path is either POST /v1/chat/completions or POST /v1/responses, which "accepts a string, a message array, and tools" — there, calls arrive as tool_calls inside the message object.
curl https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_your_key" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"tools": [{"name": "get_weather", "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}}],
"messages": [{"role": "user", "content": "Weather in Austin?"}]
}'curl https://api.zukko.pro/v1/responses \
-H "Authorization: Bearer fetch_your_key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-sol",
"tools": [{"type": "function", "name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}}],
"input": "Weather in Austin?"
}'Note the base URL split: Anthropic-compatible clients (Claude Code, the Anthropic SDK) call https://api.zukko.pro with no /v1 — the client appends the path itself. OpenAI-compatible clients and direct curl calls to /v1/responses go with the /v1 suffix. If you're building an agent from scratch and switching model families mid-project, this is the first place a 404 shows up.
Tools cost tokens before the model answers anything
Tool schemas (the tools array) land in the prompt and count as regular input tokens the same way in both APIs. If your agent carries a dozen tools with verbose JSON Schemas, that's a real chunk of context before the user's first message even arrives. Before running a real agent loop, it's worth measuring what the system prompt plus tool definitions actually cost, using the free token count:
curl https://api.zukko.pro/v1/messages/count_tokens \
-H "Authorization: Bearer fetch_your_key" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model": "claude-sonnet-5", "tools": [...], "messages": [{"role":"user","content":"ping"}]}'This costs nothing and never reaches the model — it only counts. There's no separate count-tokens endpoint for the OpenAI-compatible path, but running the same tool schema through claude-sonnet-5 gives a comparable estimate of the volume involved, since JSON Schema tokenizes similarly either way.
What breaks in a long agent loop
A tool-using agent typically runs several rounds: call the model, run the tool, call the model again with the result. If the client times out mid-round, retrying with the same Idempotency-Key (unique to each step, identical across retries of that step) within 24 hours returns the identical response without charging twice — that saves you from duplicated tool invocations when the network hiccups right as a response comes back.
Second: the model catalog changes over time. When an old id is retired with a named replacement, that surfaces as 400 model_retired, not a 404:
{"error": {"message": "Model 'gpt-5.4' has been retired. Use 'gpt-5.6-sol' instead", "code": "model_retired"}}If a model is simply disabled in the catalog (that's what claude-opus-4.6 returns now, for example), you get 503 model_disabled — with no replacement in the text. It's worth writing agent code that, on model_retired, parses the message field, extracts the replacement name, and retries the step with the new model, and on model_disabled falls back to a preconfigured backup model — otherwise the agent loop just stops dead in production until someone edits the config by hand.
Third — if you deliberately restricted the key handed to your agent to a list of cheap models on the key's page in the dashboard, and the agent logic suddenly tries to escalate to claude-opus-5-5 or gpt-5.6-sol, you'll get 403 model_not_allowed_for_key. That's not a gateway bug, it's the policy doing its job — handle it the same way as a retired model: fall back to an allowed model, or fail loudly with a clear error instead of retrying blindly.
A practical way to pick
If the agent reads a lot of images — screenshots, diagrams, scans — any Claude or GPT model works, since they all accept images (GLM doesn't). If the economics of a long loop with frequent intermediate calls matter more, route by cost: try a cheaper model first (gpt-5.6-luna or glm-5.3, $0.10 per 1M tokens), and only escalate to claude-opus-5-5 or gpt-5.6-sol ($0.30) on harder steps or explicit validation failures — test which model handles your steps. One caveat on long contexts: vendors charge about 10% of the input price for prompt-cache reads, while Zukko bills cached tokens at the normal rate, so for agents with a large repeated context the real gap versus official pricing is smaller than a head-to-head comparison suggests. This routing works the same for both lineups because both APIs sit behind one gateway with one balance — the spend for each step shows up in the X-Zukko-Cost-Micros response header (on non-streaming requests), and you can log it per tool call without waiting for a rolled-up report from /v1/usage.
If a project is already built on the Anthropic Messages API — say you started from Claude Code or the Anthropic SDK — there's no need to switch formats just to try a GPT model: gpt-* models also answer through /v1/chat/completions and /v1/responses, but rewriting your tool_use parsing into tool_calls handling is only worth it when you specifically need a model from that other family, not on the vague chance that it might be better.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- AI agent vs AI assistant: the difference and what to pick for a taskA model answers, an assistant remembers the dialogue, an agent takes steps with tools on its own. The differences by example, and how to decide what your task needs.
- Roo Code Ollama: local models in Cline and Aider, an honest lookWe connect Ollama to Roo Code, Cline, Aider and OpenCode per each tool's documentation, cover the limits and show when it is simpler to return to a cloud API.
- opencode agents: setting up roles, models and toolsA custom agent in opencode is a role, a model and a set of permissions. A working config where a cheap model handles routine work and a stronger one edits code.
- Plan mode in Claude Code: plan first, then edit the codeIn plan mode Claude Code reads your code and proposes a plan but edits nothing until you agree. How to enable it, use it and what it costs.