Skip to main content
skills 可以指示 agent 运行 shell 命令,也可以在 scripts/ 目录中打包可复用脚本。本指南会介绍一次性命令、自包含且自带依赖的脚本,以及如何为 agent 使用场景设计脚本接口。

一次性命令

如果现有包已经能满足你的需求,你可以直接在 SKILL.md 指令里引用它,而不一定要单独建立 scripts/ 目录。很多生态都提供了能在运行时自动解析依赖的工具。
uvx 会在隔离环境中运行 Python 包,并使用非常激进的缓存策略。它随 uv 一起提供。
uvx ruff@0.8.0 check .
uvx black@24.10.0 .
  • 不随 Python 一起提供,需要额外安装。
  • 很快。缓存策略很积极,因此重复运行几乎是瞬时的。
在 skills 中编写一次性命令时的建议:
  • 固定版本。 例如 npx eslint@9.0.0,这样命令在不同时间运行时行为一致。
  • 把前置条件写进 SKILL.md 例如“Requires Node.js 18+”,不要默认 agent 所在环境已经具备这些条件。对于运行时级别的要求,请使用 compatibility frontmatter 字段
  • 复杂命令移入脚本。 当你只是带几个 flag 调用一个工具时,一次性命令很适合;但如果命令已经复杂到第一次就不容易写对,那么放进经过测试的 scripts/ 脚本会更可靠。

SKILL.md 引用脚本

引用打包文件时,请使用 相对于 skill 目录根的相对路径。agent 会自动解析这些路径,不需要绝对路径。 SKILL.md 中列出有哪些脚本可用,这样 agent 才知道它们存在:
SKILL.md
## Available scripts

- **`scripts/validate.sh`** — Validates configuration files
- **`scripts/process.py`** — Processes input data
然后明确指示 agent 去运行它们:
SKILL.md
## Workflow

1. Run the validation script:
   ```bash
   bash scripts/validate.sh "$INPUT_FILE"
   ```

2. Process the results:
   ```bash
   python3 scripts/process.py --input results.json
   ```
这种相对路径约定同样适用于 references/*.md 这类辅助文件。代码块中的脚本执行路径始终是相对于 skill 目录根 的,因为 agent 会从那里执行命令。

自包含脚本

如果你需要可复用逻辑,可以在 scripts/ 中打包一个脚本,并让它以内联方式声明自身依赖。这样 agent 只用一条命令就能运行脚本,不需要额外的 manifest 文件,也不用提前执行安装步骤。 有几种语言都支持内联依赖声明:
PEP 723 定义了脚本内联元数据的标准格式。你可以在 # /// 标记之间用一个 TOML 代码块声明依赖:
scripts/extract.py
# /// script
# dependencies = [
#   "beautifulsoup4",
# ]
# ///

from bs4 import BeautifulSoup

html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
print(BeautifulSoup(html, "html.parser").select_one("p.info").get_text())
推荐使用 uv 运行:
uv run scripts/extract.py
uv run 会创建隔离环境、安装声明过的依赖,然后执行脚本。pipxpipx run scripts/extract.py)也支持 PEP 723。
  • PEP 508 规范固定版本,例如:"beautifulsoup4>=4.12,<5"
  • 使用 requires-python 约束 Python 版本。
  • 使用 uv lock --script 生成 lockfile,以获得完整可复现性。

为 agent 使用场景设计脚本

当 agent 运行你的脚本时,它会读取 stdout 和 stderr 来决定下一步怎么做。有几个设计选择会显著影响脚本对 agent 是否友好。

避免交互式提示

这是 agent 执行环境里的硬性要求。agent 工作在非交互式 shell 中,不能响应 TTY 提示、密码对话框或确认菜单。任何等待交互输入的脚本都会一直挂起。 应当通过命令行 flag、环境变量或 stdin 接收全部输入:
# Bad: hangs waiting for input
$ python scripts/deploy.py
Target environment: _

# Good: clear error with guidance
$ python scripts/deploy.py
Error: --env is required. Options: development, staging, production.
Usage: python scripts/deploy.py --env staging --tag v1.2.3

--help 记录用法

--help 输出是 agent 学习脚本接口的主要方式。请包含简短描述、可用 flag 和使用示例:
Usage: scripts/process.py [OPTIONS] INPUT_FILE

Process input data and produce a summary report.

Options:
  --format FORMAT    Output format: json, csv, table (default: json)
  --output FILE      Write output to FILE instead of stdout
  --verbose          Print progress to stderr

Examples:
  scripts/process.py data.csv
  scripts/process.py --format csv --output report.csv data.csv
保持简洁,因为这些输出会和 agent 正在处理的其他内容一起进入上下文窗口。

编写有帮助的错误消息

当 agent 拿到一个错误时,这条消息会直接影响它下一次尝试怎么改。一个含糊的 “Error: invalid input” 只会浪费一次轮次。更好的方式是:明确说出哪里错了、期望的是什么、下一步应该怎么试。
Error: --format must be one of: json, csv, table.
       Received: "xml"

使用结构化输出

优先使用结构化格式,例如 JSON、CSV、TSV,而不是自由文本。结构化格式既便于 agent 消费,也便于标准工具(jqcutawk)处理,因此更容易组成流水线。
# Whitespace-aligned — hard to parse programmatically
NAME          STATUS    CREATED
my-service    running   2025-01-15

# Delimited — unambiguous field boundaries
{"name": "my-service", "status": "running", "created": "2025-01-15"}
把数据和诊断信息分开: 结构化数据输出到 stdout,进度消息、警告和其他诊断信息输出到 stderr。这样 agent 既能拿到干净、可解析的数据输出,又能在需要时查看诊断信息。

更多考虑

  • 幂等性。 agent 可能会重试命令。“如果不存在则创建”通常比“创建并在重复时报错”更安全。
  • 输入约束。 遇到有歧义的输入时,不要猜,直接报一个清晰错误。尽量使用枚举值和封闭集合。
  • Dry-run 支持。 对于破坏性或有状态的操作,--dry-run 可以让 agent 先预览将要发生什么。
  • 有意义的退出码。 为不同失败类型使用不同退出码(例如未找到、参数非法、鉴权失败),并在 --help 输出中记录这些退出码的含义,让 agent 知道该如何解释它们。
  • 安全默认值。 需要破坏性操作时,要考虑是否应该要求显式确认 flag(例如 --confirm--force)或其他与风险级别相匹配的保护措施。
  • 可预测的输出规模。 许多 agent 运行环境会在工具输出超过阈值时自动截断(例如 10 到 30K 字符),这可能导致关键内容丢失。如果你的脚本可能输出很多内容,默认就应该返回摘要或合理限制,并支持像 --offset 这样的 flag,让 agent 可以按需请求更多内容。另一种做法是:如果输出很大且不适合分页,就要求 agent 显式传入 --output,指定输出文件,或传 - 来明确表示要输出到 stdout。