← Back to Blog
EN中文

Hephaestus:用 AI Agent 流水线解剖工业级 C++ 代码

大家好。如果你和我一样,对 Gitea 上那些沉睡的工业级 C/C++ 宝藏代码充满好奇——分布式系统、高性能网络库、反机器人引擎——但又苦于没有大块时间去逐行品读,那你一定能理解我启动这个项目的初衷。

手动分析代码,就像手工作坊,精致但无法规模化。我的目标是构建一个全自动的"代码考古学家"——一个永不疲倦的 AI Agent 系统,它每天自己去 Gitea 上"寻宝",深度阅读源码,提炼设计精髓,然后用另一种语言"复述"它的理解,最后把分析成果整理成结构化的技术参考文档,供我后续撰写博客时使用。

我给它起名 Hephaestus(赫菲斯托斯),希腊神话中的工匠之神。

上一篇文章中,我们搭建了 Docker + OpenClaw 的运行环境。今天跳过基础部署,直奔主题:Hephaestus 的多 Agent 架构设计,以及那些让我在深夜挠头的踩坑实录。

立规矩:给 AI 刻一块石碑

动手之前,我为 Hephaestus 写了一份 SOUL.md——不是普通的 system prompt,而是整个项目的"宪法"。里面有七条不可逾越的规则,其中最核心的四条:

  1. 净室隔离:绝对禁止泄露任何原始代码片段、函数名、命名空间、项目名称。所有分析必须基于理解,只展示自己亲手写的演示代码。
  2. 复述而非改进:演示代码的目标是让读者理解原始设计的意图和权衡。禁止暗示演示代码比原始代码"更好"或"更安全"。
  3. 禁止踩一抬一:不能说"Rust 解决了 C++ 的缺陷"。每种语言的设计都是在特定约束下做出的合理权衡。
  4. 语言轮换:每篇演示随机选择一种语言(Rust/Go/Zig/C++20/Python/Java/C#),且不连续使用同一种。

这些规则看起来只是几行文字,但它们直接导致了后面一系列有趣的挑战。

三 Agent 架构

单兵 Agent 难以胜任这种复杂的多阶段任务。Hephaestus 采用三 Agent 协作的流水线:

┌──────────────┐     ┌──────────────────┐     ┌──────────────────┐
│   Scanner    │     │    Analyzer       │     │     Writer       │
│ Gemini Flash │────▶│  Gemini Flash     │────▶│   Gemini Pro     │
│              │     │                   │     │                  │
│ Gitea API    │     │ Sparse Checkout   │     │ 中英双语参考文档   │
│ 目录+README  │     │ 深度代码分析       │     │ 自审+Git Push     │
│ → 选题索引   │     │ 净室演示+编译验证  │     │ → ref-output     │
└──────────────┘     └──────────────────┘     └──────────────────┘

Scanner(侦察兵,Gemini Flash)通过 Gitea REST API 轻量扫描仓库目录结构和 README,不 clone 代码。产出一份选题索引 TOPIC_INDEX.md,首次运行扫描了 3 个仓库,产出 35 个候选选题。为什么不 clone?因为目标仓库(某些大型 C++ 项目)动辄几十 GB,全量克隆会让系统在第一步就破产。Scanner 只带回地图和摘要,而不是把整座山都搬回来。

Analyzer(学者,Gemini Flash)是流水线核心。每 24 小时由心跳触发,从索引中选 2 个题目。用 Gitea API 或 git sparse-checkout 精准拉取目标子目录的代码。它遵循一套"四问检查清单"来解剖代码:

  1. 这段代码解决什么问题?
  2. 设计者为什么这样设计?
  3. 这种设计的代价是什么?
  4. 用另一种语言如何表达同样的设计意图?

答不出就跳过,换题。不发浅文。分析完后编写净室演示代码并编译验证——Rust 用 cargo clippy,Go 用 go vet,连续 10 次编译失败则转为失败复盘文章。

Writer(作家,Gemini Pro)由 Analyzer 通过 OpenClaw 的 sessions_spawn 机制委托。使用更擅长长文生成的 Gemini Pro,将分析成果整理为中英双语技术参考文档,执行自审(检查净室隔离、语气中立、技术深度),然后 git pushref-output 仓库。

踩坑实录

这部分才是正菜。任何自动化系统,Debug 的时间都远超写代码的时间。

坑1:SOUL.md 的"隐身术"

现象:第一篇产出完全是英文,格式全错,写作规则一条没遵守。精心设计的七条规则形同虚设。

排查:日志里 Agent 声称自己加载了 SOUL.md。我 exec 进容器直接 cat 了它读取的文件:

You're not a chatbot. You're becoming someone.
Your mission is to...

这是 OpenClaw 的默认模板,不是我的规则文件。

根因:OpenClaw 指示 Agent 从 workspace 目录(/home/node/.openclaw/workspace/)读取配置。我的 SOUL.md.openclaw 配置目录里,但 workspace 里是框架自动生成的默认版本。Agent 忠实地执行了——只不过执行的是别人的规矩。

修复:确保自定义 SOUL.md 被同步到 workspace 目录。一行 cp 命令,但这个 bug 花了我半天。

教训:永远不要假设 Agent 读取的配置就是你以为的那个。进容器亲眼看一下。

坑2:驯服语气——5 轮迭代

现象SOUL.md 位置修复后,文章质量飞跃——中文了,格式对了,有代码了。但字里行间仍然弥漫着"Rust 拯救世界"的味道。

问题:AI 模型在被要求"用另一种语言复述"时,天然倾向于分出优劣。"Rust 的所有权系统从根本上避免了 C++ 的悬垂指针问题"——技术上没错,但违反了"禁止踩一抬一"原则。

5 轮迭代

版本 策略 效果
V1 "Don't say Rust is better." 几乎无效
V2 "Focus on trade-offs." 好一点,但仍偏颇
V3 引入禁用词黑名单——"陷阱""隐患""优雅""更胜一筹"等词直接禁止 明显改善
V4 提供正向示例——"C++ 通过 RAII 管理资源,Rust 将检查内置于编译器,两种不同的设计哲学" 接近理想
V5 将分析框架从"语言对比"彻底转为"设计权衡"——所有讨论围绕"在当时的约束下为什么合理,代价是什么" 到位

最终效果:Writer 学会了用"中正平和"的学者语气,像讨论历史事件一样讨论技术决策,而不是当语言战争的裁判。这大概是整个项目中 Prompt Engineering 投入最多的地方。

坑3:sessions_spawn 的三重门

现象:Analyzer 调用 sessions_spawn 委托 Writer,日志显示调用成功,但 Writer 就是不启动。没有任何报错,静默失败。这是最让人抓狂的。

sessions_spawn 必须同时满足三个条件:

  1. 设备配对paired.json 必须存在且有效。容器重建后配对可能丢失,需要重新生成。
  2. Agent 白名单:调用方必须在配置中声明允许 spawn 哪些子 Agent:
    "subagents": {
      "allowAgents": ["writer"]
    }
  3. 沙箱关闭:OpenClaw 默认启用沙箱(Docker-in-Docker),在容器内再套容器会失败。必须显式关闭:
    "sandbox": { "mode": "off" }

任何一道门没开,sessions_spawn 都会静默失败。最折腾的是第三个——你很难想到一个"安全特性"会成为系统不工作的原因,而且它不告诉你为什么。

坑4:大仓库的求生之道

最初设计:Analyzer 直接 clone 目标仓库,本地分析。

现实:某些大型 C++ 项目的仓库动辄几十 GB。第一次尝试直接把磁盘和网络都打爆了。

最终方案:分层获取策略。

  • 扫描阶段(Scanner):严格使用 Gitea API,只获取目录树和描述文件
  • 分析阶段(Analyzer):从 TOPIC_INDEX.md 获取具体文件路径,用 sparse checkout 只拉目标目录
git clone --depth 1 --filter=blob:none --sparse \
  ssh://git@server:2222/owner/repo.git /tmp/repo
cd /tmp/repo
git sparse-checkout set src/target_module

--filter=blob:none 告诉 Git 只在需要时才下载文件内容,不预先拉取所有 blob 数据。原来要下载几十 GB 的操作,现在只需几十 MB。分析完后 rm -rf /tmp/repo,不留痕迹。

选题系统与自动化闭环

Hephaestus 的自动化分三个阶段运转:

  • Phase A(补充):当 TOPIC_INDEX.md 中待写选题 < 5 个时,自动触发 Scanner 全量扫描补充
  • Phase B(执行):每天从索引中选 2 个题目执行。选题规则确保仓库来源不同、关键词不重叠、演示语言不重复
  • Phase C(维护):自动更新选题状态(待写/已写/跳过)

整个流程由 OpenClaw 内置的 24 小时心跳机制自动触发,不需要外部 cron。参考文档 push 到 Git 仓库后,通过 Resend API 发送邮件通知。每天早上,邮箱里就能看到"代码考古学家"交上来的最新素材,我再基于这些素材撰写和发布博客文章。

"heartbeat": {
  "every": "24h",
  "model": "google/gemini-3-flash",
  "prompt": "读取 SOUL.md 和 HEARTBEAT.md,执行 Phase B..."
}

成果

指标 数字
首次完整运行耗时 1 分 34 秒
Token 消耗(三 Agent 合计) 177.9k
Scanner 产出 扫描 3 个仓库,35 个候选选题
每次心跳产出 2 份中英双语技术参考文档

写在最后

构建 Hephaestus 的过程,远不止是写几段 Prompt。从配置文件的"灵异事件"到反复雕琢 Agent 的"性格",从静默失败的子 Agent 委托到面对巨型仓库的求生策略,每一步都在重新定义我对 AI Agent 系统的理解。

它不是要替代人类思考。它是把繁琐的"读代码 → 提炼 → 整理文档"流程变成一条全自动的流水线,让我可以把时间花在审阅、思考和最终的内容创作上,而不是重复劳动上。

工匠之神不眠不休,每天准时交上高质量的参考素材。至于最终的博客,仍然由人来把关和书写——这大概就是人机协作最理想的形态。