双 Agent 协同:我是如何用 Hermes + Codex 从零搭建 CyanLabs 的
记录由 Hermes 负责架构调度与运维、Codex 负责高精度前端组件编写的现代全栈独立站自动化建站全过程。
你正在看的这个网站,就是我下面这段话的「产物」。它不是某个团队熬夜赶工赶出来的,而是两名 AI Agent 分工协作、从一个空目录里一步步搭出来的。这篇文章既是验收报告,也是操作手册——它把所有关键决策、协作细节和踩过的坑,原原本本地留在 CyanLabs 自己的
/ai专栏里。
为什么是 CyanLabs:一个「知识实验场」的动机
在动手前,先想清楚一个问题:为什么我要自建站,而不是丢到 Medium 或 Notion 上?
四个回答,全部指向「掌控感」与「零成本」:
- 多主题叙事——AI & 本地算力、摄影与光学、量化交易、生活省钱。这类跨度极大的内容,需要一个能各自成体系、又能统一品牌的内容架构。
- 极致 SEO 性能——静态站首屏几乎是秒开,Lighthouse 的 Performance 轻易拉满 95+,这对内容站是实打实的流量杠杆。
- 零服务器费用——在 Cloudflare Pages 上托管纯静态产物,等于把运维成本压到几乎为零,个人项目可长期躺平。
- 内容即代码——Markdown/MDX 当数据库用,配合强类型校验,永远不会出现「字段拼错但还能上线」的隐性事故。
但作为独立开发者,我只有一个稀缺资源:时间。所以真正的命题不是”要不要建”,而是”怎么用最少的工程人力把它建出来,还保持硬核质量”。这正是双 Agent 协同登场的理由。
① 架构选型:为什么是 Astro + Serverless
一句话:在「内容站点」这个赛道上,Astro 是静态生成领域的最优解之一,而且对 AI Agent 出码极其友好。
静态优先,动态靠内容集合
astro.config.mjs 里只做了一件事:output: 'static'。编译期把整个站点压成纯 HTML + 极简 JS,部署后没有 Node 进程、没有数据库连接、没有冷启动——这就是”零服务器费用 + 极致 SEO”的来源。
// astro.config.mjs
export default defineConfig({
site: 'https://cyanlabs.pages.dev',
output: 'static', // 静态生成,零运行时
trailingSlash: 'never',
integrations: [tailwind(), mdx(), sitemap()],
});
选它的三个硬核理由:
- Islands 架构:默认零 JS,只有交互组件才按需加载。文章页以纯 HTML 呈现,核心 Web Vitals 直接起飞。
- Content Collections:内容文件 + TypeScript 强类型契约,编译期就能抓出所有 frontmatter 错误。
- 对 Agent 极其友好:
.astro单文件组件 + Tailwind class 化,结构扁平,Codex 这类代码焊工可以零上下文污染地精准出码。
零成本的组合拳:Astro + Tailwind + MDX + Cloudflare Pages
这是条被验证过无数次的「独立开发者黄金路径」,每层各司其职:
| 层 | 技术 | 干的事 |
|---|---|---|
| 框架 | Astro 5 | 静态生成 + 路由 + Islands |
| 样式 | Tailwind CSS 3 | 深色主题、utility 化、零手写 CSS |
| 内容 | MDX | 在 Markdown 里写组件,文章即代码 |
| 类型 | Content Collections | schema 强类型校验 frontmatter |
| 托管 | Cloudflare Pages | 分布式边缘静态托管,按量近乎免费 |
关键洞察:没有选 Next.js 或 Remix。它们的目标是”服务端渲染应用”,对内容站来说属于用力过猛——为了运行时渲染而背负 Node 服务器成本,得不偿失。Astro 恰好在”内容为王”与”工程化深度”之间找到了平衡点。
② 角色分工哲学:Hermes(总指挥)× Codex(焊工)
双 Agent 协同的成败,不在于两个模型谁更强,而在于分工是否清晰。我给这次工程定义了这样一条铁律:
架构决策、文件拓扑、任务编排、验收回归——归 Hermes;精密 UI 组件的实现细节——归 Codex。
Hermes:架构总指挥 / 运维管家
Hermes Agent 的角色是全局最优。它负责顶层决策,但不陷入像素级实现:
- 拓扑规划:先建目录树(
src/pages/{ai,photography,trading,saving}/),再定配置文件(astro.config.mjs/tailwind.config.mjs/src/content/config.ts)。 - 强类型契约:定义内容 schema,是所有文章的前置校验——这正是「架构先行」的体现。
- 自愈闭环:跑
astro check+npm run build,哪里报错就地修复,保证”每条任务完成都是真的编译通过”。 - 任务派发:遇到精密 UI 就停下来,把需求「翻译」成 Codex 能零追问执行的任务书。
Codex:专业代码焊工
Codex 的角色是局部最优。它只接一个非常具体的组件任务,把像素级细节做到位:
- 专注单文件:拿到任务书后只创建目标
.astro,不越权改全局配置。 - 严格遵循 Props:精确实现
PhotoGrid/CardSummaryCard/QuantIndicatorPanel的接口与视觉规范。 - 自检交付:产出前自己跑
npx astro check,交付时逐项打勾验收清单。
为什么这样分?——“指挥官不必会焊焊点”
这个比喻最贴切:船长决定航线,焊工打磨焊缝。如果让总指挥去写每一行 CSS,上下文会被细节淹没,全局架构就开始漂移;如果让焊工去决定架构,他会执着于当前组件的完美而忽视整体一致性。双 Agent 的价值,正是把这两种副作用各自关在笼子里。
Hermes ──► 架构 / 任务派发 / 验收 / 自愈
│ ▲
component spec (任务书) │ compile ok?
▼ │
Codex ────► PhotoGrid / CardSummaryCard / QuantIndicatorPanel
③ 核心落地细节:强类型与任务派发流
Content Collections:把字段正确性提前到编译期
这是整个项目里我最得意的一处设计。src/content/config.ts 用 Zod 定义了四个独立 collection,每个都有专属字段:
// src/content/config.ts(节选)
const ai = defineCollection({
type: 'content',
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
publishDate: z.coerce.date(),
stack: z.array(z.string()).default([]),
hardware: z.string().optional(),
featured: z.boolean().default(false),
tags: z.array(z.string()).default([]),
}),
});
const saving = defineCollection({
type: 'content',
schema: z.object({
...articleFields,
bank: z.string().optional(),
annualFee: z.number().optional(), // 用于 CardSummaryCard 渲染
cardTier: z.enum(['travel', 'cash-back', 'points', 'business']).optional(),
}),
});
价值在哪? 举例:trading collection 的 strategyType 被约束为 enum;当某篇文章写错拼写了 trendd,npm run build 直接红字报错——在你 deploy 之前。这就是”内容即代码”的红利:文章数据有了类型,才有了可被机器理解和校验的资格。
沙箱安全机制:Agent 权限的最小化原则
多代理协同最怕「越权捣乱」。三个具体约束:
- 工具白名单:给 Codex 的任务书里限定”只写目标组件、不装依赖、不改 config”。
- 单文件出码:精密切面(如只建
PhotoGrid.astro),从源头杜绝污染面。 - 独立验收网关:Codex 交付后,Hermes 用统一命令(
npm run build)做收口回归,不合格就地打回。
Codex 任务派发流:从需求到可执行任务书
一个组件从需求到落地,经过了这样一条脱水链路:
需求(高层) → 拆解 Props 接口 → 规定 8 条视觉硬要求
→ 列硬性约束(纯astro/无script/无图表库)
→ 给验收清单 → 派发 → 回归
以 QuantIndicatorPanel 为例,任务书里会写死:主指标 text-4xl、夏普按 sharpe < 1 / 1–2 / > 2 分挡着色、回撤超过 20% 标红加 △、胜率用 CSS 宽度条而不是 canvas——把”美学判断”也翻译成了可执行的规则。这就是让代码焊工零追问开工的秘诀。
④ 自动化闭环:从本地自愈测试到 Git 自动上线
最后一环,是把「能编译」升级成「能稳定迭代」——一条从本地到线上的闭环流水线。
本地自愈测试
标准动作是 npm run build。它的意义不是出个 dist/ 那么简单,而是一次”全站体检”:
npm run build # Astro 编译全站,任一文章/组件报错即失败
任何 schema 违例、组件类型错误、MDX 语法问题,都会在这一步被拦截。站点上线后新增内容,只要 build 通过,就没有”上线了才发现坏了一块”的惊吓。
Git 版本归档
本地自检通过后,初始化仓库、打上语义化初始提交:
git init
git add .
git commit -m "feat: init CyanLabs — Astro + Tailwind + MDX 双 Agent 骨架与 AI 专栏首发"
.gitignore 里排掉 node_modules / dist / .env,保证仓库干净可复现。以后每一次内容更新、组件迭代,都成为一个可回溯的提交节点。
一键部署到 Cloudflare Pages
推 main 分支到 GitHub,Cloudflare Pages 自动接管:
| 配置项 | 值 |
|---|---|
| 框架预设 | Astro |
| 构建命令 | npm run build |
| 输出目录 | dist/ |
| 环境要求 | Node ≥ 20 |
从此改完 → build 自检 → push → Cloudflare 自动构建部署,一套纯自动、零服务器维护的上线链路。内容站的更新频率再高,也扛得住。
踩过的坑 & 给后来者的三条建议
- 别让总指挥写像素——全局决策和局部实现混在一起,是双 Agent 项目最大的坑。任务书里连”框架偏好(纯 .astro)“都要写清。
- 类型即契约,越早越好——Content Collections 的 schema 要第一个写,它是后面所有文章和组件的”法律”。
- 把验收做成命令——“完成了”不是 AI 说了算,而是
npm run build的退出码说了算。让机器当裁判。
结语:这场自动化建站的真正红利
回看整个过程,双 Agent 协同最大的收获不是”省了几天时间”,而是建立了一套可持续运转的内容工程系统:架构有契约、组件有任务书、上线有闭环。CyanLabs 上之后的每一篇新文章、每一次改版,都能在这套系统里被复用。
这个站点本身就是活着的证明 —— 你现在读到的排版、深色主题、四大专栏的骨架,都是这套工作流的产物。
下一篇文章预告:我会拆开
PhotoGrid的 Masonry 瀑布流细节,讲讲如何用 CSS columns 在纯服务端完成响应式图片墙——敬请期待。
本文由 DeepSeek-V4-Flash 驱动的 Hermes Agent 撰写,部署于 CyanLabs /ai 专栏。