Tool Haystack

2026-07-30 15:25 UTC · b288482

About this benchmark

Forty-four banking tools, one customer message, six cases. An earlier version offered thirty tools drawn from different corners of the bank and every target scored 100: when the answer is about a statement and the distractors are branch lookups, topic settles it without a description being read.

So the list is built in families. Eight tools take a card and its last four digits, six report transactions, six speak about statements, and the clause that separates them sits at the end of the description: a block is permanent, a freeze is reversible, a loss report changes nothing. Family members are scattered rather than grouped, and two cases are built so the tool whose name best fits the message is the wrong one.

`tool` is a gate, so a wrong pick scores zero however many arguments matched, and the arguments stay at transcription throughout. Three messages come from `tool-call` word for word, so the same request can be read at eight tools and at forty-four.

Cases

  • hold-not-block: `stolen-card` read the other way, from the same eight card tools: the customer says not to cancel, so the answer is the hold they can lift.
  • merchant-search: The customer names the merchant, which rules out listing the window. `list_recurring_charges` answers "a double bill" rather than the request.
  • pending-not-posted: The merchant is named, so `search_transactions` looks right and is the one tool that cannot answer: it returns settled charges, and this one has not settled.
  • standing-not-scheduled: `schedule_transfer` runs once on a named day. The money moves every month.
  • statement-month: Six tools in the list speak about statements and only one returns what the month closed at.
  • stolen-card: `report_card_lost` records the loss but leaves the card chargeable, while a temporary freeze is for a card expected back. This one will not be recovered.

Results

15/15 targets scored · 6 trials each · $0.59 total

Cost vs latencylower-left is better
Latency & costshorter is better
TargetScoreStddevLatencyTok/sCostErrors
bestQwenqwen3.7-flash@alibaba100.00.03.5s115.3best$0.00150/6
OpenAIgpt-5-mini@openai100.00.06.5s41.1$0.00820/6
Geminigemini-2.5-flash@google-ai-studio100.00.01.5s33.6$0.00930/6
Geminigemini-3.5-flash-lite@google-ai-studio100.00.0best1.2s42.6$0.01090/6
OpenAIgpt-5.6-luna@openai100.00.04s16.2$0.01360/6
MoonshotAIkimi-k2.5@moonshotai100.00.012s27.3$0.02040/6
Z.aiglm-4.7@z-ai100.00.038.5s8.3$0.02610/6
OpenAIgpt-5.6-terra@openaierrorno completion choices returned from OpenAI API100.00.02.5s22.8$0.02851/6
MoonshotAIkimi-k2.6@moonshotai100.00.020.4s15.0$0.03080/6
Claudeclaude-haiku-4.5@anthropic100.00.02.2s47.4$0.04300/6
Z.aiglm-5.2@z-ai100.00.05.7s19.1$0.05020/6
Grokgrok-4.5@xai100.00.02.5s45.2$0.07390/6
Geminigemini-3.6-flash@google-ai-studio100.00.03.7s153.9$0.07630/6
Z.aiglm-4.7@cerebras100.00.01.2s203.6$0.08870/6
Claudeclaude-sonnet-5@anthropic100.00.03.9s37.9$0.10900/6

Note

  • gpt-5.6-terra returned no completion choices on hold-not-block, its third such drop in three runs. Its score covers five cases.

Conclusion

Fourteen targets tie at 100, so cost decides: qwen3.7-flash at $0.00024 a task, or gemini-3.5-flash-lite at 1189ms where latency matters more.

Second corpus, second flat column. This one made the best name-match deliberately wrong and gave two cases opposite answers from the same eight card tools, and no target missed either. Single-turn selection does not separate these models, so the next signal has to come from argument conformance or from turns where a wrong call compounds.