NVIDIA Developer ★ 90 8 min

How to Evaluate AI Agents From Tool Calls to Task Completion

Agentic AI / Generative AIAI AgentLLM BenchmarkingNemotron

🔗 https://developer.nvidia.com/blog/how-to-evaluate-ai-agents-from-tool-calls-to-task-completion/

📌 評估 AI Agent,不能只看單次呼叫像不像

TL;DR:NVIDIA 部落格梳理 agent 評測如何從單次呼叫進化到整個任務成敗。

一個 agent 呼叫的 API 語法完全正確、參數也填對,但如果背後該做的檢查或更新被跳過了,這個任務仍然算失敗——這正是為什麼「評估 agent」和「評估模型輸出」是兩件完全不同的事。

🤔 從單一輸出到多步驟任務,舊評測框架不夠用

早期的評測工具是為靜態任務設計的:給一個輸入,看一個輸出字串對不對。第一個與模型無關、開源的評測框架,把模型和評測協定分離開來,但 agent 打破了這個假設,它要在多步驟任務中呼叫工具、處理錯誤、觀察結果,單一輸出字串已經不夠用了。Berkeley Function-Calling Leaderboard(BFCL)因此出現,用來評估單輪與多輪情境下的函式選擇與參數準確度。但 BFCL 只評估「個別呼叫」本身,文章舉例:一次語法正確的 issue_refund 呼叫,如果背後該執行的檢查或更新被跳過了,任務照樣算失敗。呼叫正確是必要條件,但不是充分條件。

🧩 完整的 agent 評測,需要一個真正會執行的環境

要完整評估 agent,需要一個能執行每次工具呼叫、追蹤跨步驟狀態、並在事後讀取世界狀態來判斷任務是否完成的執行環境。在這個環境之上疊了兩層評分:Step-level(過程評分)問「在當下的狀態下,這次呼叫是否有效、相關且有用?」;End-to-end/E2E(結果評分)忽略過程,只看最終狀態,例如退款有沒有真的入帳、工單有沒有正確分派。Step-level 能告訴你鏈條在哪裡斷掉,適合除錯或決定微調的施力點;E2E 則會把「第一步就失敗」和「第九步才失敗」都算成同一種「任務失敗」,但 E2E 才是使用者真正體驗到的結果,所以多數上線評測會把 E2E 當作放行的關卡,同時保留 step-level 追蹤在底層供除錯用。這兩種分數其實是同一份東西的兩種讀法:trace(追蹤紀錄),是單次嘗試的完整有序紀錄,包含使用者訊息、每一步,以及嘗試結束時的環境狀態;process scoring 是對每一列打分,E2E scoring 則是對最終狀態打分。

一個工具呼叫的評測,依序評估三件事:要不要用工具、選對工具、把參數填對。該用工具卻直接給答案,跟該給答案卻硬要呼叫工具,都一樣算失敗;成本與延遲則疊加在上面,由呼叫的冗長程度與執行時間決定。

每一次評測執行都依循一個固定的層級關係:Benchmark → Trial → Task → Turn → Step。Trial 是在固定設定下,對整個任務集合跑一次獨立的嘗試;Task 是一個可以獨立打分的問題實例,有自己的 task ID;Turn 是一次「訊息進、agent 回覆出」之間的交換邊界,中間發生的一切都屬於這個 turn;Step 則是 turn 裡的一個原子動作,可能是一次工具/指令呼叫,也可能是非工具的輸出,例如一份計畫或最終回覆。Step 通常就是一次工具呼叫,往上所有的分數都是從這些 step 一路捲上去的。

📊 該追蹤的指標,收斂成三個軸:準確度、冗長度、成本

指標公式軸向為什麼重要
Task success ratesuccessful_tasks / tasks準確度放行的關鍵門檻,環境是否真的到達目標狀態
Consistency3-5 次 trial 間成功率的區間準確度90%/74% 的分佈不等於 84%,該報範圍而非單一點估計
Tool-call precisioncorrect_calls / calls_issued準確度幻覺呼叫、多餘呼叫會在這裡現形,而非在成功率上
Argument accuracycorrect_args / calls_with_right_tool準確度區分「呼叫錯 API」和「呼叫對 API 但填錯參數」
Steps per successsteps / successful_tasks冗長度任務真的完成時,軌跡跑了多長
Cost per successspend / successful_tasks成本token 與 GPU 秒數只有換算成每個成功任務才有意義

這些指標要成對看:只看成功率不看一致性,等於把一個隨機系統的表現當成單一個點估計,一個時而 90%、時而 74% 的模型,比一個穩定維持在 84% 的模型風險更高;只看 tool-call precision 不看 argument accuracy,會把填錯參數的失敗藏起來。同一個任務下,不同模型之間差異最大的軸往往是 step 數(四步 vs 十五步),不過在 Terminal-Bench 2.0 這類套件上,每個 turn 的 step 數本身也會變動,所以哪個軸差異最大要看具體 benchmark。平行工具呼叫可以縮短 step 數與延遲,但不會減少呼叫次數,一個 turn 裡同時打出四個工具呼叫,仍然是四次呼叫。重點是要依序捲上分數,不能把 step 數拿去平均後當成 benchmark 總分。

💡 看懂一份評測結果,要分辨三個維度

兩個都號稱在測「工具呼叫」的 benchmark,數字可能完全不能比。差異通常來自三個維度:任務複雜度(單輪單一工具,還是需要規劃、錯誤恢復與狀態管理的多輪任務);狀態性(環境是否隨每個動作更新,有狀態的 benchmark 才能揭露漂移、上下文遺失、狀態損壞這些靜態測試看不到的問題);評測方法(可執行驗證,例如資料庫是否真的更新、測試是否真的通過,是黃金標準;參考答案式評測需要人工維護一份標註答案集;LLM-as-a-Judge 可以填補沒有可執行檢查的空白,但分數在對照一批人工評分驗證之前,都只能算是暫定值)。文章也提到,污染問題已經不只是訓練資料外洩,還包括即時的變形,例如會上網搜尋的 agent 在評測過程中直接查到答案,或是 Hugging Face 上的資料集很快被重新爬進預訓練語料庫;不可被爬取的私有領域評測,天生就不會有這個問題。

📊 一筆真實 trace:SWE-bench Verified 上的除錯過程

文章附上一段來自 SWE-bench Verified(真實 GitHub issue、可執行測試驗證)的公開 trace,任務 ID 為 pytest-dev__pytest-5262(trial .2,turn 0 到 4)。使用者/使用者模擬器的指令是「在 /testbed 中完成必要修改,滿足 issue 的要求」,issue 內容是 _pytest.capture.EncodedFile 從底層 buffer 回報的 mode 是 rb+(binary),但它的 write() 只接受 str,導致像 youtube-dl 這類外部程式碼寫入 bytes 時會崩潰。這次評測用的是 OpenHands agent harness,暴露的工具有 terminal、file_editor、task_tracker、finish,平行工具呼叫關閉(每個 turn 只能呼叫一次工具),repo 狀態會跨 turn 保留(是真實的檔案系統與 git,不是模擬)。

trace 顯示:step 1(turn 0)用 terminal 的 find 指令定位到 capture.py,判定為 valid;step 2(turn 1)用 file_editor 檢視整個檔案(超過 400 行),判定為 redundant,因為先用 grep 縮小範圍會更精準;step 3(turn 2)用 terminal 的 grep 搜尋 EncodedFile,判定為 recovered,修正了 step 2 的沒效率;step 4(turn 3-4)用 file_editor 檢視特定行數範圍,準確定位到問題根因(getattr 沒有過濾就直接把 mode 委派給底層 binary buffer),判定為 valid。

🎯 實務啟示

如果你正在為自家的 agent 選 benchmark 或搭評測管線,這篇文章給出一個清楚的檢查清單:光報一個「成功率」數字沒有意義,要同時看一致性區間;區分呼叫是否正確跟參數是否正確,才能定位問題在哪;用 E2E 當作上線的放行門檻,但保留 step-level trace 做除錯;比較不同 benchmark 的分數之前,先確認彼此的任務複雜度、狀態性與驗證方法是否對得上,否則就是在比較兩個不同的東西。

🔗 來源

#AIAgents #LLMEval #ToolCalling #BenchmarkDesign #NVIDIA #AgenticAI #SWEBench #MachineLearning #MLOps #EvalMetrics

原始資料 NVIDIA Developer · 收集於 2026-09-22
來源原標題
How to Evaluate AI Agents From Tool Calls to Task Completion
作者
Elizabeth Goodman
原始標籤
Agentic AI / Generative AI · AI Agent · LLM Benchmarking · Nemotron
原始連結
https://developer.nvidia.com/blog/how-to-evaluate-ai-agents-from-tool-calls-to-task-completion/

摘要原文

When you ship an AI agent , the key question is whether it can execute a chain of work across dozens of sequential tool calls against a live environment, and recover when a step fails. Scoring whether the model sounds right tells you almost nothing about whether the work finished . That gap is why agent evaluation has had to evolve from scoring a single function call to scoring an entire task, with tool calling as the connective tissue underneath. This post traces that arc and explains why nearly every serious agent benchmark now rests on tool use. Why isn’t standard LLM benchmarking enough? The original harnesses were built for static tasks. The first model-agnostic, open-source harness decoupled the model from the evaluation protocol. Agents broke this assumption. Operating across multi-step tasks, an agent calls tools, handles errors, and observes results over many steps, making a single output string insufficient. The Berkeley Function-Calling Leaderboard (BFCL) emerged to evaluate function selection and argument accuracy across single- and multi-turn scenarios. However, BFCL only evaluates individual calls —a valid issue_refund call still fails if underlying checks or updates were skipped. Call accuracy is necessary, but not sufficient. From scoring calls to scoring the environment Full agentic evaluation now requires a full execution environment : one that executes each tool call, tracks state across steps, and reads the world afterward to decide whether the work got done. Two scoring layers sit on top of it: Step-level ( process scoring ) asks was this call valid, relevant, and useful given the state at that point? End-to-end (E2E, or outcome scoring ) ignores the path and checks only the final state: did the refund post, did the ticket route correctly? Step-level tells you where the chain breaks, which is what you want when debugging or targeting fine-tuning effort; E2E collapses a failure on step one and a failure on step nine into the same “task failed.” E2E is what your users actually experience, which is why most production evals gate the release on it and keep step-level tracing underneath for debugging. Those two scores are two readings of one object: the trace . A trace is the ordered log of a single attempt: the user message, each step, and the environment state when the attempt stops. Process scoring grades the rows. E2E scoring grades the final state. What a benchmark run measures A tool-calling benchmark scores three things in order: deciding to use a tool, selecting the right one, and populating its arguments. A model that reaches for a tool when a direct answer would fail as surely as one that skips a tool it needed. Cost and latency ride on top, set by the call’s verbosity and runtime. Every run rolls up through a fixed hierarchy: Benchmark → Trial → Task → Turn → Step : A trial is one independent pass over the whole task set under a fixed configuration. A task is one independently scorable problem instance, identified by a task ID. A turn is one exchange boundary: a message in, the agent’s reply out, everything between belongs to that turn. A step is one atomic action inside a turn — a tool/command invocation, or a non-tool emission like a plan or the final message. Figure 1. Visualization of turn vs step in agent workflows A step is usually a tool call , and every score above it rolls up from those steps. The metrics worth tracking collapse onto three axes: accuracy , verbosity , cost (see Table 1, below). Metric Formula Axis Why it exists Task success rate successful_tasks / tasks Accuracy The release gate. Did the environment reach the goal state? Consistency range of success rate across 3–5 trials Accuracy A 90% / 74% split isn’t 84%. Report 82–88%, not a point estimate. Tool-call precision correct_calls / calls_issued Accuracy Hallucinated names and extra calls surface here, not in success rate. Argument accuracy correct_args / calls_with_right_tool Accuracy Separates “wrong API” from “right API, filled wrong.” Steps per success steps / successful_tasks Verbosity How long the trajectory runs when the task actually finishes. Cost per success spend / successful_tasks Cost The economic unit. Tokens and GPU-seconds only matter per successful task. Table 1. Core evaluation metrics, grouped by axis (accuracy, verbosity, cost) The pairings matter: success rate without consistency is a point estimate on a stochastic system (a model that hits 90% then 74% is a worse bet than one holding 84%); tool-call precision without argument accuracy hides slot-filling failures. Step count is often the axis that varies most across models on the same task — four steps versus fifteen — though on suites like Terminal-Bench 2.0 steps-per-turn varies too, so which axis moves most is benchmark-dependent. Parallel tool calling cuts step count and latency, but not call count: a one-step turn firing four tools still issued four calls. Roll up in order; don’t average steps and call it a benchmark score. How to read an evaluation Two benchmarks can both claim to test tool calling and produce numbers that aren’t comparable. Three dimensions explain most of the gap: Task complexity — single-turn with one tool, or multi-turn requiring planning, error recovery, and state management? A single-call benchmark won’t tell you whether a model collapses on step eight of fifteen. Statefulness — does the environment update on each action? Stateful benchmarks surface drift, context loss, and corrupted state that static ones miss. Methodology — executable verification (did the DB update, did tests pass) is the gold standard. Reference-based evaluation needs an annotated answer set someone must maintain. LLM-as-a-Judge fills the gap where no executable check exists, but treats its scores as provisional until validated against human ratings on a sample. Contamination now extends beyond training data leaks to live variants: web-searching agents retrieving answer keys during evaluation, and datasets on Hugging Face quickly re-scraped into pretraining corpora. Private domain evals solve this by being unable to scrape. Table 2, below, is a public trace from a real benchmark run using step-level and E2E scoring, where the suite rather than an artificial ticket provides the tools, user, and completion criteria. Suite: SWE-bench Verified (real GitHub issues, executable test verification) Task ID: pytest-dev__pytest-5262 (trial .2, turns 0–4) User / user-simulator opening: “Implement the necessary changes to the repository ( /testbed ) so that the requirements specified in the issue are satisfied” — the issue: _pytest.capture.EncodedFile reports mode rb+ (binary) from its underlying buffer, but its write() only accepts str , so external code that checks .mode (e.g. youtube-dl ) crashes when it writes bytes . Harness notes (tools exposed, max steps, parallel calling on/off): OpenHands agent harness; tools exposed: terminal , file_editor , task_tracker , finish ; parallel tool-calling off (one tool call per turn); repo state persists turn to turn (real filesystem + git, not a mock). Step Turn Call Environment observation Verdict Why (valid / useful / redundant / recovered / policy) 1 0 terminal(find /testbed -name "capture.py") Returns /testbed/src/_pytest/capture.py valid Locates the file named in the issue before editing anything 2 1 file_editor(view, capture.py) Dumps the full file (400+ lines) redundant File is large; grepping for the class first would have been more targeted 3 2 terminal(grep -n "EncodedFile" capture.py) Returns 422: return EncodedFile(...) / 425: class EncodedFile(object): recovered Corrects step 2’s inefficiency by narrowing straight to the relevant lines 4 3–4 file_editor(view, view_range=[420,450]/[450,470]) Shows EncodedFile.__init__ / __getattr__ , revealing it delegates .mode straight from the binary-mode buffer valid Pinpoints the exact root cause (unfiltered __getattr__ delegation) that step 5+ fixes Table 2.

由 claude-code/sonnet 自動生成