How to Measure Tool-Calling Accuracy in AI Agents

Tool calling is where capable agents quietly break. An agent can reason well and still pick the wrong function, pass a malformed argument, or plow on after a tool returns an error. Because these failures look plausible, a single "did the task succeed" score hides them. Tool call accuracy — also written tool calling accuracy — is the measurement that surfaces them, and measuring it properly means scoring each part of the call separately instead of collapsing a whole trace into one number.

Quick answer: Tool call accuracy measures whether an agent picks the right tool, passes correct arguments, sequences calls correctly, and recovers from tool errors. Score it deterministically where possible — exact argument match, schema validation, type checks — and reserve an LLM judge for free-form fields. Measure selection, arguments, sequencing, and error-handling separately, because one pass/fail hides where it breaks.

What is tool call accuracy?

Tool call accuracy is not one number. It is a set of dimensions, each of which can fail independently:

Collapsing these into one pass/fail is the most common measurement mistake. Each dimension fails for a different reason and is fixed in a different place, so a single number tells you that the agent broke without telling you where — which is the only part you can act on.

Which failure modes actually matter?

The dangerous failures are the ones that look fine. A call to the correct tool with a subtly wrong argument. A correct first call that the agent never recovers from once the tool errors. An unnecessary call that burns latency and cost. Happy-path testing — where the tool always returns clean data and the request is well-formed — creates false confidence, because production is never that clean. Weight your cases toward the messy paths.

A worked example: one trace, four dimensions

Abstract dimensions are easy to nod along to and hard to implement. Here is a single request scored end to end, with the actual pass/fail logic for each dimension.

Request: "Refund my last order and email me the confirmation." Tools available: find_order(customer_id), refund_order(order_id, amount_cents, reason), send_email(to, template, vars).

The agent's trace:

1  find_order(customer_id="C-8871")
   → {"order_id": "O-4412", "total_cents": 4250, "placed": "2026-05-02"}

2  refund_order(order_id="O-4412", amount_cents=4250, reason="customer_request")
   → {"error": "refund_window_expired"}

3  send_email(to="c8871@example.com", template="refund_confirmation",
             vars={"amount": "€42.50"})
   → {"sent": true}

Scored dimension by dimension:

DimensionPass/fail logicThis trace
Selectionset(called_tools) == set(expected_tools), and no call outside the allow-list.Pass — all three tools were the right ones to reach for.
ArgumentsPer call: schema-valid, then value match after normalisation. All-or-nothing on side-effecting calls.Passorder_id, amount_cents, and reason all match the expected call exactly.
SequencingData-flow assertion: refund_order.order_id must equal the order_id returned by step 1, and no confirmation may precede a successful refund.Fail — step 1 → 2 flows correctly, but step 3 runs after a failed refund.
RecoveryAfter a tool returns an error, assert the next action is a retry with adjusted arguments, a fallback tool, or an explicit failure report to the user — and that the final response never claims success.Fail — the agent ignored refund_window_expired and confirmed a refund that never happened.

This is the point of splitting the dimensions. A single "did the task succeed" check reports one bit — failed — and sends you looking at the wrong thing, because two of the four dimensions were perfect. The agent picked the right tools and passed flawless arguments; it simply did not read the error. That is a prompt-and-control-flow fix, not a tool-schema fix, and only per-dimension scoring tells you so.

Note also what the trace would score if refund_order had succeeded: four passes, and a clean run. The dimensions that break are the ones you only see when a tool fails — which is why your case set has to make tools fail on purpose.

Deterministic checks vs. LLM judges — when to use which?

Prefer determinism. It is faster, cheaper, and reproducible:

Normalize before you compare, or determinism turns into false negatives. "NYC" and "New York City", or an ISO date and a spelled-out one, are the same argument in different surface forms — a naive exact-match fails the agent for choosing a different valid spelling of the right value. Canonicalize dates and known aliases first, then compare, so the check fails a genuine value error and not a harmless phrasing difference.

Taken dimension by dimension, most of the work is deterministic and only two edges genuinely need a judge:

DimensionDeterministic checkWhen a judge is warrantedDefault
Tool selectionSet equality against the expected tool set; assert no unexpected callOnly when several different tools are legitimately correct for the requestDeterministic
ArgumentsSchema validation, then normalised value match per argumentFree-form fields only (query, body) where several phrasings are rightDeterministic
SequencingData-flow assertions — the output of call N appears in the arguments of call N+1 — plus ordering constraints you can write downWhen many orderings are valid and you want the plan judged rather than one pathDeterministic wherever a partial order can be specified
Error recoveryAssert a state transition: a call followed the error, and the final response does not claim successJudging whether the explanation given to the user was actually adequateMixed — deterministic gate, judge for quality
Clarification vs. guessingAssert zero tool calls were made and the response is a questionJudging whether it asked the right questionDeterministic gate, judge for quality

The pattern holds across the table: determinism decides whether the behaviour was correct, and a judge only ever grades how well something free-form was expressed. If a judge is deciding correctness on a closed-set field, you have bought variance for no signal.

Only reach for an LLM-as-judge where a field is genuinely free-form and meaning matters more than string equality — for example, a natural-language query argument where several phrasings are equally correct. Even then, validate the judge periodically against human labels, because judge bias and drift quietly corrupt your numbers: a judge that rewards verbosity or favours whichever candidate it sees first will hand you a stable, precise, wrong score.

The split, by argument type:

Argument typeCheckWhy
Tool nameExact matchOne right answer; no interpretation needed.
Enum / booleanExact matchClosed set — a judge adds cost and variance for nothing.
Number, currencyExact match after unit normalisation1000 and 1,000.00 are one value; 1000 and 100 are a real failure.
Date, timeCanonicalise to ISO, then exact match"next Friday" resolves to a date; compare the resolution, not the phrasing.
ID, enum-like stringNormalised match against an alias table"NYC" / "New York City" is a spelling difference, not an error.
Free-form text (query, body)LLM judge, validatedSeveral phrasings are genuinely correct; string equality produces false failures.
Whole-call shapeSchema validation + call countCatches extra, missing, and malformed calls deterministically.

The rule underneath the table: use a judge only where the set of correct answers is open. Every closed-set field scored by a judge is cost and variance you bought for no additional signal.

What does argument-level scoring look like in practice?

"The agent called the right tool" is not a result you can act on. Score each argument separately, then decide how the parts roll up. Take a booking request — "Book a flight from Amsterdam to New York on 3 March for two people" — against book_flight(origin, destination, date, passengers):

CaseAgent's callArgument scoringVerdict
Exact("AMS", "JFK", "2026-03-03", 2)4/4 exactPass
Surface variant("Amsterdam", "New York", "2026-03-03", 2)4/4 after alias + ISO normalisationPass — normalise before comparing, or you fail a correct agent
Near-miss value("AMS", "JFK", "2026-03-04", 2)3/4 — date wrong by one dayFail — the dangerous case: schema-valid, plausible, wrong
Wrong type, right idea("AMS", "JFK", "2026-03-03", "two")3/4 — passengers fails type checkFail on schema validation alone
Hallucinated argument("AMS", "JFK", "2026-03-03", 2, seat="12A")4/4 correct, plus one inventedFail — assert the argument set, not just the ones you expected
Under-specified request"Book me a flight to New York"("AMS", "JFK", "2026-03-09", 1)origin, date, passengers all inventedFail — asking is the correct behaviour here

Two things fall out of this table. First, the near-miss is invisible to any pass/fail that only checks the tool name and schema validity — it is the failure mode most likely to reach production, and it is only caught by comparing argument values. Second, the last row is scored on the opposite polarity: the agent that confidently fills in a missing date scores worse than the one that asks.

How the per-argument scores roll up is a deliberate choice. All-or-nothing (every argument must match) is the right default for calls with side effects — booking, payment, writes — because a call that is 75% correct still books the wrong flight. Partial credit is more useful for tracking progress on read-only calls, where a 3/4 tells you the agent is close. Report both if you can: the strict rate gates the release, the partial rate tells you which argument is costing you.

Tool calling accuracy vs. task success rate

These get used interchangeably and they are not the same measurement. Task success rate is end-to-end: did the user get what they asked for, one bit per task. Tool calling accuracy is per-call: was each step of the path correct. One is the outcome, the other is the mechanism.

Task success rateTool call accuracy
UnitOne taskOne call, scored per dimension
AnswersDid it work?Which part broke?
Ground truthFinal state or outputExpected call — tool name plus arguments
Blind toWhy it failed; cost and latency of the pathWhether the user's goal was actually met
Best forProduct and release reportingDebugging, CI gating, regression triage

They come apart in both directions, which is why you need both:

The practical rule: report task success rate to the people deciding whether to ship, and tool call accuracy to the people fixing it. Gate CI on the per-dimension numbers, because those are the ones that localise a regression. If you only track task success, a regression tells you something broke last week and leaves you to find it by hand.

How do you build a golden set for tool calls?

Combine two sources. Mine real production traces for authentic cases and label them, then add synthetic edge cases to cover failure paths you haven't seen yet — ambiguous requests, missing parameters, tools that error, and near-miss arguments. Synthetic generation is fast but clusters around common patterns, so always review generated cases before they enter your official set.

How big should the set be? Big enough for the risk it carries. Volume is only meaningful when scored against a minimum that rises with the deployment's risk tier, which is why a high-risk pack with fifteen cases scores worse than a low-risk one with the same fifteen. Coverage of the failure paths beats raw count. And keep the set out of places it can leak: a tool-calling eval that ends up in public CI logs loses its value once agents are trained on it — see how to tell if your eval is contaminated.

How do you know your tool-calling eval actually works?

Before you trust an eval's verdicts on an agent you don't know, run it against agents whose quality you already know. This is mutation testing applied to the eval itself:

If the eval can't separate those three, it isn't measuring tool-calling — it's measuring something merely correlated with it, like response length. See the tool-calling correctness benchmark for this discriminating-power check run on a real reference panel, and what a reference-panel harness is for the method in depth.

How do you catch regressions in CI?

Treat tool-calling evals like unit tests. Every pull request that touches a prompt, a model version, or a tool schema triggers an eval run against the golden set, and a run that regresses past your threshold does not merge. Track the dimensions separately over time — a drop in error-recovery rate tells you something very different from a drop in tool selection.

CI is only half the picture, though. A golden set answers a closed question — does the agent still handle the cases we thought of? — and it cannot see the inputs you never imagined. Once the agent ships, pair the gate with a sensor: monitoring tool calls in production tracks selection distribution, argument validity, and unrecovered errors on live traffic, and feeds the failures it finds back into this golden set as new cases. It's also a different question from everything above: this section is about whether the agent still gets the decision right, not whether it holds up against a slow or flaky tool — see tool-calling accuracy vs reliability for the execution-time failures a clean golden set never exercises.

Related

FAQ

What is tool-calling accuracy?

It measures whether an agent selects the correct tool, passes valid arguments, sequences calls correctly, and recovers from tool errors — evaluated as separate dimensions rather than a single pass/fail.

How do you measure tool call accuracy?

Score each call against an expected call on four dimensions separately. Tool selection: set equality against the expected tool set, with no unexpected calls. Arguments: schema validation followed by a normalised value match per argument. Sequencing: assert that the output of one call flows into the arguments of the next, and that ordering constraints hold. Error recovery: after a tool returns an error, assert the agent retried, fell back, or reported the failure, and never claimed success. Keep the four scores separate — a single pass/fail tells you the agent broke without telling you where.

What is a good tool calling accuracy metric to report?

Report a strict per-dimension rate rather than one aggregate. The most useful set is tool selection accuracy, strict argument-match rate (all arguments correct, which is the number that gates a release on side-effecting calls), partial argument credit for read-only calls, and error-recovery rate. Pair them with task success rate for outcome reporting, but gate CI on the per-dimension numbers, because those localise a regression.

Should I use exact-match or an LLM judge for tool arguments?

Use deterministic checks (exact match, schema validation, type checks) wherever arguments are structured. Reserve an LLM judge only for free-form fields where meaning matters more than exact string equality.

How many test cases does a tool-calling eval need?

It scales with the risk of the deployment, not a fixed target. Test-case volume should be scored against a minimum that rises with the deployment's risk tier — on the order of ten cases for a low-risk internal helper, several times that for an agent that can move money or change production state. Volume alone is not the point: a small set that covers failure paths (tool errors, ambiguous requests, missing parameters) discriminates far better than a large set of happy-path cases.

How do you measure tool-call error recovery?

Make the tool return an error or an empty result, then score what the agent does next. Correct behavior is to retry with adjusted arguments, fall back to another tool, or tell the user it could not complete the task. The failure to catch is the agent that proceeds as though the call succeeded and fabricates a result from nothing.

What is the most common tool-calling failure mode?

Plausible-looking calls that break on edge cases: the right tool with a subtly wrong argument, or a correct call the agent never recovers from when the tool returns an error.

Can I run tool-calling evals in CI?

Yes. Treat them like unit tests: gate every pull request that touches a prompt, model version, or tool schema, and block merges that regress past your threshold.

How do I stop my tool-calling eval from going stale?

Keep the case set out of public CI logs and blog posts, rotate cases over time, and periodically perturbation-test it: reword the cases without changing the underlying task and confirm the eval still separates a good agent from a broken one. A pack whose verdicts flip on a harmless rewording was keyed to its own wording, not to the capability.

What's the difference between tool-calling correctness and function-calling accuracy?

Function-calling accuracy usually means the model emitted schema-valid JSON. Correctness is broader: whether that was the right tool for the request, whether the argument values are right (not just well-typed), and whether the agent should have asked a clarifying question instead of calling anything at all.

Should a tool-calling eval penalize an agent for asking a clarifying question?

Only when the request was unambiguous. On a genuinely under-specified request, asking is the correct behavior and should score full marks — an agent that confidently guesses arguments on an ambiguous request is exhibiting the exact failure the eval should catch, not rewarding.

Should argument scoring be all-or-nothing or partial credit?

Use all-or-nothing for calls with side effects — booking, payment, writes — because a call with three of four arguments right still books the wrong flight. Partial credit is more informative for read-only calls, where it tells you which argument is failing. Reporting both is ideal: the strict rate gates the release, the partial rate tells you where to fix.

Do you need production monitoring if you already have a tool-calling eval in CI?

Yes — they catch different failures. A CI eval only tests the cases you thought of, while production monitoring watches live traffic for tool-selection drift, argument validation failures, and unrecovered errors on inputs your golden set never contained. The monitor also supplies the highest-value new test cases to feed back into the eval.

Can you test tool-calling without executing the real tools?

Yes, and usually you should. Give the agent the tool schemas and score the call it chooses — tool name plus arguments — against the expected call, which keeps the eval deterministic and free of side effects. Execute real or simulated tools only when you also need to test how the agent handles the returned result.

← Back to guides