- NO.
- 005
- DATE
- 更新于 2026-06-12
- READ
- ~6 min
- STATUS
- 原文
和 AI Agent 一起搭站:我维护这个双语博客的工具流
不是让 AI 随便改代码,而是先给它一份可验证的边界——AGENTS.md、内容 schema、发布闸门,再加一套只能提议、不能擅自发布的自研 CMS。
这个站点从一个公开模板起步,现在是我自己长期用的双语博客。它的代码、内容和部署,基本都是我和一个 AI 编码 agent 一起做出来的。
但"和 AI 一起写代码"真正让它跑得稳的,不是模型多聪明,而是我花在边界和可验证流程上的功夫。模型会忘事、会自信地改错、会顺手"优化"掉你不想动的东西。所以这套工具流的重点不是放权,而是:把项目改造成一个 agent 可以安全操作的对象。
这篇是一次复盘。我会把这个仓库当成例子,讲清楚我是怎么搭这套流程的。如果你也想让 agent 帮你维护一个长期项目、而不是改完一片狼藉,这些应该能直接拿去用。
核心思路:先定边界,再谈效率
让机器改代码的瓶颈从来不是"它会不会写",而是"你敢不敢信"。信任不是靠人盯出来的,是靠把规则写成机器能读、能查的东西。
我把这套东西分成三层,由软到硬:
- 宪法:一份
AGENTS.md,告诉任何 agent 这个项目的形状、规矩和红线。 - 护栏:类型化的内容 schema 和一个锁文件,让"不该改的字段"改了就会在 diff 里现形。
- 闸门:一条 draft → 校验 → 构建 → 锁 → 人审 diff → push 即部署的发布链路,把"发布"变成一道需要人点头的关卡。
下面逐层说。
给 agent 一份"宪法":AGENTS.md
仓库根目录有一个 AGENTS.md。它不是给人看的 README,而是专门写给 AI agent 的上下文:项目是什么、用哪些命令、关键路径在哪、哪些规则不能破、设计红线是什么、发布流程怎么走、有哪些已知的坑、收尾前必须跑哪些验证。
它的价值在于:agent 接手时先读这份文件,继承我的约束,而不是自己猜。比如里面有这样的规则:
- 保持静态优先;JavaScript 只用来增强可用的 HTML,不是替代它。
- 加 UI 文案时,必须同时写进 zh 和 en 两份 messages。
- 加标签前,先把它写进每一个 taxonomy 文件。
- 不要提交 dist/、.astro/、node_modules/ 等生成物。
- 把 /admin/ 当成内容编辑器,而不是发布器。
写 AGENTS.md 的过程,本质上是逼自己把"我心里默认的规矩"显式化。一旦写下来,它对人和对 agent 都生效。
内容即数据,schema 即护栏
正文用 Astro 的 content collections 管理,每篇内容都有一份严格的 schema。机器生成的内容如果没有硬约束,会慢慢漂:少个字段、日期格式不一致、标签拼错。schema 把这些挡在构建之前。
更关键的是身份字段。一篇文章一旦发布,它的 URL 和身份就由几个字段决定:collection、locale、contentId、slug、pubDate、translationOf。我用一个 content.lock.json 把这些锁住——不是禁止改,而是让任何改动都在 diff 里显眼地出现,必须是我有意为之:
{
"collection": "blog",
"locale": "zh",
"contentId": "tooling-and-ai-workflow",
"slug": "tooling-and-ai-workflow",
"pubDate": "2026-06-09"
}
标题、描述、正文、标签这些日常字段随便改,不碰锁。只有动到身份字段,才需要刷新锁文件,而那份 diff 就是这次改动的"知情同意书"。
让"发布"变成一道闸门,而不是一个动作
写作时一律 draft: true。要让一篇内容真正上线,得走完一条链路,每一步都能挡住问题:
npm run content:publish -- --id my-post
# 一条命令完成:翻 draft:false、刷新锁文件、跑完整校验
# 然后人工审查 diff,commit 并 push 到 main——推送即自动部署
部署现在是 push 到 main 的自动结果,但"点头"并没有消失,只是挪到了更早、也更该它在的位置:agent 可以把内容准备到"只差一次提交",而审查 diff、决定 push 的永远是人。原来那个需要输入确认词的手动部署流程保留为兜底,用于重发和回滚。
其他高频小操作也照同样的思路收敛成了命令:新建草稿、给中英两份 taxonomy 同步加标签、给实质更新过的文章盖 updatedDate,各一条命令。阻力越小,越没有理由绕过流程。
自研 CMS:能编辑,但不能"替我做决定"
我没有用通用 CMS,而是写了一套很窄的:它能创建草稿、编辑普通字段、上传图片,但不能发布、不能撤稿、不能删除、不能改身份字段。这些都得走上面那条锁/校验链路。
生产环境里它写的不是主分支,而是 cms/<collection>/<contentId> 分支,并开一个 PR。换句话说——CMS 负责提议,人负责裁决。鉴权用一个只装在本仓库、权限最小的 GitHub App,再叠一层 Cloudflare Access 和邮箱白名单。
我要的不是"功能多的 CMS",而是"边界清楚的 CMS"。一个能帮我写、但不能替我拍板的工具,反而更敢用。
双语:不让两种语言互相污染
中英文用同一个 contentId 配对。缺译文时,语言切换会禁用不可用的那一侧,而不是拿另一种语言的正文兜底——读者不会在中文页面里突然撞见一段英文。
标签必须同时存在于中英两份 taxonomy 才能用。机器翻译的草稿会被标成 machine,并且带上源文的哈希;发布前必须人工 review、改成 reviewed,否则校验不让过。这条规则专门用来挡住"AI 翻完直接上线"。
验证是前提,不是收尾
这套流程里,每一次 agent 改动都以同一组检查结尾:内容校验、类型检查、构建、CMS 核心测试。"做完了"的定义是"验证通过了",而不是"看起来对"。
也有一些只能靠经验记住的坑,我把它们写进了 AGENTS.md:
- 可索引页面必须带
data-pagefind-body,漏了会被搜索悄悄丢掉。 npm run dev不生成搜索索引,本地测搜索要用专门的命令。SITE_URL错了,canonical、RSS、sitemap 会安静地产出错误的生产地址。
这些不是模型能凭空知道的,得写下来、让它读到。
最近一次收敛:把功能做小
维护这个站以后,我越来越倾向于让每个新交互只解决一个明确问题。比如访问统计不接第三方分析脚本,只在 Worker 的 KV 里记一个全站访问量和独立访客数;点赞不做账号体系,只做匿名反馈;正文里的术语解释也只用一个可聚焦的 span,不引入额外组件运行时。
这种做法的好处不是"功能少",而是决策面小。每个功能都能用几句话说清楚:数据写到哪里、失败时怎么降级、是否影响发布流程、是否会改变内容 URL。agent 参与时,问题也更容易被约束住:它要补的是一个闭环,而不是顺手长出一套系统。
所以我现在给 agent 的任务会尽量写成"收敛",而不是"发挥"。先把 footer、返回链接、访客统计、外链策略这些读者真的会碰到的小体验补完整;至于字体、复杂 notes、更多分析维度,先放进 roadmap。长期项目里,能被稳稳维护的小功能,比一次性堆起来的大功能更值钱。
设计也要有红线
视觉上我定了一条基线(GitHub Primer),并明确列出禁区:不引入重前端框架、不加外部字体、不把列表页做成图廊、保留功能性的青/蓝点缀、尊重 prefers-reduced-motion。
原因很实在:AI 特别喜欢"美化"。给它一点自由度,它能把一个干净的阅读页改成满屏卡片、渐变和悬浮特效。红线的作用,就是让无人监督的重构改不动阅读体验的根。
这套流程里,AI 擅长什么、不擅长什么
诚实说:
- 擅长:样板代码、规则内的重构、初稿、文档维护、机械的一致性检查、把内容准备到待发布状态。
- 需要盯:审美和设计取舍、身份/URL 这类不可逆决定、"该不该再加一个功能"的判断。这些我始终留在自己手里。
agent 把我从重复劳动里解放出来,但判断力没有外包出去。流程的设计就是为了保证这一点:让机器跑得快,让人在关键路口仍然必须点头。
一份可复用清单
如果你要让 agent 长期维护一个内容站,我会建议从这几件事开始:
- 写一份
AGENTS.md,把你的规矩和红线显式化。 - 把内容做成类型化集合,让 schema 在构建前挡错。
- 用一个锁文件保护身份/URL 字段,让误改在 diff 里现形。
- 收敛成一条验证命令,每次改动都以它结尾。
- 把发布做成一条可审查的链路,上线前永远经过一次人工点头。
- 给视觉定红线,挡住无监督的"美化"。
- 让你的 CMS 只能提议、不能裁决。
工具流不是为了让 AI 替你做主,而是为了让你能放心地把重复的部分交出去,同时把判断牢牢留下。
Ps: Claude Code 生成,已经过人工审阅。
评论
评论由 GitHub Discussions 提供。登录 GitHub 后即可评论。 前往对应 Discussion