Agent X-Ray
RuntimeNotesAbout
Notes/产品经理/内容分享/第5章

远程控制自动化开发:一台手机驱动一座 AI 编码工厂

11 分钟 · 更新于 2026-09-01

远程控制自动化开发:一台手机驱动一座 AI 编码工厂

文档定位 这是一份"分享稿"——讲给同事 / 实习生 / 跨团队听众,用通俗的语言解释一套已经跑了 34 轮(约 200 个 user story)、做完一个完整个人知识库产品并免费部署上线的远程自动化编码流程。

配套的"工程沉淀"文档见 远程控制自动化开发流程——那边有所有真实配置、命令、踩坑细节;这里更偏故事、动机、隐喻和经验。


0. 开场白:为什么我做这个分享

我不是工程师。我是产品经理。

过去半年我做了一件听起来不可思议的事——仅用一部手机,在 34 个工作"轮次"里完成了一个完整的个人知识库产品的开发,并把它免费部署到了公网上

写代码的不是我。是一个跑在 Arch Linux 服务器上的 AI 编码循环。 告诉它要做什么的,也不是我直接告诉它的——是另一个 AI,先把我"在地铁上打的一句话"翻译成了几十条可执行的验收标准,再把它们扔进循环里去执行。

我的角色,只剩下两个

  1. 在飞书里说"我想要 X 功能"。
  2. 看 AI 回报的进度,判断要不要中止、改方向、或拍板上线。

这套流程不是魔法,也不是一个"agent"在做事——是五段链路、四个角色互相牵制的工程结果。今天我把它拆开讲。


1. 一句话总结

我用 飞书 当遥控器,vibe-remote 当中继站,Claude 当项目经理,Ralph 循环 当包工头,Codex 当编码工人,Encore Cloud + Cloudflare 当免费机房——把"想做一个产品"压缩成了"在地铁上发一句话"。


2. 谁在做事?六个出场角色

比喻:把它想成一个剧组 我是甲方(产品经理),下了一个 brief。剧组里:制片(vibe)+ 导演(Claude)+ 副导演兼场务(Ralph)+ 三个分别负责拍摄/审片/写场记的现场(Codex × 3)+ 后期发行(Encore Cloud / Cloudflare)。我只对接导演,其他人导演去管。

角色是什么我对它说什么它对谁交付
我(产品经理)唯一的人类"想要 X 功能 / 改 Y 体验"整条链路
飞书IM 平台直接发消息vibe-remote
vibe-remote本地消息桥不直接说话,只是转交Claude
Claude(Max 订阅)项目经理 / 规划者详细需求 + 约束 + 不做的范围把意图翻成 prd.json,启动 Ralph
Ralph 循环自主执行循环(一个 Python 脚本)不说话,只读 prd.json调度三个 Codex 进程
Codex(订阅)真正写代码的 AI(也可以换成 Claude)不说话,只读分配给它的 prompt 文件git commit
Encore Cloud + Cloudflare免费机房git push公网 URL

关键:六个角色全程不进同一个上下文窗口。 每个 Codex 进程被 spawn 出来时只知道自己这一份 prompt + 当前 user story 的验收标准,干完就退出。这是这套系统能稳定跑 34 轮的核心结构性原因。


3. 完整流程剧本:我在地铁上发了一句话之后

场景:周一早上 8:23,我在地铁里

步骤 1.我发消息

飞书私聊 @vibe-bot: "我想给知识库加一个语音笔记功能:录音、转写、自动 ingest 到 wiki。先做后端骨架,前端下一轮再做。"

步骤 2.消息穿越云端 → 我的服务器

飞书开放平台通过 WebSocket 把消息推给跑在 130 服务器上的 vibe-remote。vibe 把消息塞进当前飞书会话对应的那个 Claude Code 进程的 stdin。

这一步不经任何云中转 我的代码、我的服务器都在本地。飞书只是消息总线,不接触代码。

步骤 3.Claude 听懂了,开始规划

Claude 读完消息后做几件事:

  1. 产品规划/rounds/ 下写一份规划草稿(这一轮要做什么、不做什么、关键技术决策、验收标准的方向)。
  2. 把规划翻译成 scripts/ralph/prd.json——一个结构化的 user story 列表。每个 story 长这样:
json
{
  "id": "S198",
  "title": "新增 voice 服务,POST /voice/upload 接收音频",
  "priority": "P0",
  "passes": false,
  "blocked": false,
  "notes": "",
  "retryCount": 0,
  "acceptanceCriteria": [
    "新建 voice/ service 目录 + encore.service.ts",
    "POST /voice/upload 接受 multipart audio + 鉴权",
    "TypeScript 严格模式 npx tsc --noEmit 零 error",
    "encore test --run voice/ 全绿",
    "Commit `feat: [S198] - voice upload endpoint`"
  ]
}

关键转换:自然语言 → 客观可验证规则 "我想要语音笔记功能"是主观需求;acceptanceCriteria 是客观规则——能用编译器、测试、grep 来判断真假。Claude 在这里完成了"主观→客观"的翻译。

  1. 启动 Ralph:python3 scripts/ralph/ralph.py codex
  2. 注册一个飞书事件回推:vibe watch add ... -- bash watch_round.sh 35,让 Ralph 跑出来的事件自动回推到当前飞书话题。

步骤 4.Ralph 接管

Ralph 是一个最多迭代 50 次的 Python while 循环。每次迭代:

text
迭代 N 开始
├─ 第 1 步:Spawn 一个 Codex 进程当 Dev
│   - 读 prd.json,找最高优先级且 passes:false 的 story
│   - 实现它(写文件、改文件、跑测试、commit)
│   - 自报 passes:true
├─ 第 2 步:Spawn 另一个 Codex 进程当 Validator
│   - 完全不读 Dev 的上下文,只读 progress.txt 最后一条
│   - 跑 npx tsc / encore check / encore test 三道闸
│   - 通过 → 不动;失败 → 把 passes 改回 false,写 notes 失败原因
└─ 第 3 步:检查所有 story 是否完成或卡死
    - 都完成 → spawn 第三个 Codex 当 Summarizer,写本轮总结,循环结束
    - 否则 → 进入下一迭代

步骤 5.飞书提示叮一声

我刚出地铁,手机震动:

🤖 Ralph R35 watcher event: STORY_DONE: S198 (a3f29c1 feat: [S198] - voice upload endpoint) — 新增 voice 服务

我在咖啡店点单,发了一句"继续"。Claude 看到 STORY_DONE 事件,知道这一轮还在跑,回复"在跑 S199 的转写实现"。

步骤 6.大约 90 分钟后

🤖 Ralph R35 watcher event: ROUND_COMPLETE: round-35 digest written

这一轮 5 个 user story 全部跑完,Summarizer 已经把本轮成果写成 agent-rules/rounds/round-35-voice-io.md,并且把"已交付轮次"那一行追加到了 AGENTS.md

步骤 7.我决定要不要上线

Ralph 默认不 push——所有 commit 都留在 130 本机。我看 dashboard 的截图、看 progress.txt 里的 Validator 验收报告,觉得可以了,飞书发一句"push"。Claude 跑 git push origin main

GitHub webhook → Encore Cloud → Build → Test → Provision → Deploy。约 6 分钟后,新功能在 https://staging-knowledge-encore-vpzi.encr.app/ 可访问。

整条流程,我在飞书里说了 4 句话:发需求、说继续、说 push、看部署成功。


4. 这套系统为什么能跑稳?三个机制

机制 1:角色分离(不让一个 AI 兼任规划 + 执行)

业界常见的失败模式:用一个超大上下文 agent 一口气做"规划 + 拆任务 + 写代码 + 自我验证"。 长程 agent 跑着跑着就开始幻觉、跑偏、甚至自己改自己的验收标准来"通过"测试。

这套系统的拆法:

  • 规划 = Claude(看长上下文,做主观决策)
  • 执行 = 多个独立的 Codex 进程(短上下文,做客观完成)
  • 验证 = 又一个独立的 Codex 进程(不读 Dev 的上下文,只看输出)
  • 总结 = 再一个独立的 Codex 进程(写下一轮要继承的"项目地图")

比喻 像让出题人、考生、阅卷人是三个不能私下沟通的人——出题人定标准,考生闷头答,阅卷人按标准客观打分。如果让一个人同时干三件事,他会偷偷修改答案。

机制 2:状态机(让"完成"有客观定义)

prd.json 是这套系统的"宪法"——所有人都改它,但改的字段被严格规定

  • Dev 改:把自己实现完的 story passes 改成 true
  • Validator 改:通过则不动;失败则改回 false、写 notes、加 retryCountretryCount >= 5blocked: true 进死区
  • Summarizer:完全不改
mermaid
flowchart TD
    Start([Claude 写入 PRD]) --> A[待做]
    A -->|Dev 选中| B[实现中]
    B -->|Dev 标 passes=true| C[已自报]
    C -->|Validator 验收通过| D[已通过 ✓]
    C -->|Validator 失败<br/>记 notes 失败原因| A
    A -->|重试 ≥ 5 次| E[已卡死 🚫]
    D --> End([本 story 完成])
    E --> End

    classDef ok fill:#d3f9d8,stroke:#2f9e44,color:#1b4a25
    classDef bad fill:#ffe3e3,stroke:#c92a2a,color:#5c0a0a
    class D ok
    class E bad

"passes:true 不是开发者说了算" 这条是这套系统能信得过的根本——Dev 自报通过,Validator 用编译器和测试客观复核。中间不留任何"自评"空间。

机制 3:事件回流(让 AI 主动来找我,而不是我去问)

我没办法在飞书里 tail -f /var/log/ralph.log。所以系统反过来——Ralph 跑出有意义的事件时,主动推送给我。

watch_round.sh 是一个 bash 脚本,由 vibe-remote 在后台拉起。它做的事情很简单:每 30 秒看一眼 prd.json 和 ralph 日志,命中以下任一条件就退出并打印一行:

事件我的反应
STORY_DONE: S198 ...知道在前进,不动
ERROR_SIGNAL: <traceback / quota / 401>出问题了,进飞书会话问 Claude 详情
HEARTBEAT: round-35 alive after 1800s30 分钟没动静但还活着,不动
ROUND_COMPLETE / RALPH_EXITED_NO_DIGEST一轮跑完或挂了,决定下一步

vibe 接收这些事件并自动以飞书消息卡片形式投递回我所在的话题。整套系统对外只有这一个出口:飞书消息。


5. 一组数字(截至 2026-05-09)

  • 34 轮迭代,约 200 个 user story
  • 单轮平均 5-8 个 story,跑完约 60-180 分钟
  • 零现金成本:Claude Max(包月)+ Codex(包月)+ Encore Cloud Dev Environment(免费档)+ Cloudflare Pages(永久免费)
  • 已交付的能力:注册登录 / 个人知识库 / 增量编译 / DeepSeek + 多 LLM 接入 / chat + tool calling + SSE / 语义检索 / 公开订阅 / 移动端 PWA / 审计流水 / GraphQL 网关 / 语音 I/O / 图片附件 / 转写 / MCP 接入 / Inline AI 编辑 / Avatar 公开问答 / 多渠道发布 / Encore Bucket 对象存储……
  • 我看代码的频率:基本不看。看 progress.txt 的 Validator notes + 看 dashboard 截图就够了。

6. 一个具体案例:Round 34 的 ENOENT 大坑

背景

Round 5-33 一直用本地文件系统存 raw / wiki markdown,本地 dev 跑得好好的。

现场

2026-05-07 第一次部署 staging 成功。我在飞书里说"试试 ingest 一篇文章"。 回报:internal_message='ENOENT: no such file or directory, open /workspace/storage/<uid>/scheme/<sid>.md'

根因(Claude 帮我分析)

Encore Cloud 是无状态容器,pod 重启 / 多副本之间不共享本地盘。本地 FS 这条路从一开始就走不通。

解决(Claude 把方案翻成 4 个 user story 喂给 Ralph)

  • S194:把 kb/storage.ts 内部从本地 FS 改写成 encore.dev/storage/objects.Bucket,但 10 个公共 export 签名一行不动——Adapter 模式。
  • S195:5 个调用方移除 relative(repoRoot(), ...) 这种本地 FS 写法,改用新加的 relativeKbPath() helper。
  • S196:全量 encore test 跑红的测试逐个修绿(约 30+ 个测试要改)。
  • S197:写一个端到端 smoke 脚本,本地起 mock LLM + encore run,跑通注册→raw→ingest→query→chat 整链路,确认 ENOENT 没了。

数字

  • 耗时:~3 小时(包括 Validator 把 S196 打回过两次,Dev 修了 2 个文件)。
  • 我的输入:发一句话描述问题;中间被 Validator notes 提醒"S196 还有 4 个测试 fail 是因为 mock 路径写错了",我让 Claude 把这个细节加进 acceptanceCriteria 重启了一次循环。
  • 结果:4 个 story 全 passes、22 个 prod 调用方 0 改动、~30 个测试修绿、staging ENOENT 永久消失、Round 34 digest 自动写入仓库。

我没写一行代码。


7. 你能从这套流程里学到什么

7.1 给产品经理:这套思路怎么挪到你自己的工作

  • 把"主观需求"翻成"客观验收标准"是核心技能。即使你不跑 Ralph,光是逼自己把每个需求写成"npx tsc 零 error / curl /api/x 返回 200 / grep -c 'foo' file 输出 ≥ 1"这种规则,PRD 质量都会上一个台阶。
  • 用"角色分离"做需求评审:让评审者和提案者用两套独立标准看同一份 PRD(你自己提案、找另一个人挑刺),效果远好于自评。
  • 用"事件回流"做项目跟进:不是天天问开发"做完没",而是定义"项目状态变化时主动通知"——这就是 webhook 思维。

7.2 给工程师:这套架构里的工程巧思

  • 进程隔离 > 上下文隔离:每个 agent 独立子进程,崩了不影响别人,token 用量也按需。
  • 状态文件 > 内存共享prd.json + progress.txt 当 agent 间的"消息总线"——简单、可审计、可回滚。
  • 退出码 + stdout 当事件协议watch_round.sh 用退出码 0 / 2 / 75 + 一行 stdout 表达完整事件类型,比 webhook / queue 简单太多。
  • emit 在前,persist 在后:宁可重复通知也不能吞事件——这是分布式系统设计的基本功。
  • 二次校验产物存在:不要相信子进程退出码——exit 0 可能是真成功,可能是 quota 用尽假完成,diff 文件系统才是真。

7.3 给所有人:AI 协作的底层认知

一个反直觉的结论 AI 越长程越不可信。所以工程的目标不是"让 AI 一次干更多",而是"把 AI 的不可信压缩成短程可验证 + 异常可上报"。

这套系统所有的设计——单 story 切片、Validator 独立校验、watch heartbeat、Summarizer 二次校验——都在做这一件事。


8. 适合 / 不适合

适合

  • ✅ 个人项目 / solo 维护
  • ✅ TypeScript / 强类型 + 框架收敛(Encore.ts、NestJS、Spring Boot)的项目
  • ✅ 需求可拆成"30 分钟内可完成 + 有客观验收"的 user story
  • ✅ 有完整的本机开发环境(一条 xxx run 起所有依赖)

不适合

  • ❌ 多人协作 + 严格 PR review 的团队项目(直接 commit main 会冲突)
  • ❌ 需要 GUI 主观判断("这个按钮好不好看"AI 的 Validator 判别不了)
  • ❌ 弱类型 / 测试覆盖低的老项目(Validator 没有客观判据)
  • ❌ 生产风险敏感的关键链路(哪怕跑出来代码也要人审)

9. 想自己复刻?最小起步路径

阶段投入产出
0. 零成本试水跟着 Geoffrey Huntley 的 Ralph 原文(这套流程的灵感来源)跑一个小 demo跑通"循环 + Codex / Claude 写代码 + 自动 commit"
1. 加状态机prd.json + Dev/Validator 两个 prompt跑通"Dev 自报 + Validator 复核"
2. 加 Summarizer写第三个 prompt + 跨轮 round digest 索引跑通"多轮迭代不丢上下文"
3. 加飞书桥装 vibe-remote + 配飞书自建应用移动端能下指令、能收事件
4. 加云部署Encore Cloud(TS/Go)/ Fly.io(Python/Java/Go)+ Cloudflare Pages公网可访问
5. 复刻完成≈ 3-5 个工作日(按本指南 + 工程沉淀文档)自己的"AI 编码工厂"

10. 预期问答

Q1:跟传统 IDE + Copilot 比,效率到底高多少? A:不是"快多少",是"在线时长"差。Copilot 需要我坐在电脑前;这套流程允许我在地铁、咖啡店、晚饭后躺床上推进项目。一个产品经理一天里真正能在电脑前的时间也就 4-5 小时;这套系统让其他 19 小时也变成了可生产时段。

Q2:成本真的是 0? A:现金 0,订阅费 ≈ 全年 1 万人民币以内(Claude Max + Codex 双订阅,按个人节奏开关)。Encore Cloud / Cloudflare 的免费档对个人项目完全够用——这个项目跑了 34 轮,没付过一分钱给云厂商

Q3:Codex 写出来的代码质量行吗? A:单 story 粒度(30-90 分钟、20-200 行改动、有完整测试)下,质量稳定可用——重要的不是 Codex 多聪明,而是 acceptanceCriteria 写得多严格 + Validator 跑的客观闸有多多。Acceptance 写松了,AI 一定会偷工减料;写得严,AI 写出来的代码反而比我自己写的更规整(因为它从不偷懒省 typecheck)。

Q4:会不会有一天 AI 把代码改飞了我没察觉? A:会,发生过。两道防线:(1) Ralph 默认不 push——commit 全留 130 本机,要部署得我手动说"push";(2) Validator 跑全量 encore test——回归一定会被打回。真正出过事故的是"Validator 把验证写到错误 story 上"——靠改成按 id 精确匹配解决。

Q5:能不能把它用到机票 / 支付的工作项目上? A:原则上可以,需要做的改造:(1) 写一份 agent-rules/<framework>-rules.md 给 Java / PHP;(2) Validator 的客观闸要换成现有 CI(mvn test / phpunit);(3) 不直接 commit 主干——改成提交到 claude/round-N 候选分支,类似 OpenClaw 的 candidate-branch 方案,由我审核后再合到主干。

Q6:失败的轮次有没有? A:有。早期 Round 8 撞 Codex 的 usage limit、Round 17 watch 的 OOM 词汇误报、Round 25 验收标准歧义反复打架——这些坑都已沉淀成现在的过滤规则、心跳机制、Summarizer 二次校验。这套流程的 80% 工程价值,在跑过的 20 个事故里


  • 远程控制自动化开发流程(工程沉淀稿) — 配套的"硬核"文档:所有真实配置、命令、状态机定义、踩坑记录
  • vibe-remote 飞书桥接 — 飞书入口的具体实现
  • OpenClaw 能力索引 — 平行系统:另一种"飞书 bot 自动化"的实现路径,主打候选分支提交
  • Encore 研究摘要 — 后端框架技术选型背景
  • AI 协同工作站 — 整体 AI 基础设施总览
  • 产品经理如何打造 AI 协同工作流程 — 同类话题的另一篇分享
  • 上游灵感(必读):Geoffrey Huntley — Ralph
  • 项目代码:https://github.com/cking000bigdemon/encore-backend · https://github.com/cking000bigdemon/encore-frontend

本章目录
0. 开场白:为什么我做这个分享1. 一句话总结2. 谁在做事?六个出场角色3. 完整流程剧本:我在地铁上发了一句话之后4. 这套系统为什么能跑稳?三个机制5. 一组数字(截至 2026-05-09)6. 一个具体案例:Round 34 的 ENOENT 大坑7. 你能从这套流程里学到什么8. 适合 / 不适合9. 想自己复刻?最小起步路径10. 预期问答Related Documents
苏ICP备2025204887号-2