站在上帝视角审视 Andy Lab 从"一句话部署内容"到"自我进化 skill 体系"的完整工作流。架构、流程、规则、数据、优缺点、改进方向——一次讲透。
这篇文档不是教你怎么装修、也不是讲冰箱板材。它解剖的是"Claude 和 Andy 一起搭建的、把内容自动变成上线 H5 页面的工作流"。
整套系统在 2026 年 4 月 15 日一天之内从单个臃肿 skill进化到 5 个专职 skill + 1 个 orchestrator + 分层记忆系统,当天完成了 4 次真实内容部署实战,其中一次还触发了"用户反馈 → 规则升格 → 下次不再犯"的完整闭环。
只想了解架构 → 跳到 第 3 章
在意实战数据 → 跳到 第 12 章
关心缺点和改进 → 跳到 第 14-15 章
为什么单一 skill 不够?旧流程有什么痛点?这个工作流的重构是怎么开始的?
最早只有一个 aliyun-deploy skill,SKILL.md 长达 336 行,里面捆绑了 6 件事:
每次部署,我要从头读完 336 行、在脑子里临时拼装步骤顺序、边做边漏。第一次跑 paint-guide 时,因为认知负担太大,出现了至少 2 次 Edit 工具失败(参数名写错成 old_str、全角半角标点不匹配)、差点漏掉首页同步。
部署、构建、同步、验证混在一个 skill 里。任一环节的经验更新都要在这个巨型文件里找位置。
每次新任务都要重新理解同一套步骤,没有"记忆 → 规则 → 沉淀"的机制。上一次踩过的坑这次还会再踩。
一个大 skill 的"完成"定义很模糊,没有清晰的中间产物,很难判断是哪一步出了问题。
用户在 4 月 15 日的对话中提出了四点扩展要求,直接催生了现在的架构:
5 个专职 skill + 1 个 orchestrator + 2 个支撑系统(styles / memory)。每个 skill 都有清晰的职责边界。
| Skill | 职责 | 禁止做的事 |
|---|---|---|
| deploy-guide | 编排流程、决策分类与预设、调用其他 skill、读写记忆 | 直接写 HTML、直接 ssh、直接改首页 |
| build-h5 | 从源内容生成 index.html |
部署、改首页、自行决定风格 |
| homepage-sync | 改 qinan.wang/index.html 的元数据 |
上传其他文件、部署新项目 |
| aliyun-deploy | ssh + scp + 可选 nginx 更新 | 碰首页、跑验证、检查字体 |
| page-verify | 只做检查(local 或 online) | 自动修复问题 |
这五条边界是硬规则,每个 skill 的 SKILL.md 的"反模式"段落里都写清楚了"这些事不要做"。
Claude Code 的 skill 本质是 playbook(写给 Claude 看的操作手册),不是真正的函数调用。所谓 deploy-guide "调用" build-h5,实际上是 deploy-guide 的 SKILL.md 告诉我"现在去调 /build-h5 工具",然后我在主对话里串起来执行。
这个事实影响了整个架构的设计:orchestrator 是一份流程清单 + 决策规则,不是执行引擎。
这是整套工作流的核心心脏。每个 Phase 都有明确的输入、动作、输出。
三个并行 Read:
~/.claude/skills/deploy-guide/memory/rules.md → 13 条硬规则~/.claude/skills/deploy-guide/styles/registry.md → 分类→预设映射并行执行(R2 规则),不串行读。目的是把所有"硬约束"和"历史经验"在动工前一次性加载进上下文。避免我在后面步骤里"凭记忆"跑流程。
处理源文件(通常是 markdown):
grep "^#{1,3} " file.md实战数据:4 次装修系列源文 323–718 行,全部遵守 R3 分段读。最长的 steam-oven-guide 分了 3 段。
按决策树判断新内容归哪个分类:
分类决策树
│
├─ 明显匹配已注册分类(主题 + 源路径 + 文件名都指向同一个)
│ → 自动归类,无需问用户
│
├─ 完全新主题(和任何已有分类对不上)
│ → 创建新分类候选 + 向用户确认
│
└─ 歧义(可能 A 可能 B)
→ 列出候选让用户选
信号源优先级(从高到低):① 用户在命令里的明示 → ② 源文件所在目录 → ③ 内容首段关键词 → ④ 文件名关键词
已有分类:从 registry.md 拿到 preset 名 → Read presets/{preset}.md 拿到完整预设 → 严格套用,自定义只允许在"辅助色卡"层。
新分类:调用 frontend-design 原则创建新风格 → 产出草稿给用户确认 → 确认后写回 presets/{new}.md 并更新 registry.md。
辅助色规则:每篇允许 2-5 个 --{slug}-* 变量用于装饰元素。核心 token(--bg / --ink / --accent / --font-*)绝对不允许覆盖。
调用 build-h5 skill,内部 4 个子阶段:
.fade-in 加 .in(R12)→ screenshot视觉不对就回到 4b 改骨架,不继续填充。
调用 page-verify 的 local 模式。5 项检查:
任一失败 → 回到 Phase 4 修正。
调用 aliyun-deploy(瘦身版),只做两件事:
ssh mkdir -p /var/www/html/{slug}scp index.html → 服务器如果是新项目,还要走"拉 nginx 配置 → 本地 Edit 插入 location 块 → 推回 → reload"的三步流程(不用远程 sed)。
调用 homepage-sync。按 R9 规则"先拉后推":
Step 1: scp server:/index.html → 本地
Step 2: 5 个并行 Edit
Edit A0: Hero 全局 stats (R13)
Edit A: 分类 section-count (+1)
Edit B: 新卡片插入
Edit C: 近期动态顶部插入
Edit D: footer 导航追加
Step 3: scp 本地 → server:/index.html
5 个并行 Edit 是同一条消息里的 5 个 tool_use,充分利用 R5 的并行能力。
调用 page-verify 的 online 模式(三件套,R10):
然后写 raw 日志到 memory/raw/{YYYY-MM-DD}-{slug}.md,追加 successes.md,最后问用户一句"有教训要升格吗?"
骨架优先 + 预览 + 批次填充的执行引擎。R6 规则的具体落实者。
为什么不能一次 Write 一个完整的 2000 行 HTML?三个原因:
从 5 次实战看,每批 3-4 章是最优尺寸:
| Batch 大小 | 风险 | 收益 |
|---|---|---|
| 1 章/批 | 太零碎,没有并行优势 | 安全但慢 |
| 3-4 章/批 ⭐ | 可控 | 并行 Edit 效率最高 |
| 5+ 章/批 | old_string 容易撞车、超长 message 可能触发限制 | 慢且风险大 |
特殊情况:超大章节独立一批。steam-oven-guide 的 Ch4 有 18 个小节,独立成一批处理,避免和其他章节混批导致的复杂度失控。
location.href = '...' 不一定跳转,要用 window.location.replace('...')window.scrollTo(y) 在 reload 后会被重置,要用 document.getElementById(id).scrollIntoView().fade-in 类靠 IntersectionObserver 在滚动时加 .in,截图前必须 querySelectorAll('.fade-in').forEach(el => el.classList.add('in'))这些细节都写进了 R12 规则。
改首页元数据的单一职责 skill。5 个锚点 + 先拉后推。
这个 skill 最初只管 4 个锚点,后来因为用户反馈升格出 R13,变成 5 个:
| 锚点 | 位置 | 更新规则 |
|---|---|---|
| Edit A0 · Hero 全局 stats(R13 新增) | .hero-stat-num[data-count] | 项目 +1 / 深度报告按分类判断 / 万字按实测累加 |
| Edit A · 分类 section-count | <span class="section-count"> | 单复数同步(1 guide → 2 guides) |
| Edit B · 新卡片 | .cards-grid 占位卡之前 | 标题 + 摘要 + meta + arrow |
| Edit C · 近期动态 | .updates-list 顶部 | 插入在第一条之前 |
| Edit D · Footer 导航 | footer 链接列表末尾 | 追加 |
首页可能在其他会话中被修改过(样式优化、SVG 插画、结构调整)。如果直接用本地旧文件覆盖上传,会丢失所有这些改动。这是 R9 规则。
# 1. scp 从服务器拉最新版覆盖本地
scp -i ~/.ssh/qinan_wang \
root@8.148.210.114:/var/www/html/index.html \
/Users/.../qinan.wang/index.html
# 2. Read 确认结构 → 5 个并行 Edit
# 3. scp 推回
scp /Users/.../qinan.wang/index.html \
root@8.148.210.114:/var/www/html/index.html
# 4. curl 验证
R13 规则里定义了正文字数统计命令:
perl -0777 -pe 's{<style[^>]*>.*?</style>}{}gs;
s{<script[^>]*>.*?</script>}{}gs;
s{<[^>]*>}{}g;
s{&[a-z#0-9]+;}{}g' file.html | tr -d '[:space:]' | wc -m
然后按"旧万字数 + 新页面万字数(向下取整)"更新 Hero stats。
瘦身后的单一职责 skill。只做 ssh + scp + 可选 nginx 更新,不再是什么都做的"万金油"。
| 维度 | 瘦身前 | 瘦身后 |
|---|---|---|
| SKILL.md 行数 | 336 行 | ~120 行 |
| 职责数量 | 6 件事 | 2 件事(ssh/scp + nginx) |
| 认知负担 | 每次要想"漏了哪步" | 只需要知道"文件从 A 搬到 B" |
| 失败可定位性 | 模糊 | 明确 |
剥离出去的职责全部有了新归宿:
homepage-syncpage-verify (online)page-verify (local)这不是删代码,是把代码搬家到正确的位置。每段逻辑都找到了它的单一归属。
反斜杠和换行转义太脆弱,一旦项目名里有特殊字符就会引爆配置。统一走拉→编辑→推三步。
# 3a. 拉到本地
scp root@server:/etc/nginx/conf.d/qinan.conf /tmp/qinan.conf
# 3b. Read → 用 Edit 工具插入 location 块(在"# Gzip 压缩"之前)
# location /{slug}/ {
# try_files $uri $uri/ /{slug}/index.html;
# }
# 3c. 推回 + reload
scp /tmp/qinan.conf root@server:/etc/nginx/conf.d/qinan.conf
ssh root@server "nginx -t && systemctl reload nginx"
Edit 工具处理缩进和转义比 sed 安全得多,推送前可以 Read 检查结果。
瘦身时发现 paint-guide 之前部署时没登记 nginx 显式 location 块,只是靠 location / 兜底才能访问。瘦身过程顺手补齐了它。
这说明单一职责不仅让新代码清爽,还会暴露旧代码的遗漏。
双模式检查器。只做检查,不修任何东西——发现问题交给调用方决定。
输入一个 HTML 文件路径,跑 5 个检查:
| 编号 | 检查 | 命令 |
|---|---|---|
| L1 | 字体合规 | grep -iE "font-family[^;]*(Cormorant|Instrument...)" |
| L2 | 共享 CSS 引用 | grep -q 'href="/shared/andy-lab.css"' |
| L3 | 共享 JS 引用 | grep -q 'src="/shared/andy-lab.js"' |
| L4 | Google Fonts 链接 | grep -q 'family=Syne' |
| L5 | 深色主题 hack 检测 | grep -iE 'background.*#0[0-9a-f]{5,}' |
L1-L4 是硬检查(FAIL 就停),L5 是警告(提示人工 review)。
输入 URL,跑 5 个 curl:
grep -c '<h2|<section' → 匹配期望第 2 项特别重要——很多时候页面 HTML 能访问,但共享资源挂了导致页面"裸奔"(只有 DOM 没有样式)。裸 grep 没法发现这种情况。
把"用什么视觉风格"这件事从"每次即兴发挥"变成"注册表驱动"。
~/.claude/skills/deploy-guide/styles/
├── registry.md ← 分类↔预设映射表
└── presets/
├── andy-lab-warm-paper.md ← 装修避坑 / 暖纸色系
├── andy-lab-tech-report.md ← Claude Code 解读 / 技术报告
└── andy-lab-product-card.md ← 产品与工具 / 产品卡
这是一份人类可读的 markdown 表格:
| 分类 | 预设 | URL 规则 | 已有页面 |
|---|---|---|---|
| 装修避坑 · 生活指南 | andy-lab-warm-paper | /{slug}-guide/ | fridge · paint · cabinet · steam-oven |
| Claude Code 解读 | andy-lab-tech-report | /{slug}/ | kairos · ultraplan · memory-report ... |
| 产品与工具 | andy-lab-product-card | /{slug}/ | minimax · hitutor · hushclaw-intro |
每个 preset 描述文件包含:
/shared/andy-lab.css)写得够具体,让我看完就能直接写 HTML,不需要再问"这个预设下 hero 应该长什么样"。
当内容主题天然包含"温度 / 火焰 / 橙红暖色"(厨房家电、烘焙、热水器等),辅助色中的"暖色强调色"可以直接复用 var(--accent) #D4430A,而不是另造一个。
这条约定写进了 andy-lab-warm-paper.md 的"辅助色层"章节,成为 preset-level 的正式约定。
让 AI 真正"记得"自己踩过的坑。rules / raw / successes 三层职责分明。
~/.claude/skills/deploy-guide/memory/
├── rules.md ← 正式规则(目前 13 条)
├── successes.md ← 成功案例索引(每次 1 行)
└── raw/
├── 2026-04-15-paint-guide.md
├── 2026-04-15-cabinet-guide.md
├── 2026-04-15-steam-oven-guide.md
└── ...
三层的定位完全不同:
流程跑完,"有值得升格为规则的教训吗?"用户说有 → 立即升格;用户说没有 → 只留 successes.md 一行索引。
这个设计避免了我"自作主张判断什么算失误"——我对自己失误的识别能力有系统性偏差(往往觉得自己做得很好),所以必须让用户当最终裁判。
| 路径 | 门槛 | 来源 |
|---|---|---|
| 常规 | 同一类错误在 raw/ 中出现 ≥2 次才升格 | 防噪声 |
| 特殊 | 用户直接指出的问题立刻升格(跳过门槛) | 最强信号 |
这是记忆系统第一次完整运转的案例。
cabinet-guide 部署完成后,用户截图显示首页顶部 "8 已上线项目 / 5 深度报告 / 30 万字分析",没有反映新上线的 cabinet-guide。
grep 定位到问题:homepage-sync skill 最初只定义了 4 个锚点(section-count / 新卡片 / 动态行 / footer),没有把 Hero 顶部的 .hero-stat-num[data-count] 纳入同步范围。
homepage-sync/SKILL.md:锚点从 4 个变 5 个,新增 Edit A0deploy-guide/memory/rules.md:新增 R13 规则原文下一次 steam-oven-guide 部署时,Phase 7 的 homepage-sync 一次性把 Hero stats 的三个数字都改了(11→12 / 37→39),同一个错误物理上不可能再犯。
这个案例完整演示了"硬触发 → 定位 → 修数据 → 修架构 → 验证"的闭环。这是记忆系统从概念变成现实的第一次。
前 8 条继承自历史项目 MEMORY,后 5 条来自 4 月 15 日当天的实战。每条都有来源标注。
4 月 15 日当天跑了 5 次部署。数据说话,趋势一目了然。
| # | 页面 | 源 md 行数 | HTML 行数 | 正文字数 | 章节 | Edit 失败 | 返工 | 架构 |
|---|---|---|---|---|---|---|---|---|
| 01 | fridge-guide | — | ~1600 | 29158 | — | — | — | 旧(单 skill) |
| 02 | paint-guide | 690 | 1975 | 20628 | 13 | 2 次 | 1 次 | 旧 → 升级中 |
| 03 | cabinet-guide | 323 | 1429 | 17126 | 10 | 0 | 0 | 新(5 skills) |
| 04 | steam-oven-guide | 718 | 1658 | 24666 | 13 | 0 | 0 | 新 |
| 05 | deploy-workflow(本篇) | ~500 | TBD | TBD | 16 | TBD | TBD | 新 |
按 Phase 耗时比例(主观感受):
Phase 0-1 (Read 规则 + 内容摄入) ████░░░░░░░░░░░░░░░░░░░░ 10%
Phase 4 骨架 (Write 一次) ████████░░░░░░░░░░░░░░░░ 20%
Phase 4 预览验证 ██░░░░░░░░░░░░░░░░░░░░░░ 5%
Phase 4 批次填充 (主要耗时) ████████████████░░░░░░░░ 40%
Phase 5 本地验证 █░░░░░░░░░░░░░░░░░░░░░░░ 3%
Phase 6 部署 ██░░░░░░░░░░░░░░░░░░░░░░ 5%
Phase 7 首页同步 ████░░░░░░░░░░░░░░░░░░░░ 10%
Phase 8 验证 + 记忆 ███░░░░░░░░░░░░░░░░░░░░░ 7%
批次填充仍然是最重的一环——因为内容本身就要写进 HTML 里。
8 条真正兑现过的优点,每一条都有实战证据。
5 个 skill 各管一摊。任一环节出错,错误范围被限制在那个 skill 内,不会污染全局。改一个 skill 不需要担心另一个 skill 的影响。
R13 的升格过程证明了这不是空口号。用户一次反馈,规则就永久沉淀,下次物理上不可能再犯。每次运行都在变得更稳。
每跑一次装修系列,andy-lab-warm-paper 预设的 CSS 组件就多积累一些通用块(callout / table / summary / spec card)。cabinet 和 steam-oven 的 CSS 有 60% 以上是复用。
rules.md 的 13 条规则写得足够具体("用 old_string 不要用 old_str"),即使我"忘记"某条规则,Phase 0 读一遍就回忆起来。比"靠经验"稳定得多。
每次运行的完整动作序列都在主对话里,你可以逐条检查。raw 日志又把关键事件永久沉淀。整个流程没有黑盒。
4 个章节 4 个并行 Edit 在同一条消息里发出,效率是串行的 4 倍。这是充分利用工具原子性带来的意外收益。
已有分类套用预设保证视觉一致性;新分类调 frontend-design 创造新预设。两种模式互相独立,不会出现"已有分类的页面越做越乱"的情况。
所有踩过的坑(preview_eval 的 reload 问题、font-family grep 的锚定问题)都变成了硬规则。这些"小智慧"不再是我一个人的经验,是可以被任何 agent 读取的操作手册。
8 条真实的问题。有些是架构局限,有些是 SDK 层面的制约,不美化。
playbook 式调用意味着没有结构化的参数/返回值。所有中间产物都在主对话的自然语言里流转。好处是透明,坏处是:无法形式化验证"build-h5 是不是真的调用过"、失败路径没有结构化错误码、如果我走神跳过一步没有强制机制阻止。这是 Claude Code SDK 的固有限制,短期内无法绕过。
Hero stats 的三个数字本质上是从所有已上线页面的数据聚合出来的。但现在 homepage-sync 是"每次 +N"的增量更新模式,不是"重新计算"模式。漏算会一直错下去、存量数据偏差不会自动修正、删除页面时需要手动 -1。正确做法应该是每次部署后跑一个全量重算脚本,目前还是增量模式。
SKILL.md 里写了"保留 30 天后可归档或删除",但这个清理动作没有自动化。如果 3 个月后 raw/ 里堆了 50 个文件,谁去清?目前是无人管理状态。
registry.md 是人类可读的 markdown 表格。它和实际部署的页面之间没有一致性校验。表格里写"装修避坑有 fridge + paint + cabinet + steam-oven",但服务器上如果少了一个,没人发现。应该有一个"漂移检测"步骤。
所有 4 次装修系列都是"已有分类自动归类"的简单路径。"新分类创建 → frontend-design 设计新预设 → 写回 registry" 这条路径一次都没跑过。理论上它是对的,但没有实战验证。
目前每批 3-4 章的并行 Edit 工作得很好,但没人测试过"一次 10 个并行 Edit"会发生什么。可能遇到:主对话 message 过长被截断、并行调度 old_string 撞车、工具调用量超限。没测就是不知道。
整个 Phase 4 的预览验证依赖 launch.json 定义的本地 server(npx serve -l 3456)。server 崩了、端口被占、launch.json 丢了、电脑没连电——预览就跑不动。没有 fallback。
如果一次部署把首页搞坏了(比如 Edit 工具用错 old_string 导致首页 HTML 损坏),没有一键回滚。要手动从 git 或 backup 恢复。目前 index.html 每次 scp 覆盖前没有自动备份,这是风险点。
按落地难度分三档:下次运行就能做的 / 需要改 skill 架构的 / 需要外部支持的。
curl homepage | grep data-count 打印三个数字确认。scp index.html index.html.backup.{timestamp} 一行命令解决回滚问题。几乎零成本。/var/www/html/*/index.html 实时统计重算",彻底告别漂移风险。/var/www/html/ 的实际目录,不一致就 warning。这套工作流从"1 个臃肿 skill"进化到"5 个专职 skill + 1 orchestrator + 记忆系统"花了一天。最大的启发不是架构本身,是这种架构可以被 AI 自己迭代。
传统软件的 function / module 是为"确定性执行"设计的。AI 协作是"非确定性对话",需要的是 playbook——一份写给 AI 看的"下次怎么做"的手册。
playbook 的好处是可被 AI 自己修改:我犯了错,可以把"这个错别再犯"写进 playbook;下次的我(或者别的 agent)读了 playbook 就会避开。这是一个可自我强化的闭环。
不是每个观察都该变成规则。rules.md 的价值在于"少而精"——13 条每一条都是硬约束,没有"参考建议"。
门槛设计得好:出现 2 次才升格 + 用户反馈直接升格。前者防噪声,后者留出人类裁判的位置。两种机制互补,让规则数量可控。
raw(写多读少)/ rules(读多写少)/ successes(索引)的三层结构不是我原创的,但在这个场景下的运转效果值得记下来。它可以推广到任何"需要从经验中学习"的 AI 系统:
这三层必须职责分离。混在一起就会乱。
记忆系统设计里最反直觉的一点:不让 AI 自己判断什么是错误。
原因很朴素——AI 对自己的错误有系统性偏差。我常常觉得自己做得很好,用户一看才发现漏了个关键环节(比如 Hero stats)。如果让我自己判断"这次要不要记规则",R13 这样的关键规则可能永远不会升格。
所以记忆系统必须有人类裁判。硬触发(工具失败)可以自动记,但软触发必须问用户。这不是"AI 不够聪明"的妥协,是职责分工:AI 做"快速尝试 + 发现异常",人做"裁定异常的严重程度 + 决定是否升格"。
如果你只看这一段:
用户: /deploy-guide ~/path/to/content.md
Claude:
Phase 0: 并行读 rules.md + registry.md + 项目 memory
Phase 1: Grep 章节 + 分段 Read 内容
Phase 2: 自动归类 或 提议新分类
Phase 3: 套用已有预设 或 创建新预设
Phase 4: 骨架 Write → preview 截图 → 批次 Edit 填充
Phase 5: 本地字体 + 共享资源 + DOM 检查
Phase 6: ssh mkdir + scp + 可选 nginx 三步更新
Phase 7: 先拉后推 + 5 个并行 Edit 更新首页
Phase 8: curl 三件套 + 写 raw 日志 + 问用户有没有教训
约 15 分钟,happy path 无人工干预。
2026-04-15 · 作者: Claude + Andy · 版本: v1.0 · 线上: https://qinan.wang/deploy-workflow/