Claude Skills 的官方标准明确支持在 Skill 里打包可执行脚本。但大多数人只写 Markdown,忽略了 scripts/ 目录。这篇文章结合 agentskills.io 的官方规范和我在量化投资领域的实践,聊聊为什么脚本比 Markdown 重要得多。
官方怎么说
agentskills.io 是 Claude Code Skills 遵循的开放标准。它的 Using Scripts 页面明确定义了三种在 Skill 里使用代码的方式。
方式一:一次性命令
如果现成的工具就能干活,直接在 SKILL.md 里写命令,不需要 scripts/ 目录。官方推荐的运行方式包括 uvx、npx、bunx、deno run、go run 等,都支持自动解析依赖。
比如你的 Skill 需要格式化代码,直接写 uvx ruff@0.8.0 check . 就行。关键是要锁定版本号,确保每次行为一致。
方式二:打包脚本到 scripts/ 目录
当逻辑变复杂,就该把代码放进 scripts/ 文件夹。在 SKILL.md 里列出可用脚本,然后在工作流程中引用:
## 可用脚本- scripts/validate.sh — 校验配置文件- scripts/process.py — 处理输入数据## 工作流程1. 运行校验:bash scripts/validate.sh \"$INPUT_FILE\"2. 处理结果:python3 scripts/process.py --input results.json
路径用相对路径,Agent 会自动解析。
方式三:自包含脚本(依赖内联声明)
这是最优雅的方式。Python 的 PEP 723 允许你在脚本文件内部声明依赖:
# /// script# dependencies = [\"beautifulsoup4\"]# ///from bs4 import BeautifulSoup# ... 你的逻辑
用 uv run scripts/extract.py 执行,它会自动创建隔离环境、安装依赖、运行脚本。一条命令搞定,不需要 requirements.txt。
给 Agent 写脚本的四条铁律
官方文档特别强调了为 AI Agent 设计脚本时的注意事项,这些跟给人写脚本很不一样。
第一:绝对不能有交互式提示。 Agent 在非交互式 shell 里运行,遇到需要用户输入的地方会直接卡死。所有输入必须通过命令行参数、环境变量或 stdin 传入。
第二:必须有 --help 输出。 这是 Agent 学习你脚本接口的主要方式。写清楚有哪些参数、什么格式、给个例子。保持简洁——输出会进入 Agent 的上下文窗口,太长会挤占其他内容的空间。
第三:错误信息要有指导性。 Agent 拿到错误信息后会决定下一步怎么做。"Error: invalid input" 毫无帮助。要说清楚哪里错了、期望什么、怎么修:
Error: --format must be one of: json, csv, table. Received: \"xml\"
第四:输出用结构化格式。 JSON、CSV 优于自由文本。结构化输出可以被 Agent 和标准工具(jq、awk)直接消费。数据走 stdout,诊断信息走 stderr,分开来。
更深层的设计考量
官方还提到了几个容易忽略的点:
幂等性 — Agent 可能重试命令。"如果不存在则创建"比"创建,重复则报错"安全得多。
Dry-run 支持 — 对有副作用的操作(删除文件、发送请求),提供 --dry-run 参数让 Agent 先预览结果。
可预测的输出大小 — 很多 Agent 框架会自动截断超过 10-30K 字符的工具输出。如果你的脚本可能产生大量输出,默认输出摘要,支持 --offset 分页,或者用 --output 参数写文件。
量化实战:从理论到落地
说完官方规范,聊聊我在实际项目中的体会。
我做了一个叫 portfolio-distiller 的 Skill,用来把散户的 181 只持仓"蒸馏"成 15-20 只有纪律的组合。它的结构是:
portfolio-distiller/├── SKILL.md ← 流程编排 + 输出规范(约 200 行)├── scripts/│ ├── score.py ← 因子打分引擎(约 300 行)│ └── transition.py ← 税务优化过渡计划(约 300 行)├── references/│ └── factors.md ← 因子定义文档└── gotchas.md ← 踩坑记录
为什么 score.py 比 SKILL.md 重要
score.py 里做了几件 Markdown 做不到的事:
ROE 截断处理——超过 50% 的 ROE 很可能是高杠杆导致的虚高,代码里一行 roe_capped = stocks['roe'].clip(upper=0.5) 就解决了。如果写在 SKILL.md 里提醒 Claude "注意处理高杠杆 ROE",它可能记得也可能忘。
百分位排名——不同量纲的指标(ROE 是百分比、PE 是倍数、价格涨幅是百分比)必须归一化才能比较。这种数学运算写在 Python 里一劳永逸,不能指望 Claude 每次心算。
缺失值处理——如果两个以上因子缺数据,标记为需要人工审核,不自动打分。这种边界条件在 Markdown 里很容易被忽略,在代码里是强制执行的。
transition.py 的税务逻辑
过渡计划生成器更能体现脚本的价值。它需要判断:每个持仓的持有期是长期还是短期?离满一年还有多少天?卖出的税率是多少?先卖亏损的(tax loss harvest)还是先卖盈利的?
这些逻辑有大量条件判断和计算,每次用户的情况都不同。如果让 Claude 从头推理,每次可能走不同的路径。写成 Python 脚本,逻辑是锁死的——同样的输入永远得到同样的输出。
价值分布
经过实践,我认为这个 Skill 的价值分布是:SKILL.md 占 20%,scripts 占 60%,gotchas 占 20%。
SKILL.md 的角色很薄——告诉 Claude 什么时候跑什么脚本、结果怎么呈现。真正的核心能力在 scripts 里。而 gotchas.md 会随着使用不断积累,最终成为信噪比最高的内容。
诚实的局限
即使有了脚本,这个 Skill 仍然有几个问题没解决:
因子权重没有经过回测验证。动量 40%、质量 35%、价值 25% 是根据学术文献设定的,不是从历史数据优化出来的。这需要再加一个 backtest.py。
没有换手约束。每月重新打分可能导致大洗牌,交易成本和税会吃掉收益。需要在 score.py 里加 --max-turnover 参数。
聚类太粗糙。只按行业分类,没有用收益率相关性矩阵。这也是代码层面的改进。
这些局限进一步证明了一个观点:Skill 的天花板取决于 scripts 文件夹里的代码质量,不取决于 SKILL.md 写得多漂亮。 后续迭代的精力应该花在 Python 上,不是 Markdown 上。
总结
如果你在做 Claude Skills,记住这个优先级:
- 脚本要遵守四条铁律:无交互、有 help、错误信息有指导、输出结构化
- SKILL.md 只做流程编排和输出规范,越薄越好
- 没有回测的量化 Skill 只是好看的排序器——一定要验证
Skills 的真正价值不在那份 Markdown 文档有多精美,在于它调用的代码有多可靠。