引言

很多人第一次写 Agent 工具时,会把它理解成“把一段提示词保存起来”。这当然有用,但很快会遇到三个问题:任务稍微复杂一点,提示词就变成长文;流程涉及脚本、检查清单、外部工具时,模型不知道什么时候该读取什么;最后即使 Agent 给出结果,也很难判断它是不是真的完成了任务。

addyosmani/agent-skills 是 Addy Osmani 开源的一套面向 AI coding agent 的工程技能库。项目把软件研发过程拆成 DEFINE → PLAN → BUILD → VERIFY → REVIEW → SHIP 等阶段,并提供 20 个左右的 Skill、多个专家 Persona、slash command、检查清单和会话 Hook,用来约束 Agent 在需求澄清、任务拆解、增量实现、测试验证、代码审查和发布前检查中的行为。

这个项目给了一个更工程化的答案:把复杂任务拆成可触发、可执行、可验证、可复用的 Agent Skill。它不是知识库,也不是提示词合集,而是一套面向 AI coding agent 的工作流系统:用 Skill 描述“怎么做”,用 Command 触发“什么时候做”,用 Persona 提供“由谁从哪个视角做”,再用 Reference、Script、Hook 和验证清单控制上下文成本与执行质量。

本文会基于对该项目的分析,总结一套可复用的方法。读完后,你应该能把自己的复杂任务,比如发布前检查、日志排障、技术博客翻译、PR 审查、运维变更评审,构建成一个真正可用的 Agent 工具。

先明确:Agent 工具不是提示词,而是工程系统

Anthropic 的 Agent Skills 文档把 Skill 定义为一种模块化能力:一个目录里包含 SKILL.md、元数据、可选脚本和资源,Claude 会在相关任务出现时自动加载。它的关键是 progressive disclosure,也就是分层加载:

  1. Metadata:启动时只加载 namedescription,用于发现 Skill。
  2. Instructions:任务匹配时再加载 SKILL.md 正文。
  3. Resources / Scripts:只有被指令引用时才读取参考资料或执行脚本。

Cursor 的 Agent Skills 文档也采用类似结构:Skill 是可移植、可版本化、可包含脚本和模板的能力包,可以放在项目级或用户级目录中。MCP 则从另一侧解决“外部系统能力”问题:服务器暴露工具,客户端通过 tools/list 发现工具,再通过 tools/call 调用,并且官方文档强调敏感操作应保留 human-in-the-loop。

这意味着一个可靠的 Agent 工具至少要回答四个问题:

  • 什么时候触发:哪些用户意图、文件类型、工作阶段应该启用它?
  • 如何执行:步骤是什么?哪些步骤不能跳?
  • 如何取上下文:哪些内容常驻,哪些按需加载,哪些交给脚本或 MCP?
  • 如何证明完成:用什么输出、测试、检查清单或运行结果作为证据?

agent-skills 项目之所以值得学习,是因为它把这些问题都变成了文件结构和工作流约束。

从 agent-skills 项目抽象出的三层模型

分析这个项目时,最有价值的不是某一个 Skill 的内容,而是它的分层方式。

第一层:Skill 负责“怎么做”

项目里的每个 Skill 都是一个独立目录,例如:

1
2
3
4
5
6
7
8
9
skills/
spec-driven-development/
SKILL.md
planning-and-task-breakdown/
SKILL.md
test-driven-development/
SKILL.md
shipping-and-launch/
SKILL.md

docs/skill-anatomy.md 给出的标准结构很清楚:SKILL.md 需要包含 frontmatter、触发条件、工作流、常见借口、红旗信号和验证清单。这里的重点是 Process over knowledge:Skill 不是百科资料,而是 Agent 必须照着执行的 SOP。

一个好的 Skill 描述应该类似这样:

1
2
3
4
---
name: pre-ship-guardian
description: Guides agents through production launch readiness checks. Use when the user asks to ship, release, deploy, or validate a change before production.
---

description 里必须同时写清楚“做什么”和“什么时候用”。如果把完整流程塞进 description,Agent 可能只读摘要就开始执行,反而绕过 SKILL.md 正文。

第二层:Command 负责“什么时候启动一组流程”

agent-skills 项目把软件研发生命周期拆成 DEFINE → PLAN → BUILD → VERIFY → REVIEW → SHIP,并提供 /spec/plan/build/test/review/ship 等命令。命令本身不是复杂逻辑,而是一个薄入口,用来告诉 Agent:现在进入哪个阶段,应调用哪个 Skill 或哪些 Persona。

例如 /ship 的思路是:发布前不是让一个 Agent 从头看到尾,而是并行启动多个专家视角:

  • code-reviewer 检查正确性、可读性、架构、安全、性能。
  • security-auditor 检查 OWASP、密钥、鉴权、依赖风险。
  • test-engineer 检查测试覆盖、边界场景、并发和错误路径。

主 Agent 最后只做合并,输出 GONO-GO 决策和 rollback plan。

第三层:Persona 负责“由谁看”

Persona 不是流程本身,而是审查视角。agent-skillsagents/ 目录里有 code-reviewertest-engineersecurity-auditor 等角色。它们适合做同一个产物的不同视角评估。

这里有一个关键约束:Persona 不要互相调用。如果让 code-reviewer 再去调用 security-auditor,就会引入多次摘要、上下文丢失和成本不透明。更好的做法是由用户或命令做编排,多个 Persona 独立产出报告,主 Agent 负责合并。

一套可复用的工程方法

把复杂任务做成 Agent 工具,可以按下面六步走。

第一步:定义任务边界

先不要写 SKILL.md。先写清楚这个任务的边界:

  • 输入是什么:代码 diff、日志文件、网页 URL、需求文档、会议记录,还是自然语言目标?
  • 输出是什么:报告、补丁、部署决策、翻译稿、命令执行结果,还是结构化 JSON?
  • 什么时候应该触发:用户说了哪些关键词,或当前处于哪个工作阶段?
  • 什么时候不应该触发:任务太小、信息不足、需要人工决策、涉及高风险操作?
  • 完成证据是什么:测试通过、报告字段完整、截图、日志、CI 状态,还是人工确认?

这一步决定 Agent 工具是否可控。没有边界的 Agent 工具,会变成“什么都想做,什么都做不稳”。

第二步:把流程拆成阶段,而不是堆成长提示词

复杂任务通常不是一个 prompt 能解决的,而是一个有依赖关系的流程。agent-skills 用生命周期拆分工程任务,我们也可以用类似方式拆自己的任务:

1
Clarify -> Collect Context -> Execute -> Verify -> Report -> Next Action

以发布前检查为例:

1
Identify change -> Collect diff -> Run focused checks -> Merge findings -> Decide GO/NO-GO -> Produce rollback plan

如果步骤之间存在依赖,就保留顺序流程;如果步骤彼此独立,就考虑并行 fan-out。不要为了“自动化”强行让一个总控 Agent 从头代理所有阶段,因为每多一次摘要,都会增加信息丢失和误判风险。

第三步:设计上下文加载策略

上下文窗口不是仓库,也不是网盘,它是预算。生产级 Agent 工具要主动控制什么进入上下文:

  • 常驻内容:只放触发条件、核心规则和必须执行的步骤。
  • 按需资料:长检查清单、模板、规范放到 references/
  • 确定性逻辑:文件扫描、格式校验、报告生成放到 scripts/
  • 外部系统:数据库、CI、工单、监控平台通过 MCP 或已有工具连接。

这就是 context engineering 的核心:让 Agent 在正确时间看到正确信息,而不是把所有材料一次性塞给模型。

第四步:把脚本当作“确定性执行层”

Agent 擅长理解意图、做判断和组织输出,但不适合反复执行机械且可验证的逻辑。以下内容更适合放脚本:

  • 收集 git diff、最近 commit、变更文件列表。
  • 校验 Markdown frontmatter、JSON schema、YAML 格式。
  • 生成报告骨架。
  • 调用内部 API 并输出结构化 JSON。
  • 检查文件大小、依赖版本、敏感关键字。

脚本的原则是:输入输出清晰、副作用可预期、结果机器可读。脚本越可靠,Agent 就越少靠猜。

第五步:把验证写进 Skill,而不是写进愿望

agent-skills 里一个很重要的模式是 VerificationCommon Rationalizations。这不是装饰,而是在对抗 Agent 常见的跳步行为。

比如不要只写:

1
Make sure the release is safe.

而要写成:

1
2
3
4
5
6
## Verification
Before producing a GO decision, confirm:
- [ ] The change summary was collected from git, not inferred from memory.
- [ ] Test status is included, even if no tests were run.
- [ ] Security-sensitive files are explicitly called out.
- [ ] Rollback steps are concrete enough for another engineer to execute.

如果结果不能被验证,就不要宣称完成。

第六步:选择正确的编排模式

references/orchestration-patterns.md 里最值得借鉴的是编排选择。可以简化成四种常用模式:

  1. 直接调用:一个任务、一个视角、一个产物。成本最低。
  2. 单 Skill / 单命令封装:同一个流程反复出现,就封装成 Skill 或 slash command。
  3. 并行 fan-out + merge:多个独立视角同时分析同一输入,主 Agent 合并结果。
  4. 用户驱动的顺序流水线:步骤之间有依赖,且每一步都需要人工判断。

判断是否需要并行 fan-out,可以问四个问题:

  • 子任务是否真正独立?
  • 每个视角是否能产生不同类型的发现?
  • 合并结果是否足够小,能放回主上下文?
  • 节省的等待时间或提升的质量,是否值得额外成本?

如果答案不明确,就从单 Skill 开始,不要一上来设计“Agent 团队”。

具体例子:构建一个发布前检查 Agent 工具

下面用一个完整例子演示如何把复杂任务做成 Agent 工具。场景是:每次准备发布前,让 Agent 自动收集变更信息、执行发布前检查、输出 GO / NO-GO 决策和 rollback plan。

这个例子可以放在支持 Agent Skills 的工具中,例如:

1
2
3
4
5
6
.cursor/skills/pre-ship-guardian/
SKILL.md
references/
launch-checklist.md
scripts/
collect_change_summary.py

如果你使用 Claude Code,也可以放到:

1
2
3
4
5
6
.claude/skills/pre-ship-guardian/
SKILL.md
references/
launch-checklist.md
scripts/
collect_change_summary.py

1. 编写 SKILL.md

SKILL.md 是 Agent 工具的入口。它不要写成“发布知识百科”,而要写成一个可执行流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
---
name: pre-ship-guardian
description: Guides agents through production launch readiness checks. Use when the user asks to ship, release, deploy, publish, or validate a change before production.
---

# Pre-Ship Guardian

## Overview

Run a production launch readiness check and produce a GO or NO-GO decision with evidence and rollback steps.

## When to Use

Use this skill when:
- The user asks whether a change is ready to ship.
- The user mentions release, deploy, production, publish, or launch.
- A PR or branch needs final validation before merge.

Do not use this skill when:
- The user only wants a local code review.
- There is no concrete change artifact to inspect.
- The user is still defining requirements.

## Required Inputs

Before starting, identify:
- Repository path
- Target branch or commit range
- Release environment
- Known risk areas

If any required input is missing, ask a clarifying question before running checks.

## Workflow

1. Collect the change summary by running `scripts/collect_change_summary.py`.
2. Read `references/launch-checklist.md`.
3. Inspect changed files and classify risk:
- Auth or authorization
- Data migration
- Configuration or secrets
- Payment or billing
- Infrastructure
- User-facing UI
4. Check test evidence:
- Unit tests
- Integration tests
- E2E tests
- Manual verification
5. Check operational readiness:
- Feature flag
- Metrics
- Logs
- Alerts
- Rollback command
6. Produce the final decision.

## Output Format

## Ship Decision: GO | NO-GO

### Evidence
- Change summary:
- Tests:
- Security:
- Operations:

### Blockers
- <blocking issue or "None">

### Recommended Fixes
- <non-blocking issue or "None">

### Rollback Plan
- Trigger:
- Command:
- Owner:
- Expected recovery time:

### Confidence
- High | Medium | Low

## Common Rationalizations

| Rationalization | Reality |
|---|---|
| "The diff is small, so we can skip checks." | Small config or auth changes can still break production. |
| "Tests probably passed earlier." | Use explicit evidence, not memory. |
| "Rollback is obvious." | A rollback plan must be executable by another engineer. |

## Verification

Before returning a GO decision, confirm:
- [ ] Change summary came from the repository, not from memory.
- [ ] Test status is explicitly stated.
- [ ] Security-sensitive files are listed when present.
- [ ] Rollback plan has a concrete trigger and command.
- [ ] Any missing evidence lowers confidence or changes the decision to NO-GO.

这个 Skill 已经包含了触发条件、排除条件、工作流、输出格式、常见跳步借口和验证清单。Agent 看到这个文件后,不需要再猜“发布前检查应该做什么”。

2. 把长检查清单放到 references

发布检查清单可能很长,不适合全部放在 SKILL.md。可以放到 references/launch-checklist.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Launch Checklist

## Code Quality

- The change is scoped to the stated release goal.
- The implementation avoids unrelated refactoring.
- Error handling is explicit for external calls.

## Security

- No secrets are committed.
- User input is validated at trust boundaries.
- Authorization checks are covered by tests.
- Dependency changes are reviewed.

## Data

- Migrations are backward compatible.
- Rollback behavior is documented.
- Data deletion or mutation paths have safeguards.

## Operations

- Metrics exist for the changed path.
- Logs include enough context for debugging.
- Alerts cover critical failure modes.
- Feature flags have owners and cleanup plans.

## Rollback

- Rollback command is documented.
- Rollback trigger is measurable.
- Recovery time expectation is stated.

这样做的好处是:只有当发布检查 Skill 被触发时,Agent 才需要读取这份清单;平时不会占用上下文。

3. 用脚本收集变更事实

让模型“根据记忆总结 diff”是不可靠的。更好的方式是用脚本收集事实,并输出 JSON。

scripts/collect_change_summary.py 可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env python3
import json
import subprocess
from pathlib import Path


def run(command):
result = subprocess.run(
command,
capture_output=True,
text=True,
check=False,
)
return {
"command": command,
"exit_code": result.returncode,
"stdout": result.stdout.strip(),
"stderr": result.stderr.strip(),
}


def main():
root = Path.cwd()
payload = {
"repository": str(root),
"status": run(["git", "status", "--short"]),
"recent_commits": run(["git", "log", "--oneline", "-5"]),
"changed_files": run(["git", "diff", "--name-only", "HEAD"]),
"staged_files": run(["git", "diff", "--cached", "--name-only"]),
}
print(json.dumps(payload, ensure_ascii=False, indent=2))


if __name__ == "__main__":
main()

脚本只负责收集事实,不做复杂判断。判断交给 Agent,事实来源交给脚本,这就是清晰的职责边界。

4. 触发方式

在支持自动发现 Skill 的工具中,用户可以直接说:

1
请检查当前分支是否可以发布到生产环境。

或者显式指定:

1
使用 pre-ship-guardian 检查当前变更,给出 GO/NO-GO 和 rollback plan。

如果你使用支持 slash command 的环境,也可以再做一个薄命令,把触发词固化下来。命令只负责入口,不要把所有检查逻辑复制进去:

1
2
3
4
Invoke the pre-ship-guardian skill.

Run the production launch readiness workflow for the current repository.
Return a GO or NO-GO decision with evidence, blockers, recommended fixes, and a rollback plan.

这和 agent-skills 项目里的 /ship 思路一致:命令是入口,Skill 是流程,Persona 或子 Agent 是独立视角。

5. 什么时候升级成并行 fan-out

上面的 pre-ship-guardian 是单 Skill。对于小团队或低风险项目,这已经够用。等你发现发布前检查经常需要多个独立视角,再升级成并行 fan-out:

1
2
3
4
                     -> code-reviewer -> code quality report
pre-ship command -> -> security-auditor -> security report
-> test-engineer -> test coverage report
main agent merges reports -> GO/NO-GO + rollback plan

升级前要确认三件事:

  1. 三个视角能独立工作,不需要互相等待。
  2. 每个视角的输出有明显差异,不是在重复同一份检查。
  3. 主 Agent 能在剩余上下文里合并报告,而不是再次丢失细节。

如果这些条件不满足,就继续使用单 Skill。Agent 工具的目标是稳定完成任务,不是展示复杂架构。

Skill、Script、MCP、Subagent 怎么选

构建 Agent 工具时,经常会混淆这些能力。可以按职责区分:

  • Skill:封装流程、规则、触发条件和验证要求。
  • Reference:保存长文档、检查清单、领域规则、模板。
  • Script:执行确定性逻辑,输出结构化结果。
  • MCP Tool:连接外部系统,例如 CI、监控、工单、数据库。
  • Subagent / Persona:提供独立上下文和独立视角。

举例来说,发布前检查里:

  • 用 Skill 定义发布检查流程。
  • 用 Reference 保存发布清单和安全清单。
  • 用 Script 收集 git 事实和生成报告骨架。
  • 用 MCP 查询 CI、监控或工单状态。
  • 用 Subagent 并行做代码、安全、测试三类审查。

不要把所有东西都塞进 Skill 正文。Skill 应该像一个任务说明书,告诉 Agent 什么时候读资料、什么时候运行脚本、什么时候调用外部工具、什么时候停止并要求人工确认。

常见坑

坑一:把 Skill 写成知识库

如果 SKILL.md 里充满背景知识,但没有明确步骤、输入输出和验证,Agent 读完也不知道该做什么。知识可以放到 references/SKILL.md 应该保留可执行流程。

坑二:description 写得太像完整流程

description 是发现入口,不是执行说明。它应该简短说明“做什么”和“何时用”。如果把完整步骤写进去,Agent 可能不会再读取正文。

坑三:没有验证闭环

“检查完成”“看起来没问题”“应该可以发布”都不是证据。可靠的 Skill 必须要求可验证输出,例如测试结果、命令输出、报告字段、截图或人工确认。

坑四:脚本副作用不清晰

脚本应该默认只读,除非 Skill 明确说明它会修改文件、提交代码或调用外部系统。涉及生产、密钥、网络请求、数据删除的脚本必须有人工确认。

坑五:过度编排

不是所有任务都需要多个 Agent。单视角、单产物、低风险任务,直接调用一个 Skill 最便宜也最稳定。并行 fan-out 只适合子任务独立、视角差异明显、合并成本可控的场景。

坑六:把上下文窗口当存储

长文档、完整日志、历史对话、工具 schema 全塞进去,会让模型注意力分散。更好的做法是分层加载、按需读取、脚本输出摘要、外部系统保留原始数据。

落地清单

当你准备把一个具体任务做成 Agent 工具时,可以按这个清单执行:

  1. 写一句话目标:这个工具帮助 Agent 完成什么任务?
  2. 写触发条件:用户说什么、看到什么文件、处于什么阶段时启用?
  3. 写排除条件:哪些情况不要用,必须先问人?
  4. 定义输入输出:输入来自哪里,最终交付什么?
  5. 拆流程:按阶段写成编号步骤。
  6. 分配上下文:核心流程进 SKILL.md,长资料进 references/,确定性逻辑进 scripts/
  7. 写验证清单:没有证据时不能宣称完成。
  8. 写常见借口:把 Agent 容易跳过的步骤提前拦住。
  9. 先从单 Skill 运行,再根据重复性和独立性决定是否加入 Command、Persona 或并行 fan-out。
  10. 像维护代码一样维护 Skill:版本管理、评审、测试、审计脚本。

总结

agent-skills 项目可以提炼出一个核心原则:好的 Agent 工具不是更长的提示词,而是把人的工程流程转化为可执行、可验证、可组合的系统

真正可复用的方法包括:

  • description 做精准触发,用 SKILL.md 写可执行流程。
  • references/scripts/ 控制上下文成本。
  • 用验证清单和常见借口约束 Agent 不跳步。
  • 用 Command 和 Persona 做轻量编排,而不是堆叠多层代理。
  • 用 MCP 接外部系统,但保留安全边界和人工确认。

如果你要为自己的团队构建 Agent 工具,建议先选一个高频、边界清晰、有明确交付物的任务开始。例如“发布前检查”“PR 审查”“日志排障”“技术文章翻译”。先做成一个单 Skill,跑通后再逐步加入脚本、参考资料、外部工具和并行审查。这样构建出来的 Agent 能力,才会从一次性的聊天技巧,变成团队可持续复用的工程资产。

参考资料

本文由 AI 辅助生成,如有错误或建议,欢迎指出。