Tool use compatibility across relay sites, and how to self-test it
Why tool calling breaks most often
Differences in text generation quality are obvious at a glance. Tool calling is not like that, because its failures are usually silent:
- Arguments get mangled and the model raises nothing. It simply performs the wrong action.
- Context is lost across turns, which shows up as "the agent suddenly forgot what it just did".
- Tool calls are chunked incorrectly under streaming, which shows up as "the tool call stopped halfway".
Worse, none of these appear in a simple test. So if you are building agent-style applications, tool calling has to be verified on its own.
How the three APIs differ structurally
OpenAI
- Request:
tools(an array whose elements are{"type":"function","function":{...}}) plustool_choice - Response:
message.tool_calls, wherefunction.argumentsis a JSON string, not an object - Returning a result: a message with role
tool, carrying atool_call_id
Anthropic
- Request:
tools, whose elements are{"name","description","input_schema"}with no outer function wrapper - Response: entries inside the
contentarray shaped{"type":"tool_use","id","name","input"}, whereinputis an already-parsed object - Returning a result:
{"type":"tool_result","tool_use_id","content"}insidecontent
Gemini
- Request:
tools[].functionDeclarations - Response: the
functionCallpart
Put plainly, the differences are: whether arguments is a string or an object, how many wrapper layers there are, and which field links a result back to its call. Those three are exactly where conversions go wrong.
Three common failures
Failure one: double-encoded arguments
The most common bug of the lot. OpenAI's arguments is a string; Anthropic's input is an object.
If the gateway serialises arguments a second time even though it is already a string, or goes the other way and passes an object through as though it were a string, you get:
- arguments as an escaped string,
"{\"city\":\"Beijing\"}"instead of{"city":"Beijing"} - or a parse failure, and the tool receives empty arguments
Symptom: the tool really is called, but with the wrong arguments.
Self-test: design a trivial tool that cannot work without an argument, such as get_weather(city), and check whether the argument arrives intact.
Failure two: context lost across turns
The typical agent loop is "model requests a tool → you execute it → you return the result → the model continues". That requires the gateway to keep tool_use and tool_result (or tool_calls and role=tool) structurally consistent across the round trip.
If the gateway downgrades a tool result into an ordinary text message at some point, the model loses the semantic "this is the result of the call I just made", and you see:
- the same tool called over and over
- the model still saying "I have not been able to retrieve that" after receiving the result
Self-test: design a two-turn call, weather first and then a recommendation based on it, and see whether turn two behaves.
Failure three: chunked tool calls under streaming
Non-streaming gives you one complete JSON payload. Streaming splits it into many delta fragments, which the client or gateway has to reassemble by index.
If the reassembly logic is wrong, arguments arrive incomplete — city comes through and date is lost, for example.
Self-test: run the same tool call streaming and non-streaming, and compare the final arguments.
A ten-minute self-test
Prepare one tool with two arguments:
{
"name": "book_room",
"description": "Book a meeting room",
"parameters": {
"type": "object",
"properties": {
"room": {"type": "string", "description": "Room name"},
"people": {"type": "integer", "description": "Number of people"}
},
"required": ["room", "people"]
}
}
Then run four cases in order:
| # | Case | Checkpoint |
|---|---|---|
| 1 | Single turn, non-streaming | Both arguments parse correctly; arguments is not a double-encoded string |
| 2 | Single turn, streaming | Arguments are complete after reassembling the fragments |
| 3 | Multi-turn: call → return result → continue | Turn two can refer to the previous result |
| 4 | Call a tool that does not exist | The error comes back structured, not as a silent success |
Pass all four and the site's tool-calling path is usable. Fail any one and you will hit faults in a real agent that are very hard to localise.
What this means per use case
- Plain text chat: if you never use tools, you can ignore this article.
- Coding assistants (Claude Code, Cursor, Cline): this has to pass. Tool calling is the core mechanism of these tools; reading files, editing files and running commands all depend on it. One lesson the industry keeps relearning: when a client shows odd tool behaviour after being pointed at a relay site, suspect the relay's protocol conversion layer first, not the client.
- Agents and workflows (Dify, FastGPT, in-house): this has to pass, and multi-turn has to be tested.
- RAG applications: pure retrieval plus generation can skip it, but the moment you use a function to route retrieval, you have to test it.
One practical recommendation
If you are building agent-style products, put this self-test on your supplier onboarding checklist, at the same level as "can we connect at all".
A connectivity problem takes you five minutes to find. A tool-calling problem may take you two weeks, and you will suspect your own code first.
Was this useful? If you have run into something the article does not cover, tell us and we will verify it and update the text.
Related articles
Video generation behind a relay: three API shapes, four billing traps, one acceptance checklist
MCP through a relay: what works, what never will, and how to test it in ten minutes
A relay selection decision tree: working back from your scenario to a site
Logging and reconciliation: attributing token spend to the project level
Migrating suppliers gradually: replacing an API site without interrupting service
Build your own probe: twenty lines of script to monitor your API suppliers
Read on: a few of the services we list
This article does not point at a specific model family, so here are a few of the highest-scoring services we list, in case you want to read on. They are ordered by score and uptime and are not a recommendation.
See the full list in the directory, or browse by model family.