Skills 把领域流程、工具使用规范和操作步骤封装成可复用指令,让 Agent 能处理退款审核、故障排查、合规检查等专门任务。但一个回答读起来流畅,并不代表 Agent 选对了 Skill,更不代表它遵循了 Skill 中规定的步骤。
因此,评测 Skill 型 Agent 时,不能只给最终答案打分。更可靠的做法是同时观察 Skill 选择、指令遵循和任务结果,再分别用 Strands Evals 做开发期回归,用 Amazon Bedrock AgentCore Evaluations 承接集成或运行环境中的评测。
把一次 Agent 执行拆成三层证据
一条测试用例至少应回答三个问题:
- 选对了吗?
- 用户要求退款,Agent 是否选择了
refund_review,而不是通用客服 Skill? -
遇到信息不足时,它是否选择了澄清流程,而不是强行执行?
-
照着做了吗?
- Skill 要求先校验订单、再检查退款期限,Agent 是否按顺序执行?
- Skill 明确要求不得猜测客户身份,Agent 是否请求补充信息?
-
某个工具失败后,Agent 是否执行了规定的降级或终止步骤?
-
结果可用吗?
- 最终结论是否正确?
- 回答是否包含必要字段、引用或风险提示?
- 是否泄露敏感信息,或者执行了超出权限的操作?
这三层不能互相替代。例如,Agent 可能误选 Skill,却凭语言模型常识碰巧答对;也可能选对 Skill,但跳过身份校验。两种情况都不应被“答案看起来不错”掩盖。
建议为每次运行保留结构化轨迹,而不是只保存聊天文本:
{
"case_id": "refund-within-window",
"events": [
{"type": "skill_selected", "skill": "refund_review"},
{"type": "instruction_completed", "name": "verify_order"},
{"type": "instruction_completed", "name": "check_refund_window"}
],
"answer": "订单已验证,并且仍在退款期限内,可以进入退款流程。"
}
这里的事件名是一种可实践的观测约定,不代表 Strands 或 AgentCore 的固定字段。实际接入时,应把框架产生的 trace、hook 或回调记录映射为类似的统一格式。
一个可以直接运行的本地评测器
下面的最小示例只使用 Python 标准库。它演示如何分别计算 Skill 选择、步骤遵循和最终答案三个分数。你可以先用它确定评测数据结构,再将同样的断言迁移到 Strands Evals 或 AgentCore Evaluations。
将以下内容保存为 evaluate_skills.py:
from dataclasses import dataclass
from typing import List, Dict, Any
@dataclass
class EvalCase:
case_id: str
expected_skill: str
required_steps: List[str]
answer_keywords: List[str]
CASES = [
EvalCase(
case_id="refund-within-window",
expected_skill="refund_review",
required_steps=["verify_order", "check_refund_window"],
answer_keywords=["退款期限", "可以"],
),
EvalCase(
case_id="missing-order-id",
expected_skill="refund_review",
required_steps=["request_order_id"],
answer_keywords=["订单号"],
),
]
# 示例中的运行记录。生产环境应替换为 Agent 的真实 trace 和回答。
RUNS: Dict[str, Dict[str, Any]] = {
"refund-within-window": {
"events": [
{"type": "skill_selected", "skill": "refund_review"},
{"type": "instruction_completed", "name": "verify_order"},
{"type": "instruction_completed", "name": "check_refund_window"},
],
"answer": "订单已验证,仍在退款期限内,可以进入退款流程。",
},
"missing-order-id": {
"events": [
{"type": "skill_selected", "skill": "refund_review"},
{"type": "instruction_completed", "name": "request_order_id"},
],
"answer": "请提供订单号,以便继续审核。",
},
}
def evaluate(case: EvalCase, run: Dict[str, Any]) -> Dict[str, Any]:
events = run.get("events", [])
selected = [
event.get("skill")
for event in events
if event.get("type") == "skill_selected"
]
completed = {
event.get("name")
for event in events
if event.get("type") == "instruction_completed"
}
selection_score = float(case.expected_skill in selected)
missing_steps = [s for s in case.required_steps if s not in completed]
adherence_score = (
1.0
if not case.required_steps
else (len(case.required_steps) - len(missing_steps)) / len(case.required_steps)
)
answer = run.get("answer", "")
missing_keywords = [k for k in case.answer_keywords if k not in answer]
answer_score = (
1.0
if not case.answer_keywords
else (len(case.answer_keywords) - len(missing_keywords))
/ len(case.answer_keywords)
)
# Skill 选错通常比措辞不佳更严重,因此给予更高权重。
total = 0.45 * selection_score + 0.35 * adherence_score + 0.20 * answer_score
return {
"case_id": case.case_id,
"selection_score": round(selection_score, 2),
"adherence_score": round(adherence_score, 2),
"answer_score": round(answer_score, 2),
"total_score": round(total, 2),
"missing_steps": missing_steps,
"missing_keywords": missing_keywords,
"passed": total >= 0.85 and selection_score == 1.0,
}
if __name__ == "__main__":
failed = False
for case in CASES:
result = evaluate(case, RUNS[case.case_id])
print(result)
failed = failed or not result["passed"]
raise SystemExit(1 if failed else 0)
运行:
python evaluate_skills.py
这个脚本还适合直接放进 CI:只要有用例失败,进程就返回非零退出码。
python evaluate_skills.py
if [ $? -ne 0 ]; then
echo "Skill evaluation failed"
exit 1
fi
真实项目中不要只依赖关键词。关键词适合验证格式和必要信息,但无法可靠判断语义正确性。更稳妥的组合是:
- 对 Skill ID、工具名、步骤顺序使用确定性断言;
- 对答案质量使用人工标注、规则或模型评审;
- 对安全边界使用明确的禁止事件和失败条件;
- 对延迟、token 和工具调用次数单独设置预算。
Strands Evals 与 AgentCore Evaluations 如何分工
可以把两者放在同一条评测流水线的不同位置,而不是让它们互相替代。
开发和提交阶段,使用 Strands Evals 组织固定数据集与回归断言。每当 Skill 文本、路由规则、模型版本或工具定义变化时,重新运行用例,及时发现:
- Skill 路由准确率下降;
- 必需步骤被遗漏;
- 步骤顺序发生变化;
- 正常请求被不必要地拒绝;
- 对抗性输入绕过了 Skill 的限制。
集成和运行阶段,可以用 Amazon Bedrock AgentCore Evaluations 对接 Agent 执行环境中的样本与轨迹,关注更接近真实流量的表现,例如不同输入分布下的成功率、指令遵循率以及版本间差异。
由于来源摘要没有给出具体 SDK 方法和配置字段,下面是一份用于设计评测集的示意 YAML,而不是某个版本可直接提交的官方配置。接入时需要按当前 Strands Evals 或 AgentCore Evaluations 的接口做字段映射:
suite: refund-skill-regression
metrics:
- skill_selection
- instruction_adherence
- answer_quality
cases:
- id: refund-within-window
input: "订单 A-100 已签收 3 天,我想退款。"
expected_skill: refund_review
required_steps:
- verify_order
- check_refund_window
forbidden_events:
- issue_refund_before_verification
- id: missing-order-id
input: "帮我退款,但我没有提供订单号。"
expected_skill: refund_review
required_steps:
- request_order_id
forbidden_events:
- fabricate_order_id
- issue_refund
关键不是配置文件长什么样,而是让本地测试、托管评测和线上观测共享同一套语义:相同的 Skill 名称、步骤名称、失败原因和版本标识。否则,同一个问题在三套系统中会得到三种无法对齐的统计结果。
上线前应守住的几条线
评测集不要只收集“标准答案题”。至少加入以下样本:
- 两个 Skill 都可能匹配的模糊请求;
- 应该拒绝或转人工的越权请求;
- 缺少关键参数的请求;
- 工具超时、返回空值或部分失败的情况;
- 用户试图覆盖 Skill 指令的提示注入;
- 换一种说法但意图不变的同义输入。
发布门槛也不宜只看平均总分。一个平均 95 分的版本,仍可能在高风险场景中连续跳过身份校验。更合理的门槛包括:
- 高风险用例的 Skill 选择必须全部正确;
- 禁止事件出现次数必须为零;
- 必需步骤遵循率不得低于设定阈值;
- 新版本不能显著差于当前生产基线;
- 失败记录必须能够回溯到 Skill、模型、提示词和工具版本。
Skill 让 Agent 的行为更容易复用,也让评测从“答案是否顺眼”推进到“过程是否符合制度”。只有把选择、执行和结果拆开测量,团队才能知道问题究竟出在路由、Skill 指令、模型推理,还是外部工具上,并据此做出可验证的改进。