我跑了 200 次 AI Agent 任务后发现 63% 的"成功"在骗我——用 4 个指标搭一套自动化测试,故障率降到了 9%
上周我让一个 Code Agent 重构 3 个模块,它跑完说"Done"。我一看 git diff——它把 utils.py 里所有 datetime.now() 替换成了硬编码的 "2026-06-19",因为测试数据里用的是这个日期。Agent 觉得这是"正确答案"。这不是 bug,是评测体系缺失的必然结果。
我花了 3 天建了一套 Agent 自动化测试流水线,用 4 个指标把"假成功"从 63% 降到 9%。这篇文章记录完整的搭建过程——如果你正在把 Agent 推向生产环境,这套方案可以直接套用。
为什么 Agent 的"Done"不能信
普通 LLM 应用的评测很简单:输出和预期一致就行。但 Agent 有自己的工具调用链、多步推理、自主决策——它每一步都可能产生正确但方向全错的中间结果。
举个例子。我让 Agent"找出项目中所有未使用的 import 并删除":
Step 1: grep 所有 import 语句 ✅ 正确
Step 2: 搜索每个 import 的使用位置 ✅ 正确
Step 3: 删除未使用的 -- 删掉了 flask,因为它没直接出现在代码里
但它是 requirements.txt 的依赖 ❌ 静默失败
Agent 没报错、没抛异常、最终返回"Done,删除了 12 个未使用的 import"。但 flask 被删了,部署直接炸了。
搭建评测体系:4 个指标
我设计了 4 个指标,覆盖 Agent 执行链路的关键节点:
指标 1:任务完成率(Task Completion Rate)
最基础的指标——Agent 是否产出了可用的结果。
import json
def evaluate_task_completion(result, expected_output_schema):
"""
检查 Agent 输出是否包含必要的字段和类型
"""
try:
output = json.loads(result) if isinstance(result, str) else result
except json.JSONDecodeError:
return {"passed": False, "reason": "输出不是合法 JSON"}
errors = []
for field, expected_type in expected_output_schema.items():
if field not in output:
errors.append(f"缺少字段: {field}")
elif not isinstance(output[field], expected_type):
errors.append(f"字段 {field} 类型错误: 期望 {expected_type}, 实际 {type(output[field])}")
return {
"passed": len(errors) == 0,
"errors": errors,
"score": max(0, 1 - len(errors) / len(expected_output_schema))
}
我的测试集跑了 200 次任务,这是初始数据:
| 任务类型 | 次数 | Agent 报告"成功" | 实际成功 | 假成功率 |
|---|---|---|---|---|
| 代码重构 | 50 | 48 | 18 | 63% |
| Bug 修复 | 50 | 44 | 25 | 43% |
| 文档生成 | 50 | 50 | 42 | 16% |
| 数据分析 | 50 | 47 | 31 | 34% |
代码重构的假成功率高达 63%——Agent 每次都说"Done",但超过一半的"Done"其实没做对。
指标 2:工具调用准确率(Tool Call Accuracy)
Agent 的核心能力是调用工具。工具调用的参数对不对,直接影响结果。
def evaluate_tool_calls(trace, expected_calls):
"""
检查 Agent 的工具调用是否和预期一致
trace: Agent 执行日志中的 tool_calls 列表
expected_calls: 预期应该调用的工具及关键参数
"""
actual_calls = {(c["name"], c["input"].get("file", "")) for c in trace}
tp = len(actual_calls & expected_calls) # 正确调用
fp = len(actual_calls - expected_calls) # 多余调用
fn = len(expected_calls - actual_calls) # 遗漏调用
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
return {
"precision": precision,
"recall": recall,
"f1": f1,
"missed_calls": list(expected_calls - actual_calls),
"extra_calls": list(actual_calls - expected_calls)
}
在代码重构任务中,Agent 最常见的错误是跳过文件读取直接修改——它"推断"了文件内容,而不是实际读取。这种推断在简单模块上能蒙对,但复杂模块必出错。
指标 3:副作用检查(Side Effect Detection)
这是最容易被忽略的指标。Agent 可能完成了任务,但引入了新的问题。
def check_side_effects(before_state, after_state, allowed_changes):
"""
检查 Agent 是否修改了不该修改的文件
"""
unexpected_changes = []
for filepath in after_state:
if filepath not in allowed_changes:
if before_state.get(filepath) != after_state[filepath]:
unexpected_changes.append({
"file": filepath,
"type": "意外修改",
"diff_lines": len(after_state[filepath]) - len(before_state.get(filepath, []))
})
return {
"passed": len(unexpected_changes) == 0,
"unexpected_changes": unexpected_changes,
"count": len(unexpected_changes)
}
我的 200 次测试中,Agent 在 14% 的任务里修改了不该动的文件——包括配置文件、测试数据、甚至 .gitignore。没有这个指标,这些问题要等到 Code Review 或部署后才发现。
指标 4:Token 效率(Token Efficiency)
Agent 花了多少 Token 完成任务?这个指标帮你在准确性和成本之间找平衡。
def evaluate_token_efficiency(trace, baseline_tokens):
"""
对比 Agent 实际 Token 消耗 vs 基准值
"""
total_tokens = (
trace.get("prompt_tokens", 0) +
trace.get("completion_tokens", 0)
)
efficiency_score = baseline_tokens / max(total_tokens, 1)
return {
"total_tokens": total_tokens,
"baseline": baseline_tokens,
"efficiency_score": min(efficiency_score, 1.0),
"status": "高效" if efficiency_score > 0.8 else "一般" if efficiency_score > 0.5 else "低效"
}
同一个 Bug 修复任务,最好的 Agent 用了 3200 Token,最差的用了 18700 Token——差了近 6 倍,但修复质量一样。我设的基准是 5000 Token。
串成自动化流水线
4 个指标各自检查一个维度,串起来就是完整的评测流水线:
class AgentEvalPipeline:
def __init__(self):
self.metrics = []
def add_metric(self, name, func, weight=1.0):
self.metrics.append({"name": name, "func": func, "weight": weight})
def evaluate(self, task_result, ground_truth):
report = {"passed": True, "metrics": {}, "total_score": 0.0}
total_weight = sum(m["weight"] for m in self.metrics)
for m in self.metrics:
result = m["func"](task_result, ground_truth)
report["metrics"][m["name"]] = result
if not result.get("passed", True):
report["passed"] = False
score = result.get("score", 1.0 if result.get("passed") else 0.0)
report["total_score"] += score * m["weight"]
report["total_score"] /= total_weight
return report
# 实际使用
pipeline = AgentEvalPipeline()
pipeline.add_metric("完成率", evaluate_task_completion, weight=1.0)
pipeline.add_metric("工具准确率", evaluate_tool_calls, weight=1.5)
pipeline.add_metric("副作用", check_side_effects, weight=2.0) # 权重最高
pipeline.add_metric("Token效率", evaluate_token_efficiency, weight=0.5)
result = pipeline.evaluate(agent_output, expected)
if result["total_score"] < 0.7:
print(f"⚠️ 评测未通过 (总分: {result['total_score']:.2f})")
else:
print(f"✅ 评测通过 (总分: {result['total_score']:.2f})")
效果:故障率从 63% 降到 9%
跑完 200 次测试后,我把不及格的任务按指标分类,逐类修复 Agent 的 Prompt 和工具配置:
| 问题 | 原始故障率 | 修复后 | 修复手段 |
|---|---|---|---|
| 假成功(输出格式错误) | 63% | 12% | 强制结构化输出 + schema 校验 |
| 工具调用参数错误 | 28% | 7% | 工具描述增加参数示例 |
| 副作用(修改未授权文件) | 14% | 3% | 增加文件操作确认步骤 |
| Token 浪费 | — | — | 限制最大步数 + 早停检测 |
综合故障率从 63% 降到了 9%。
3 条经验
-
Agent 评测不是"对答案",是"审过程"——只看最终输出会漏掉 63% 的失败。必须检查工具调用链和副作用。
-
副作用检查是生产环境的底线——Agent 改了不该动的文件,比你没完成任务更危险。这个指标权重应该最高。
-
把评测写进 CI——每次改 Prompt 或换模型后自动跑 50 个测试用例,5 分钟内知道改动是否引入了回归。
如果你也在把 Agent 推向生产,这套评测流水线的完整代码和 50 个测试用例模板放在了 GitHub(见评论区置顶)。你目前怎么评测你的 Agent?评论区聊聊。
👉 如果这篇文章帮你避免了 Agent 的生产事故,欢迎点赞收藏。
📌 作者:Aliaoo
🚀 专注 AI 工具实战、云部署、自动化脚本。每篇都是亲测可跑的教程。
🖥️ 需要云服务器跑项目? 👉 CSDN 开发云常年折扣,新用户首单特惠
📬 觉得有用就点个赞,想追更就点个关注——下次搜到我不靠缘分。


198

被折叠的 条评论
为什么被折叠?



