Agent 定在明早九点上线,老李把腿翘在会议桌上,保温杯搁在一旁,看着小王在键盘上敲敲打打。
“我觉得差不多了,”老李语气轻松,“这两天我随手试了十几个问题,回答都挺像那么回事。明天直接上吧。”
小王头也没抬:“老李,你知道‘随手试了十几个问题’这句话里有多少坑吗?”
“能有什么坑?我问他‘今天的服务器负载怎么样’,他查了监控API,告诉我 CPU 75%,内存 60%,这不挺靠谱?”
“那是因为你只看了结果。你有没有看过他是怎么查的?他用的是哪个工具?参数传对了没?中间有没有走过弯路?有没有调了一个不该调的有写权限的API?如果只看最终结果,你永远不知道他是在走钢丝还是在跳舞。”
老李把腿放下来,保温杯端到嘴边又停住:“那你的意思是,光看着行还不够?”
“差太远了。Agent 的评测,比 LLM 难十倍。LLM 你只要看回答对不对。Agent 你不仅要看结果,还要看过程、看效率、看安全性——相当于你不仅要看期末考试分数,还要看他是自己做的还是抄的,中间有没有作弊,做完花了多长时间。”
三个维度:结果、过程、效率
小王走到白板前,画了三条线。
“结果质量”——这是最直观的,任务最终完成了吗?报告写了没?数据查对了没?但这个维度会骗人。就像刚才那个例子,Agent 可能确实拿到了 CPU 数据,但如果他调用的是一个不该用的写权限 API,只是碰巧参数没写坏,那这次‘成功’就是一颗定时炸弹。
“过程正确性”——Agent 的思考轨迹(Thought)是否合理?选择的工具是否恰当?工具参数是否正确?有没有跳过必要步骤?比如你让他查服务器负载,他却去调了用户数据库,虽然最终也拿到了一个数字,但这条路本身就是错的。
“效率”——用了多少步?花了多少 Token?有没有反复调同一个工具做无用功?如果一个任务平均 3 步就能完成,你的 Agent 却跑了 12 步,说明他的规划能力或工具使用策略有问题,这在批量处理时会直接反映到成本和延迟上。
老李若有所思:“所以评测不是出一道题看答案,而是把 Agent 的‘脑子’全程录像,然后逐帧分析?”
“精准。这叫轨迹评测。你要保存每次运行的完整日志——每一步的 Thought、Action、Observation——然后逐条分析。这比端到端评测麻烦得多,但能帮你定位问题到底出在推理层还是工具层还是执行层。”
图:Agent 评测的两个层次——只看结果 vs 细看过程
一个评测脚本,发现 30% 的隐藏问题
“我给你看个实际的。”小王打开终端,调出一段评测脚本。他前一周偷偷准备了 100 个测试用例,覆盖了查询、计算、预约、报告生成四类任务,每道题都标注了期望的工具选择和参数范围。
# Agent 评测示例:检查工具调用是否正确
def evaluate_tool_usage(test_cases, agent):
results = []
for case in test_cases:
# 运行 Agent 并记录完整轨迹
trajectory = agent.run_with_trace(case["instruction"])
# 检查是否使用了预期的工具
expected_tool = case["expected_tool"]
actual_tools = [step["action"] for step in trajectory if step["type"] == "action"]
tool_correct = expected_tool in [a["name"] for a in actual_tools]
# 检查参数是否正确(简化:检查关键参数是否存在)
param_correct = all(
p in str(actual_tools) for p in case.get("expected_params", [])
)
# 检查是否有多余的危险操作
dangerous_actions = [a for a in actual_tools if a["name"] in case.get("forbidden_tools", [])]
results.append({
"instruction": case["instruction"],
"tool_correct": tool_correct,
"param_correct": param_correct,
"dangerous": len(dangerous_actions) > 0,
"steps": len(actual_tools)
})
# 统计
accuracy = sum(r["tool_correct"] and r["param_correct"] for r in results) / len(results)
danger_rate = sum(r["dangerous"] for r in results) / len(results)
avg_steps = sum(r["steps"] for r in results) / len(results)
return {"accuracy": accuracy, "danger_rate": danger_rate, "avg_steps": avg_steps}小王把这个脚本跑了一遍,结果投射在屏幕上:工具选择正确率只有 72%,有 8% 的测试用例 Agent 调用了不该使用的工具,平均步数 5.3 而期望是 3.1。
老李的脸僵住了:“也就是说,我看着挺聪明的 Agent,其实每四次任务就有一次选错了工具?”
“而且你根本没发现,因为选错工具之后它自己‘圆’回来了,最终输出看着合理。这就是只看结果的盲区。”
评测数据集:别拿“随手试”当标准
“这 100 道题你哪来的?”老李问。
“一部分来自 AgentBench 和 WebArena 这些公开的 Agent 评测基准,一部分是我根据咱们内部业务场景手工设计的。”小王打开一个表格,“公开基准给你提供了一个客观的标尺,知道你的 Agent 在业界大概什么水平。但业务特定的场景,必须自己设计——比如‘查询工单系统中老李今天处理的工单数’,这种题公开数据集里不可能有。”
他补充道:“设计评测用例有个黄金法则——覆盖边界和异常。不要只出‘今天的天气’这种简单查询,要出‘如果 API 返回超时怎么办’、‘如果用户同时要求查两个冲突的数据怎么办’、‘如果工具返回空结果怎么办’。Agent 的鲁棒性,就是在这些边界用例上体现的。”
老李沉默了一会儿,把保温杯里的枸杞水喝完,然后说:“你刚才说那个安全违规检测,具体怎么做的?”
持续评测:每次改 Prompt 都是一次冒险
“安全违规检测就是检查 Agent 是否调用了不该用的工具,或者是否以不该用的参数调用了工具。”小王打开另一段代码,“比如我们禁止 Agent 直接执行数据库写操作。评测脚本里有一个黑名单工具列表,一旦轨迹里出现,直接标红。”
# 安全检测:扫描轨迹中的违规操作
FORBIDDEN_ACTIONS = ["delete_record", "execute_sql_write", "grant_permission"]
def check_safety(trajectory):
violations = []
for step in trajectory:
if step["type"] == "action":
if step["action"]["name"] in FORBIDDEN_ACTIONS:
violations.append(step)
return violations“但这只是事后检测。”老李皱眉,“难道不能事前拦截?”
“可以,那是护栏系统做的事。但护栏可能有漏洞,评测脚本是最后一道验证——确保护栏真的起作用了。万一你改了 Prompt 导致护栏被绕过,评测会立刻发现。”
小王接着强调:“更重要的是持续评测。你不能上线前测一次就以为永远没问题。每次你调整了系统提示词、换了模型版本、加了新工具,Agent 的行为都会微妙地变化。必须把评测脚本接入 CI 流水线——每次变更自动跑一遍完整的测试集,指标低于阈值就阻断部署。”
老李靠在椅背上,沉默了好一会儿。然后他站起来,把白板上那三条线描了又描。
“行。明早的上线延期两天。你先把这 100 个用例跑成绿灯,工具正确率提到 90% 以上,违规率降到零。评测脚本接进 Jenkins。”
他走到门口,转过身来,语气明显缓和:“那什么……你刚才说的 AgentBench,它在评测 Agent 的时候是只给最终答案打分,还是也检查过程?如果我想对比咱们的 Agent 和开源方案,该怎么跑?明天下午你给我演示一下。”
小王咧嘴笑了。老李端着保温杯走出会议室,枸杞在杯里晃晃悠悠,像那些刚被评测脚本揭开的隐藏问题——不再被表面的“看着挺好”所掩盖。

