第6章 工具增强型Agent的评测体系
本章你将学到:
- 为什么“最终输出正确”不等于“过程正确”
- 在评测体系中新增工具调用审计维度
- 构建包含工具调用链的黄金标准测试集
- 用Trae生成扩展后的评测Agent和批量评测脚本
- 跑通完整评测流程,基于数据做一次迭代优化
本章你将产出:一套能同时评估“输出质量”和“工具使用质量”的评测系统,以及一份包含工具调用审计的评测报告
全部章节:收录在专栏《AI应用工程化实战教程》之【智能体工具使用实战】
6.1 评测的新挑战
在第一部【AI智能体工程化实战】中,评测的逻辑很清晰:Agent输出一个JSON,你把它的valid字段和黄金标准的gt_label做对比。一致就对了,不一致就错了。评测Agent只看两样东西——业务Agent的输出和GT——然后给出match或不match。
现在情况变了。
你的数据分析助手Agent在一次任务中可能会经历这样的过程:
用户提问 → Agent调用 read_file → Agent调用 execute_python → Agent调用 write_file → Agent输出总结最终它生成了一份analysis_report.md,也输出了总结文字。你打开报告一看——数据正确,格式清晰,结论合理。看起来不错。
但你有想过这些问题吗:
- 它有没有在应该用
execute_python的时候,选择了自己“心算”? - 它有没有把
read_file的参数写错,导致读了错误的文件,只是恰好那个文件也有类似数据? - 它有没有调了三次工具但其实一次就够了(浪费API调用)?
- 它有没有在某个工具调用失败后,假装什么都没发生,继续编造结果?
最终输出正确,不代表过程正确。如果Agent第一次就读错了文件但恰好数据相似,如果它跳过了计算步骤直接编造了数字,你只看最终输出是发现不了的。
这就是工具增强型Agent评测面临的新挑战:你不仅要评“说了什么”,还要评“做了什么”。
6.2 工具调用审计维度
参照第一部L1/L2/L3三层指标体系的设计思路,我们在第二部的评测体系中新增一个工具调用审计模块。它在L2业务指标层面增加了一个全新的评估维度。
6.2.1 新增错误类型代码
在评测Agent的判定逻辑中,原有的错误类型(FP、FN、RE)仍然有效——它们评的是最终输出。但我们需要新增一组专门针对工具调用的错误代码:
| 错误代码 | 全称 | 含义 | 示例 |
|---|---|---|---|
| TW | Tool Wrong | 工具选择错误——应该用A工具却用了B,或者应该用工具却直接回答 | 需要计算平均值,Agent没有调execute_python,而是自己“估算”了一个数字 |
| PA | Parameter Error | 参数错误——工具选对了,但参数传错了 | 调用了read_file,但path写成了"score.csv"而不是"scores.csv" |
| EX | Execution Error | 工具执行异常——工具选对了,参数也对了,但执行失败,Agent没有正确处理 | 沙盒返回了超时错误,Agent却假装成功,继续编造后续结果 |
| TC | Tool Call Missing | 缺少必要的工具调用——GT预期应该调用的工具,Agent没有调用 | GT预期需要调execute_python进行计算,但Agent跳过了这一步 |
这四个代码和原有的OK、FP、FN、RE一起,构成了扩展后的错误分类体系。
6.2.2 审计的逻辑
工具调用审计的核心逻辑是:把Agent实际调用的工具序列,和GT中标注的“预期工具调用序列”做比对。
比对什么?
- 工具名称:Agent调用的工具是否在预期列表中?
- 调用顺序:工具的调用顺序是否合理?(这一步不强制完全一致,但如果顺序明显错误——比如先写文件再读文件——应该标记)
- 关键参数:对于决定性参数(如文件路径),是否与GT一致?
- 缺失调用:GT预期必须发生的工具调用,Agent是否跳过了?
- 多余调用:Agent是否调用了不需要的工具(浪费)?
一个完整的工具调用审计结果包含:
{"tool_audit":{"overall":"OK"/"TW"/"PA"/"EX"/"TC","expected_tools":["read_file","execute_python"],"actual_tools":["read_file","execute_python","write_file"],"match_details":[{"step":1,"expected":"read_file","actual":"read_file","match":true,"param_match":true},{"step":2,"expected":"execute_python","actual":"execute_python","match":true,"param_match":true}],"issues":[]}}6.3 构建含工具调用链的GT测试集
6.3.1 扩展GT结构
第一部的GT是一条简单的标签:"有效"或"无效"。
第二部的GT需要扩展为包含两部分:
- final_output:预期的最终输出(与第一部相同,用于评估输出质量)
- expected_tool_calls:预期的工具调用序列,每个调用包含工具名、关键参数、是否必须
一个完整的GT条目结构如下:
{"test_id":"T001","user_request":"请读取 scores.csv,计算高数平均分,保存报告为 高数分析.md","setup":{"files":{"scores.csv":"已存在于项目根目录"}},"expected_tool_calls":[{"tool_name":"read_file","params":{"path":"scores.csv"},"required":true,"note":"读取成绩数据"},{"tool_name":"execute_python","params_check":"code 参数中应包含 df['高数'].mean() 或类似的计算逻辑","required":true,"note":"计算高数平均分"},{"tool_name":"write_file","params":{"path":"高数分析.md"},"required":true,"note":"保存分析报告"}],"expected_final_output":{"should_contain":["高数平均分","高数分析.md"],"should_not_contain":["无法读取","没有数据"],"format":"自然语言总结"}}6.3.2 用Trae生成测试集
在Trae对话面板中输入:
在项目>6.3.3 审查并校准GT生成测试集后,打开data/test_cases.json,你需要人工审查至少3条关键的GT条目:
- 审查T001(正常场景):预期的工具调用顺序是否合理?有没有遗漏必要的调用?
- 审查文件不存在场景:Agent的预期行为是“处理错误,不崩溃”。GT中是否体现了这一点?
- 审查多文件读取场景:工具调用顺序是否可能有两种合理路径?如果是,GT不应该定死唯一路径。
一个重要的原则:GT中expected_tool_calls的required: true/false标记要慎重。如果某个工具调用确实不可或缺,标true;如果只是推荐但不是必须的,标false。过于严格的GT会导致评测失真——Agent用了另一种同样合理的方式却被扣分。
6.4 用Trae生成扩展版评测Agent
现在我们需要一个能同时评“输出”和“工具”的评测Agent。
6.4.1 评测Agent的系统提示词
在Trae对话面板中输入:
在项目>6.4.2 生成批量评测脚本在Trae对话面板中继续输入:
在项目>6.4.3 修改 agent.py 使其返回执行日志评测需要Agent的执行日志。我们需要修改agent.py中的run_agent函数,让它在返回最终回答的同时,也返回工具调用的完整记录。
在Trae对话面板中输入:
请修改 agent.py 中的 run_agent 函数。 ## 修改要求 1. 函数签名改为 run_agent(user_query: str) -> tuple[str, str] 返回:(最终回答文本, 执行日志字符串) 2. 在函数内部维护一个 log_lines 列表,记录每一步: - 用户请求 - 每一轮API调用:模型是否返回了 tool_calls - 每个工具调用:工具名、参数(JSON格式)、返回结果(前200字符) - 最终回答 3. 日志格式示例: [用户请求] 请读取 scores.csv... [第1轮] 模型调用工具: read_file({"path": "scores.csv"}) [工具返回] 学号,姓名,高数... [第2轮] 模型调用工具: execute_python({"code": "import pandas..."}) [工具返回] 72.3 [第3轮] 模型最终回答: 高数平均分为72.3分... 4. 将 log_lines 用换行符拼接为字符串,与最终回答一起返回 5. 同时更新脚本底部的测试入口,适配新的返回值格式
6.5 运行评测与分析
所有组件就绪。现在跑通完整的评测流程。
6.5.1 运行评测
在Trae终端中执行:
python run_evaluation.py
你会看到终端里逐个显示每个测试用例的执行过程和评测结果。运行完成后,打开evaluation_report.json。
6.5.2 解读评测报告
评测报告的summary部分类似这样:
{"summary":{"total":8,"avg_overall_score":78.5,"avg_output_score":85.0,"avg_tool_score":72.0,"error_distribution":{"OK":5,"TW":1,"PA":1,"EX":1,"TC":0}}}
重点关注avg_tool_score——它往往低于avg_output_score。这说明Agent的最终输出看起来还行,但工具使用过程存在问题。这正是只看最终输出发现不了的“水下冰山”。
查看error_distribution:
- TW(工具选择错误)最多:Agent在判断“该用什么工具”时有问题。需要优化系统提示词中工具使用的指引,或者优化工具描述让它更容易被正确选择。
- PA(参数错误)最多:Agent选了正确的工具,但参数传错了。检查工具描述中的
parameters定义——参数名是否清晰?description是否说明了参数格式? - EX(执行异常)最多:工具执行失败但Agent没正确处理。可能是沙盒拦截了某些操作,但Agent没有读取错误信息并调整。
- TC(缺少工具调用)最多:Agent跳过了必要的工具调用。可能是在系统提示词中没有强调“必须先读文件再分析”。
打开details列表,找到得分最低的那个测试用例。仔细阅读它的tool_audit.match_details和issues,理解Agent到底在哪个步骤出了问题。
6.6 基于评测数据做一次迭代优化
假设你的评测报告显示:T003(多文件对比分析场景)的tool_audit.error_type是PA,原因是Agent在读取第二个文件时,路径写成了"scores2.csv"但实际文件是"scores_2.csv"。
这个问题的根因可能是:Agent在第一次read_file拿到第一个文件内容后,没有仔细核对第二个文件的路径,而是凭“感觉”写了一个类似的文件名。
修改方向:在系统提示词中增加对文件路径的强调。
在Trae对话面板中输入:
请修改 agent.py 的系统提示词,在工具使用指引中增加一条: "在使用 read_file 工具时,务必使用用户提供的精确文件路径。如果需要读取多个文件,每读取一个文件前都要确认文件名。如果文件不存在,仔细检查路径拼写,修正后重试。"
修改完成后,重新运行评测:
python run_evaluation.py
对比两次evaluation_report.json中 PA 错误的数量变化。
用Git记录这次迭代:
gitaddagent.py evaluator.py run_evaluation.py data/ evaluation_report.jsongitcommit-m"v1.1: 扩展评测体系,增加工具调用审计。修改系统提示词修复PA问题,工具审计分从72提升至XX"
6.7 本章小结
- “最终输出正确”不等于“过程正确”。工具增强型Agent的评测必须同时评估输出质量和工具使用质量。
- 新增四种工具调用错误代码:TW(工具选择错误)、PA(参数错误)、EX(执行异常处理不当)、TC(缺少必要工具调用)。
- GT结构扩展:从单一标签变为
expected_tool_calls+expected_final_output。工具调用序列包含工具名、参数、是否必须。 - 评测Agent也升级了:从“比对最终输出”升级为“审计完整执行日志”。执行日志需要Agent主动记录每一步工具调用。
- 迭代优化依然是闭环:评测→归因→修改→再评测。与第一部的工程化方法论完全一致。
下一章是第二部能力跃迁的顶点——你将让Agent自己给自己造工具。当它发现现有工具箱缺少某个功能时,自动生成Python代码、保存为工具文件、注册到ToolManager、然后调用。
课后练习
- 打开
evaluation_report.json,找出tool_audit.error_type不是OK的测试用例。阅读它的issues和match_details,分析Agent到底在哪个环节出了问题。 - 如果你发现某个工具调用错误反复出现(比如总是PA),尝试定位根因——是工具描述不够清晰,还是系统提示词中的使用指引有歧义?修改后重新评测,观察指标变化。
- (进阶)在评测体系中增加一个效率指标:Agent实际使用的工具调用次数与GT中
required调用次数的比值。如果Agent调了5次工具但GT只需要3次,这个指标会反映“过度调用”问题。修改evaluator.py实现这个指标。 - (进阶思考)如果一个任务存在多种同样合理的工具调用路径(比如可以先计算再筛选,也可以先筛选再计算),评测体系应该如何避免“路径唯一性偏见”?写下你的设计思路。