ORANGE BOOK · AGENT SKILL

第九章 Skill 进阶(脚本/模板/依赖)

你将学到

  • 在 Skill 里嵌入 Python / Bash 脚本的正确姿势。
  • templates/references/assets/ 三个目录的用法。
  • dependencies 字段声明 Python 依赖。
  • 2 个完整进阶实战:股票 K 线 + 项目甘特图。
  • 多 Skill 协作:流水线、嵌套、并行。
  • 避坑:脚本路径、虚拟环境、超时控制。

你需要准备

  • 已经能跑基础 Skill 的 Claude(推荐 Claude Code,进阶玩法本地体验最好)。
  • 装好 Python ≥ 3.10(python.org 下载)。
  • 一些好奇心和 1.5 小时。

提醒:本章涉及一些 Python 基础。完全不会代码的话,跑通"股票 K 线"和"甘特图"两个完整示例就够你抄;不强求理解每一行。


一、Skill 的"加料"——四个目录

第八章我们说 SKILL.md 已经够用。但当你的 Skill 复杂到一定程度,需要真的执行代码真的读公司模板时,就需要扩展目录。

按 Anthropic 官方约定,Skill 文件夹下有 4 个特殊子目录:

目录 装什么 Claude 怎么用
scripts/ Python / Bash / Shell 脚本 在沙箱里执行
templates/ 文件模板(.docx, .pptx, .xlsx, .md, .html 等) 读取后填充并输出
references/ 参考资料(.md 长文) 按需阅读,理解领域知识
assets/ 静态资源(图片、字体、音频) 嵌入到输出文件里

所有这些子目录都是按需加载的——Claude 只在用得到的时候才打开。这是渐进式披露的核心。


二、scripts/:让 Skill 真的"动手做事"

2.1 脚本的"调用契约"

最朴素的用法:在 SKILL.md 里告诉 Claude "用 scripts/xxx.py 处理这个输入",Claude 会用 Bash 工具去跑:

python ~/.claude/skills/<skill-name>/scripts/xxx.py [args]

脚本的 stdout 是返回结果,Claude 会把它读回来继续处理。

2.2 脚本写法的 5 条建议

按 Anthropic 官方文档:

  1. 只接受简单参数(命令行 args 或 stdin),不要假设有数据库连接或秘密。
  2. 输出 JSON / Markdown / CSV 这种结构化文本,方便 Claude 解析。
  3. 失败时退出码非 0 + stderr 输出错误信息。
  4. 不要打印不必要的"装饰"(progress bar、日志),它们会污染结果。
  5. 超时自我控制:长任务自己拆批,避免被沙箱强杀。

2.3 一个最简单的脚本示例

# ~/.claude/skills/word-counter/scripts/count.py
import sys
import json

text = sys.stdin.read()

result = {
    "chars": len(text),
    "words": len(text.split()),
    "lines": len(text.splitlines()),
}

print(json.dumps(result, ensure_ascii=False))

对应的 SKILL.md:

---
name: word-counter
description: 统计输入文本的字数、词数、行数。触发: "字数统计""word count""统计字数"
allowed-tools: Read, Bash
---

# 字数统计器

## 工作流
当用户给出一段文本(或者贴一个文件路径),用 scripts/count.py 处理。

调用方式:
```bash
echo "$INPUT" | python scripts/count.py

将 JSON 解析后给用户友好的输出:

字数:X,词数:Y,行数:Z


> **关键**:在 `allowed-tools` 里加上 `Bash`,否则 Claude 跑不了脚本。

---

## 三、实战 1:股票 K 线 + 趋势分析 Skill

### 3.1 目标

输入股票代码(如 `AAPL`),输出最近 60 天 K 线图 + 简短趋势分析(含 MA20、MA60、RSI)。

### 3.2 文件结构

stock-analyst/ ├── SKILL.md ├── scripts/ │ ├── fetch.py # 拉取行情数据 │ └── plot.py # 画 K 线图 + 计算指标 └── references/ └── indicators.md # 技术指标定义(让 Claude 知道 MA20 是啥)


### 3.3 SKILL.md

```markdown
---
name: stock-analyst
description: >
  对指定美股/A 股做 60 天 K 线分析。输出: K 线图、MA20/MA60、RSI、一段趋势点评。
  触发: "看下 xxx 股票""分析 AAPL""股票分析""K 线""画 K 线"
allowed-tools: Read, Write, Bash
dependencies:
  - yfinance
  - pandas
  - matplotlib
  - mplfinance
---

# 股票分析师

## 输入
用户给出股票代码(默认美股,如 AAPL;A 股加 .SS / .SZ 后缀)。
可选: 时间窗口(默认 60 天)。

## 工作流

### 第 1 步:拉数据
跑 scripts/fetch.py:
```bash
python scripts/fetch.py <SYMBOL> <DAYS>

输出 stdout 是 CSV 格式行情数据。

第 2 步:画图 + 算指标

把 CSV 通过 stdin 喂给 scripts/plot.py:

python scripts/plot.py <SYMBOL> <DAYS> < data.csv

会生成 ~/stock-charts/<SYMBOL>-YYYYMMDD.png 并在 stdout 输出 JSON: { "current_price": ..., "ma20": ..., "ma60": ..., "rsi": ..., "30d_high": ..., "30d_low": ..., "trend": "up" | "down" | "sideways" }

第 3 步:写点评

基于 JSON 写一段 100 字以内的趋势点评,结构:

  • 当前价位 vs MA20/MA60 的关系
  • RSI 是否进入超买/超卖区
  • 30 天高低点判断
  • 一句"非投资建议"的免责声明

第 4 步:输出给用户

  • 一段 Markdown 总结
  • 嵌入 K 线图
  • JSON 数据(折叠展示)

风格

  • 中性、客观、不诱导
  • 必须包含: "本分析仅供参考,不构成投资建议"
  • 数字保留两位小数

参考

查看 references/indicators.md 了解 MA、RSI 的标准计算。


### 3.4 scripts/fetch.py

```python
#!/usr/bin/env python3
import sys
from datetime import datetime, timedelta
import yfinance as yf

if len(sys.argv) < 2:
    print("Usage: fetch.py <SYMBOL> [DAYS]", file=sys.stderr)
    sys.exit(1)

symbol = sys.argv[1]
days = int(sys.argv[2]) if len(sys.argv) > 2 else 60

end = datetime.now()
start = end - timedelta(days=days * 2)

try:
    df = yf.download(symbol, start=start, end=end, progress=False)
    if df.empty:
        print(f"No data for {symbol}", file=sys.stderr)
        sys.exit(2)
    df.tail(days).to_csv(sys.stdout)
except Exception as e:
    print(f"Error fetching {symbol}: {e}", file=sys.stderr)
    sys.exit(3)

3.5 scripts/plot.py

#!/usr/bin/env python3
import sys
import json
import os
from datetime import datetime
import pandas as pd
import mplfinance as mpf

if len(sys.argv) < 3:
    print("Usage: plot.py <SYMBOL> <DAYS>", file=sys.stderr)
    sys.exit(1)

symbol = sys.argv[1]
days = int(sys.argv[2])

df = pd.read_csv(sys.stdin, index_col=0, parse_dates=True)

df["MA20"] = df["Close"].rolling(20).mean()
df["MA60"] = df["Close"].rolling(60).mean()

delta = df["Close"].diff()
gain = (delta.where(delta > 0, 0)).rolling(14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(14).mean()
rs = gain / loss
df["RSI"] = 100 - (100 / (1 + rs))

out_dir = os.path.expanduser("~/stock-charts")
os.makedirs(out_dir, exist_ok=True)
out = os.path.join(out_dir, f"{symbol}-{datetime.now().strftime('%Y%m%d')}.png")

apds = [
    mpf.make_addplot(df["MA20"], color="orange"),
    mpf.make_addplot(df["MA60"], color="blue"),
]
mpf.plot(df, type="candle", addplot=apds, savefig=out, style="charles", title=f"{symbol} - {days}d")

current = float(df["Close"].iloc[-1])
ma20 = float(df["MA20"].iloc[-1])
ma60 = float(df["MA60"].iloc[-1])
rsi = float(df["RSI"].iloc[-1])

if current > ma20 > ma60:
    trend = "up"
elif current < ma20 < ma60:
    trend = "down"
else:
    trend = "sideways"

result = {
    "symbol": symbol,
    "current_price": round(current, 2),
    "ma20": round(ma20, 2),
    "ma60": round(ma60, 2),
    "rsi": round(rsi, 2),
    "30d_high": round(float(df["High"].tail(30).max()), 2),
    "30d_low": round(float(df["Low"].tail(30).min()), 2),
    "trend": trend,
    "chart_path": out,
}
print(json.dumps(result, ensure_ascii=False))

3.6 references/indicators.md

# 常用技术指标定义

## MA20 / MA60
N 日收盘均价,反映中短/中长趋势。

- 价格上穿 MA20: 短期看涨信号
- MA20 上穿 MA60: 中期看涨(金叉)
- MA20 下穿 MA60: 中期看空(死叉)

## RSI (相对强弱指数)
14 日窗口,0–100。

- RSI > 70: 超买区,回调可能
- RSI < 30: 超卖区,反弹可能
- 30–70: 正常区间

## K 线
开盘 / 收盘 / 最高 / 最低 / 成交量五要素。
- 阳线: 收盘 > 开盘
- 阴线: 收盘 < 开盘

> 注意:所有指标都有滞后性,单一指标不能作为投资决策依据。

3.7 用法

帮我看下 AAPL 这只股票最近的趋势。

Claude 会:

  1. 看 description 命中 → 召唤 stock-analyst。
  2. 看 instructions → 跑 fetch.py。
  3. 跑 plot.py。
  4. 读 indicators.md(如果不确定 RSI 是啥)。
  5. 写一段中文点评。
  6. 输出图 + 点评给你。

第一次跑会自动装 yfinance、pandas 等依赖(dependencies 字段的功劳)。


四、templates/:让输出"穿上你的衣服"

4.1 用途

让 Claude 用你预设的格式输出,比如:

  • 公司 PPT 模板(含 Logo、配色、字体)
  • 公司周报 Word 模板(含 header、footer、样式)
  • 公司财报 Excel 模板(含表头、公式占位)

4.2 在 SKILL.md 里"指着用"

## 输出
请基于 templates/weekly.docx 的样式生成最终周报:
- 替换占位符 {{NAME}} {{WEEK}} {{DONE}} {{PLAN}} {{RISK}} {{ASK}}
- 不要破坏原有样式
- 输出为 weekly-<NAME>-<WEEK>.docx

Claude 会用 docx Skill 加载 templates/weekly.docx,替换占位符,再保存新文件。

4.3 模板文件命名约定

  • 用清晰的扩展名:.docx.pptx.xlsx.html.md
  • 命名描述用途:weekly-report-template.docxtemplate1.docx 强。
  • 多模板时用文件夹分类:templates/cn/templates/en/

五、references/:让 AI 懂你公司的"黑话"

5.1 用途

公司内部术语、业务规则、领域知识,AI 不可能"自带"。把它们写在 references/ 里,Skill 用得着时去看。

5.2 例子:销售提案 Skill 的 references

sales-proposal/
├── SKILL.md
├── references/
│   ├── product-features.md     # 我们的产品功能详解
│   ├── pricing-rules.md        # 定价规则(折扣、套餐)
│   ├── case-studies.md         # 客户案例库
│   └── competitor-notes.md     # 竞品对比要点
└── templates/
    └── proposal-template.pptx

5.3 在 SKILL.md 里"按需引用"

## 工作流
...
### 第 4 步:写"差异化"页
基于 references/competitor-notes.md,找出客户提到的 1–2 个竞品,
写明我们 vs 它的 3 个差异点。

Claude 在跑到这一步时才会去打开 competitor-notes.md。

5.4 references 的 3 条原则

  1. 每份文件聚焦一个主题,不要写"杂货铺"。
  2. 用清晰小标题分块,方便 Claude 跳读。
  3. 保持最新,定期 review;过期信息比没信息更危险。

六、dependencies:自动装包,不用你管

6.1 在 frontmatter 里声明

---
name: stock-analyst
description: ...
dependencies:
  - yfinance
  - pandas
  - matplotlib
  - mplfinance>=0.12
---

第一次执行此 Skill 的脚本时,Claude 会自动 pip install 这些包。

6.2 进阶:指定版本

dependencies:
  - pandas>=2.0,<3.0
  - matplotlib==3.8.2

避免新版破坏你的脚本。

6.3 系统级依赖

如果你的脚本需要系统命令(如 ffmpegtesseract),通常 dependencies 装不了——你需要:

  • 在 README.md 里说明"装这个 Skill 前先 brew install ffmpeg"。
  • 或在 scripts/setup.sh 里写一段安装脚本,让用户手动跑一次。

七、实战 2:项目甘特图生成器 Skill

7.1 目标

输入项目任务 CSV(含任务名、负责人、起止日期、依赖),输出一张漂亮的甘特图。

7.2 文件结构

gantt-chart/
├── SKILL.md
├── scripts/
│   └── plot.py
└── templates/
    └── tasks-sample.csv

7.3 SKILL.md

---
name: gantt-chart
description: >
  从任务 CSV 生成甘特图。CSV 列: task,owner,start,end,depends_on。
  触发: "甘特图""项目计划图""gantt""画一张项目排期"
allowed-tools: Read, Write, Bash
dependencies:
  - pandas
  - matplotlib
---

# 甘特图生成器

## 输入
用户给一个 CSV 文件(或粘贴 CSV 内容)。
列: task, owner, start (YYYY-MM-DD), end (YYYY-MM-DD), depends_on (可选)

如果用户没有 CSV,让他们先按 templates/tasks-sample.csv 的格式造一个。

## 工作流
```bash
python scripts/plot.py <CSV_PATH> <OUTPUT_PATH>

输出: <OUTPUT_PATH>.png

风格

  • 横向甘特图(Y 轴是任务,X 轴是日期)
  • 每个负责人用不同颜色
  • 任务条上写任务名,旁边标负责人
  • 关键路径用粗边框(如果输入有 depends_on)
  • 中文 SimHei 字体
  • 图例放右上角

输出

  1. 甘特图 PNG
  2. 一份 Markdown 摘要:
    • 总任务数
    • 项目跨度(起 - 止)
    • 关键里程碑
    • 风险点(任务间隔过短、依赖链过长)

### 7.4 scripts/plot.py

```python
#!/usr/bin/env python3
import sys
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.patches import Patch

if len(sys.argv) < 3:
    print("Usage: plot.py <CSV_PATH> <OUTPUT_PATH>", file=sys.stderr)
    sys.exit(1)

csv_path, out_path = sys.argv[1], sys.argv[2]

df = pd.read_csv(csv_path, parse_dates=["start", "end"])
df = df.sort_values("start").reset_index(drop=True)

owners = df["owner"].unique()
colors = plt.cm.tab10.colors[: len(owners)]
owner_color = {o: colors[i] for i, o in enumerate(owners)}

fig, ax = plt.subplots(figsize=(12, max(6, len(df) * 0.4)))
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

for i, row in df.iterrows():
    duration = (row["end"] - row["start"]).days
    ax.barh(i, duration, left=row["start"], color=owner_color[row["owner"]], edgecolor="black", height=0.6)
    ax.text(row["start"], i, f"  {row['task']} ({row['owner']})", va="center")

ax.set_yticks(range(len(df)))
ax.set_yticklabels(df["task"])
ax.invert_yaxis()
ax.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d"))
ax.xaxis.set_major_locator(mdates.WeekdayLocator(interval=1))
plt.xticks(rotation=45)

legend = [Patch(facecolor=owner_color[o], label=o) for o in owners]
ax.legend(handles=legend, loc="upper right")

plt.title("项目甘特图")
plt.tight_layout()
plt.savefig(out_path, dpi=150)
print(f"Saved to {out_path}")

7.5 templates/tasks-sample.csv

task,owner,start,end,depends_on
需求调研,小王,2026-04-01,2026-04-07,
原型设计,小李,2026-04-08,2026-04-14,需求调研
开发,小张,2026-04-15,2026-04-30,原型设计
测试,小赵,2026-04-25,2026-05-05,开发
上线,小钱,2026-05-06,2026-05-07,测试

7.6 用法

[贴入 tasks.csv 内容]
帮我画一张甘特图。

10 秒后你拿到一张 PNG + Markdown 摘要。


八、多 Skill 协作:流水线、嵌套、并行

复杂任务往往需要多个 Skill 联手。Anthropic 的 Skill 系统天然支持这件事。

8.1 流水线(Pipeline)

最常见:A 的输出是 B 的输入。

用 invoice-extractor 提取这堆 PDF 发票里的字段;
然后用 family-finance Skill 把字段按月入账;
最后用 monthly-finance-report Skill 生成本月报告。

Claude 会自动按顺序调用三个 Skill,把上一步结果传给下一步。

8.2 嵌套(Nested)

一个 Skill 在执行中调用另一个 Skill。

例:weekly-report Skill 内部调用 meeting-minutes Skill 来汇总本周的会议。

实现方式:在 SKILL.md instructions 里写"如果发现用户本周开过会,调用 meeting-minutes Skill 汇总"。

8.3 并行(Parallel)

互不依赖的 Skill 可以并行跑,省时间。

例:每周早报需要同时拉 Notion、GitHub、Slack 三个数据源。

实现方式:用 Claude Code 的 sub-agent 能力(详见 sessions_spawn 文档),或在 SKILL.md 里明确写"以下三个步骤可并行"。

8.4 多 Skill 协作的 3 条注意

  1. 避免循环调用:A 调 B,B 又调 A——会无限递归。
  2. 明确边界:每个 Skill 的输入输出是什么,写清楚。
  3. 限制层数:一般不超过 3 层嵌套。

九、本章一图回顾

+-------------------------------------------------------------+
|             Skill 进阶 = SKILL.md + 4 个目录                |
+-------------------------------------------------------------+
|                                                             |
|  scripts/      ──>  Python/Bash 脚本 (在沙箱里跑)           |
|                     - 输入: args/stdin                      |
|                     - 输出: stdout (JSON/CSV/MD)            |
|                     - 失败: 退出码 + stderr                 |
|                                                             |
|  templates/    ──>  文件模板 (.docx/.pptx/.xlsx/.html)      |
|                     - 用 {{占位符}} 让 Claude 替换           |
|                                                             |
|  references/   ──>  公司术语/业务规则 (.md 长文)             |
|                     - 按需阅读                              |
|                     - 一份文件一个主题                       |
|                                                             |
|  assets/       ──>  图片/字体/音频                          |
|                     - 嵌入到输出文件                         |
|                                                             |
|  dependencies: ──>  Python 包自动装                         |
|                     - 支持版本约束                          |
+-------------------------------------------------------------+

多 Skill 协作:
  流水线: A → B → C
  嵌套:   A 内部调用 B
  并行:   A B C 同时跑

完整实战:
  - stock-analyst (拉行情 + 画 K 线 + 算指标)
  - gantt-chart (CSV → 甘特图)

3 大注意:
  避免循环 / 明确边界 / 限制层数

给你 3 句话提醒

  1. 进阶 Skill 的核心,是把"AI 决策"和"确定性执行"分开——AI 决定"做什么",脚本负责"怎么做"。
  2. 不要把所有逻辑都塞进 Python 脚本。SKILL.md 永远是主要"指挥者",脚本只是工具。
  3. 多 Skill 协作威力巨大但容易乱。先把每个 Skill 单独跑通,再串起来。

下一章预告

下一章 第十章 Skill 的安全与隐私,我们直面"Skill 的另一面"——它能动手做事,意味着它也能做坏事。

我会带你看清沙箱模型的边界、description 注入攻击的真实案例、allowed-tools 这个安全围栏怎么用、第三方 Skill 该怎么 5 步审计、家庭和财务这种敏感场景怎么单独保护。

读完那一章你会知道:哪些 Skill 装了不会出事,哪些装了可能让你后悔。

走,进第十章。