一步一步扒开问题,最后发现“做网站”这件事一股脑塞给一个 Agent 会爆。

Idea2Site 最后变成了一套 skills,这个形态是一路试出来的。

它更像是在反复遇到问题之后,一步一步被拆出来的。

如果用一句话概括这个演进过程,大概就是:

从“让 Agent 写网页”,变成“让 Agent 跑一条有质量门禁的建站流水线”。

1. 最朴素的方案:一个 Agent 直接做完整站

最开始最容易想到的方式就是一股脑全交给一个 Agent:

用户输入需求
       ↓
一个大 Agent 理解需求
       ↓
生成网站文件
       ↓
告诉用户完成

这套流程很直接,也很符合很多人对 AI 建站的想象。说实话,我一开始也觉得这条路可以先试一下。

但是一旦真的用起来,就会发现它很不稳定,而且这种不稳定会在几步之后一起爆出来。

比如用户说:

我想做一个个人博客,风格安静一点,适合写技术笔记,最好以后能发布。

一个大 Agent 需要同时决定:

  • 什么叫安静?
  • 是技术博客还是个人主页?
  • 首页应该放什么?
  • 是否需要关于页?
  • 是否需要项目页?
  • 文章页长什么样?
  • CSS 怎么组织?
  • 图片放在哪里?
  • 路径直接打开是否稳定?
  • 发布到哪里?

这里每一个问题单独看都不难,但组合在一起就很容易让模型变得短视。

它会先写一个漂亮首页,然后忘记文章详情页; 或者写了文章详情页,但是导航还是指向不存在的路径; 或者路径用 /assets/style.css,本地 HTTP 看起来没问题,但 GitHub Pages 子路径下直接坏; 或者生成一堆 demo 内容,最后没有任何地方记录哪些是 placeholder。

这时候我就意识到,核心问题在任务本身没有拆开。Agent 在一个超长 prompt 里同时管审美、结构、内容、路径和发布,最后一定会顾此失彼。

2. 第一轮拆分:把“建站”拆成几类任务

后来我把用户口中的“做一个博客”拆了一下,发现它其实至少包含五类任务。

第一类是 方向选择

也就是在还没写代码之前,先回答:

这个站到底应该是什么气质?
它是研究主页、技术博客、作品集、数字花园,还是个人档案?

第二类是 视觉参考研究

只有“安静”“技术感”“自然”这些词还不够。Agent 需要看到真实网站,提取可实现的布局、字体、颜色、内容密度和交互风格。

第三类是 静态网站生成

这一步才是真正写 HTML/CSS/JS。它要决定页面结构、导航、文章模板、项目列表、移动端布局等,这里面也有一堆容易翻车的小细节。

第四类是 内容落地

用户的 bio、项目、链接、文章、Obsidian 笔记、图片、公式都要进站,而且要进入正确的位置。

第五类是 质量检查与发布

它要检查路径、乱码、占位符、隐私、断链、浏览器表现和部署设置。

所以如果把它画成一条流程,大概是这样:

Idea
  ↓
Theme Search
  ↓
Style References
  ↓
Static Build / Style Recreation
  ↓
Personalization
  ↓
Post Import
  ↓
Review
  ↓
Publish

这时候我觉得,最自然的做法就是把这些阶段拆成不同 skill。每个 skill 负责自己最清楚的一块,让 prompt 的负担降下来。

3. 第二轮拆分:不同 skill 负责不同类型的错误

拆 skill 的另一个原因是错误定位,这个在实际跑的时候非常明显。

如果最终网站不好看,问题可能出在:

  • 主题方向本来就选错了;
  • 参考网站找得太泛;
  • 生成时没有抓住设计特征;
  • CSS 实现能力不够;
  • 用户内容太长但没有适配布局。

如果最终网站发布不了,问题可能出在:

  • 路径用了 root-absolute;
  • deploy root 选错;
  • 发布目录里没有 index.html
  • GitHub Pages 子路径没有考虑;
  • 私密文件混进了 site 目录。

如果把所有逻辑放在一个 Agent 里,失败之后很难知道应该修哪里。

拆成 skill 之后,每个问题都能更自然地回到对应模块。这样线上效果差的时候,我们至少知道该从哪里开始查。

问题对应 skill
方向太泛search-blog-theme
参考不够具体find-style-references
原创站结构不完整make-personal-site
复刻不像参考网站copy-website-style
用户身份还是 placeholderpersonalize-site
文章没导进去或格式坏了add-blog-posts
某个区域需要微调edit-site-part
路径、乱码、隐私、断链review-static-site
部署设置和平台选择publish-static-site

这让整个系统变得更像一个工程流水线,少一点巨大 prompt 的玄学输出。

每一步都有自己的 success gate,避免依赖“模型觉得做完了”。这一点我觉得很重要,因为 Agent 最容易出现的情况就是“说完成了,但其实漏了一堆东西”。

4. 第三轮拆分:实现 skill 和编排 skill 分离

到这里其实还有一个问题:

用户通常并不知道自己该调用哪个 skill。

用户很少这样说:

请先调用 search-blog-theme,再调用 find-style-references,再调用 make-personal-site。

用户通常会说:

帮我做一个个人博客。

所以还需要一个编排层。

这就是 from-idea-to-personal-sitebuild-personal-site 的作用。

这两个 skill 看起来都像路由器,但职责不完全一样。

from-idea-to-personal-site 是用户面对的端到端入口。它负责从一个模糊 idea 一路走到本地 validated site,甚至继续走到发布。

它关注的是完整流程:

明确终点
选择方向
找参考
创建/复刻网站
个性化
导入文章
审查
发布或准备发布
最终交接

build-personal-site 更像一个低层协调器。当当前问题已经进入中途状态,重点变成“现在这个状态下一步该走哪个 skill”时,它负责做路由。

比如:

  • 已有站点,替换个人信息;
  • 已有站点,加文章;
  • 已有站点,检查发布状态;
  • 某一步失败,需要路由到最小负责模块修复。

所以这两个编排 skill 的关系大概是:

from-idea-to-personal-site:面向用户完整目标
build-personal-site:面向内部阶段路由

这个拆分很重要。

因为端到端 skill 需要关心“最终有没有交付”,而低层路由 skill 需要关心“当前这一步应该找谁”。

5. 整体架构

最后的架构可以分成五层。

5.1 方向发现层

负责把用户模糊审美变成可执行方向。

search-blog-theme
find-style-references

search-blog-theme 负责提出 3-5 个主题方向,比如极简笔记、研究主页、数字花园、个人操作系统、档案式博客等。

find-style-references 负责把选定方向落到真实参考网站上,提取设计 brief。

5.2 建站执行层

负责真正生成站点。

make-personal-site
copy-website-style

make-personal-site 处理原创静态站。

copy-website-style 处理“参考这个网站做一个气质接近的版本”。

两者共同点是都输出纯静态 HTML/CSS/JS,都强调页面相对路径、UTF-8、EDITING.md 和浏览器验证。

区别是:

make-personal-site:从方向生成原创站
copy-website-style:从具体参考站重建风格和交互

5.3 内容落地层

负责让网站变成用户自己的。

personalize-site
add-blog-posts

personalize-site 替换身份、bio、项目、链接、metadata、头像、demo 文案。

add-blog-posts 导入文章、Markdown、Obsidian、Word、旧 HTML、图片、公式、内部链接等。

一个负责“人是谁”,一个负责“写了什么”。

5.4 局部迭代与质量层

负责修细节和做门禁。

edit-site-part
review-static-site

edit-site-part 负责小范围修改,整站重做会回到建站层。

review-static-site 是硬 QA,检查路径、页面类型、编码、隐私、占位符、浏览器渲染、移动端等。

5.5 发布层

负责把已经验证过的静态站准备或发布出去。

publish-static-site

它会先确认:

  • deploy root 是否正确;
  • index.html 是否在顶层;
  • 是否跑过 review;
  • 是否有隐私文件;
  • 平台设置怎么填;
  • 是否明确授权远程操作。

6. Contract 和 Gate 的作用

每个 skill 里都有一个非常关键的结构:

Inputs
Outputs
Boundaries
Success gate
If gate fails

我觉得这是整个项目里最工程化的一点。

Inputs 说明这个 skill 需要什么。

Outputs 说明它应该产出什么。

Boundaries 说明它的处理范围在哪里。

Success gate 说明什么叫做真的完成。

If gate fails 说明失败后应该怎么修。

这其实是在给 Agent 写工作协议。

比如 make-personal-site 的边界是原创静态建站;发布、大型文章迁移、高保真复刻会回到对应 skill。

如果用户要发文章,就应该交给 add-blog-posts。 如果用户要复刻某个网站,就应该交给 copy-website-style。 如果用户要部署,就应该交给 publish-static-site

这样可以避免一个 skill 越做越大,最后变成什么都管但什么都不精。

7. 为什么一定要有 review-static-site

在这套架构里,review-static-site 是一个很核心的门禁。

因为网站生成只是中间结果,通过审查后才接近交付。

一个站点看起来没问题,不代表它真的能交付。至少要检查:

  • HTML/CSS/JS/JSON/Markdown/SVG 是否 UTF-8 可读;
  • 是否有 mojibake;
  • HTML 是否有 <meta charset="utf-8">
  • hrefsrcsrcset、CSS url(...) 是否指向存在的本地资源;
  • 是否误用了 /assets/... 这类 root-absolute 本地路径;
  • 是否残留 TODOplaceholderyour name
  • 是否有 .env、私钥、token、本机绝对路径;
  • 是否至少有预期页面类型;
  • 是否有 EDITING.md

这些检查很多都被固化到了 static_site_check.py 里。

这说明 Idea2Site 同时用 prompt 约束 Agent,并把一部分质量要求写成了确定性检查。

我觉得这是非常必要的。

因为 prompt 容易漏,脚本会稳定执行。

8. 最终的工作流

最后完整流程大概是这样:

用户输入
  ↓
from-idea-to-personal-site 判断终点
  ↓
search-blog-theme 选择方向
  ↓
find-style-references 找真实参考并生成 brief
  ↓
make-personal-site 或 copy-website-style 生成站点
  ↓
personalize-site 替换用户信息
  ↓
add-blog-posts 导入文章
  ↓
review-static-site 做质量门禁
  ↓
publish-static-site 准备或执行发布

当然实际运行时按需选择步骤。

如果用户已经有参考站,就跳过主题搜索; 如果用户只是要加文章,就直接走 add-blog-posts -> review-static-site; 如果用户只是改一个按钮,就走 edit-site-part; 如果用户只是问怎么发布,就先 review,再 publish。

这就是 skill suite 相比单个大 skill 的价值:

它会根据当前状态选择最短可靠路径。

9. 小结

这个项目的架构演进,其实就是从“生成”走向“交付”。

生成页面依赖模型写代码。

交付网站需要模型知道:

  • 什么时候先研究方向;
  • 什么时候该找真实参考;
  • 什么时候该原创;
  • 什么时候该复刻;
  • 什么时候该导入内容;
  • 什么时候做局部修改;
  • 什么时候必须审查;
  • 什么时候才可以发布。

把这些判断拆成 skill,再用 contract 和 gate 串起来,Idea2Site 才从一个普通的 AI 建站想法,变成一套可以长期维护的 Agent 工作流。

这也是我觉得这个项目值得整理成项目博客的原因。

它是一个关于 Agent 如何把模糊任务工程化 的例子。