Fabro 源码研究:把 AI 编码代理关进确定性流程的「软件工厂」

45 万行 Rust 的开源软件工厂 Fabro:Graphviz 图定义流水线、CSS 式模型路由、Git check...

引言:AI 编程的「人肉监督」困局

过去两年,AI 编码代理(coding agent)的能力突飞猛进,但用它干活的人普遍有一种别扭的体验:要么全程盯着它一步步操作,要么等到它交出一份五十个文件的巨型 diff,然后对着这份「你不敢信任的改动」逐行审查。前一种浪费时间,后一种提心吊胆。业界管这个阶段叫 prompt-act-review 循环——它本质上没有定义一个可重复的软件流程,只是把「写代码」这件事变成了一次次无法复用、难以审计的即兴对话。

Fabro(GitHub: fabro-sh/fabro)试图给出第三条路:把流程本身写成代码,让代理在图里执行,人只在关键节点介入。它自称「为专家工程师打造的开源暗色软件工厂」(the open source dark software factory for expert engineers),MIT 协议,单一 Rust 二进制,零运行时依赖。这个仓库非常值得细读——不是因为它多炫,而是因为它在「确定性流程」和「不可预测的 LLM」之间做出的工程取舍,恰好是这一代 AI 软件工程的核心命题。

一、Fabro 是什么:一张图说清楚

Fabro 的核心模型极其简单:用 Graphviz DOT 语法定义工作流图,每个节点是一个阶段(agent 对话、命令、条件分支、人工审批闸门、并行组),每条边携带条件与标签,代理按图执行,人在需要决策的地方按 A(批准)/ R(修订)。

官方 README 的示例就是经典的 plan-approve-implement 流程:

digraph PlanImplement {
    graph [
        goal="Plan, approve, implement, and simplify a change"
        model_stylesheet="
            *        { model: claude-haiku-4-5; reasoning_effort: low; }
            .coding  { model: claude-sonnet-4-5; reasoning_effort: high; }
        "
    ]
    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare, label="Exit"]
    plan      [label="Plan", prompt="Analyze the goal and codebase. Write a step-by-step plan.", reasoning_effort="high"]
    approve   [shape=hexagon, label="Approve Plan"]
    implement [label="Implement", class="coding", prompt="Read plan.md and implement every step."]
    simplify  [label="Simplify", class="coding", prompt="Review the changes for clarity and correctness."]
    start -> plan -> approve
    approve -> implement [label="[A] Approve"]
    approve -> plan      [label="[R] Revise"]
    implement -> simplify -> exit
}

这段图定义里浓缩了 Fabro 的五个核心设计:

  • 流程即代码:DOT 文件可 diff、可评审、可版本控制,团队的软件流程像源码一样被管理;
  • 人机分工:六边形节点是人工闸门,代理跑到这里停下来等人决策——不再需要「全程盯梢」,只需要在关键点把关;
  • 模型路由:CSS 风格的 stylesheet 让「规划」走便宜快速的小模型、让「写代码」走前沿大模型,成本和质量分别控制;
  • 修复回路:图中显式画了 Revise 循环——代理实现的产物不符合要求时自动回到 Plan,而不是把烂结果交给下一个阶段;
  • 确定性验证层:测试套件、linter、类型检查、LLM-as-judge 都可以作为节点挂进图里,失败自动触发修复循环。

二、工作流引擎:把图变成执行

Fabro 的仓库是 Rust workspace,规模惊人:1085 个 Rust 源文件、约 45 万行代码(截至 2026 年 8 月,版本号已到 0.315.0-nightly)。核心 crate 分层清晰:

  • fabro-workflow:工作流引擎。解析 Graphviz 图、驱动阶段执行、管理 checkpoint 恢复、钩子(hooks)与人在环交互;
  • fabro-agent:AI 编码代理会话(单文件 6126 行),工具集为 Bash、Read、Write、Edit、Glob、Grep、WebFetch——经典 agent 工具面;
  • fabro-sandbox:执行环境抽象,提供 Local、Docker、Daytona 云 VM 三种提供者;
  • fabro-graphviz:DOT 解析器、渲染器、stylesheet 解析与保真度校验;
  • fabro-llm:统一 LLM 客户端,支持 Anthropic、OpenAI、Gemini 与 OpenAI 兼容端点,带重试/中间件/流式;
  • fabro-checkpoint:Git 检查点,每个阶段把代码变更与执行元数据提交到独立分支;
  • fabro-server:Axum HTTP 服务,REST + SSE 事件流 + 内置 React Web UI。

值得一提的执行细节:边的选择支持条件表达式——引擎先评估所有出边的条件,条件命中的边优先,其次才按人工选择的标签(如 [A]/[R])匹配。这是一个「确定性优先、交互兜底」的优雅设计:能自动判断的绝不停下来问人。

三、多模型路由:把便宜模型用在刀刃上

Fabro 对成本的态度非常务实。stylesheet 语法类似 CSS 选择器:* 匹配所有节点做默认配置,.coding 匹配打了 class 的节点。一行改动就能把整个工作流的模型策略调优,还支持自动故障回退链——主模型不可用时按配置降级。

这是「ensemble intelligence」的工程化:同一个工作流里,一个模型负责实现、另一个模型交叉批评、第三个做总结。对团队来说,这意味着模型选型从「开会决定」变成「改一行配置」,也意味着 token 账单可以精细管理:高频低价值的节点(plan、summarize)跑便宜模型,真正吃推理的节点(implement、simplify)才上旗舰模型。

四、沙箱与隔离:把不可信代码关起来

代理写出来的代码是「不可信代码」,跑在笔记本上等于把风险带进生产环境。Fabro 的沙箱设计分三层:

  • LocalSandbox:本地进程,适合信任的快速任务;
  • DockerSandbox:默认运行时提供者,基于镜像创建 /workspace 容器,网络与文件系统隔离;
  • DaytonaSandbox:云端 VM,快照式初始化、网络控制、自动清理——把执行彻底挪出笔记本,支持大规模并发。

调试体验是它区别于普通沙箱的亮点:fabro sandbox ssh 可以实时 SSH 进入运行中的沙箱,fabro sandbox preview 可以把沙箱内端口暴露成预览链接——代理在容器里跑,工程师在浏览器里看效果,这是「人在环」在调试环节的落地。

五、Git Checkpointing:每一步都可回退

Fabro 把「可审计」做到了 Git 层面:每个阶段结束,代码变更与执行元数据(作者、目的、阶段信息)以 Git trailer 的形式提交到独立分支(元数据分支以 fabro/meta/ 为前缀)。这意味着:

  • 任何一次运行都可以恢复(resume)、回退(revert)、追踪(trace);
  • 每次变更的「为什么」随提交一起保存,审计时能看到的不只是 diff,还有当时的执行上下文;
  • checkpoint 与沙箱的快照式初始化配合,让「从上次进度继续」变得廉价。

六、可观测性:事件流是唯一的真相

Fabro 内部有专门的文档(event-schema-v2)阐述事件架构的取舍,读起来很过瘾:单一规范化的持久事件日志(one canonical persisted event log),而不是「业务表 + 审计表」双写;RunEvent 是语义事件类型,序号 seq 放在存储/API 信封里,回放靠有序的 since_seq 游标;事件信封为执行拓扑扩展了 stage_id、parallel_group_id、parallel_branch_id、tool_call_id——把一次工具调用都能关联到图里的具体节点。

更难得的工程判断是:手写 Rust 结构体就是事件契约的真相源,明确拒绝 schema 注册表/代码生成;TypeScript 类型、JSON Schema、OpenAPI 片段都只是次级产物。项目里还有一份竞争分析文档(event-schema-competitive-analysis),对比了其他平台的事件方案——这种「先想清楚再动手」的文档文化在开源项目里相当少见。

七、工程实现与质量文化

从工程角度看,Fabro 是当代 Rust 全栈的范本:

  • API 契约驱动:OpenAPI 规范是 HTTP 接口的真相源,build.rs 用 progenitor 从规范生成 Rust 类型与客户端,服务端路由与规范漂移会被 conformance 测试抓住;TypeScript Axios 客户端同样从规范生成——一份契约,三端消费;
  • 测试基建讲究:test/twin 目录提供了 OpenAI 与 GitHub API 的本地「测试替身」(twin),E2E 测试不依赖外部服务;evals 目录挂接了 SWE-bench 评估;测试辅助代码用 feature gate(test-support)隔离,绝不进生产构建;
  • 供应链严谨:发布二进制与多架构 Docker 镜像携带 SLSA Build Provenance 证明,可离线验证产物确实由官方 GitHub Actions 构建;
  • 发布节奏:0.315.0-nightly 这样的版本号说明它走 nightly 预发布 + 稳定版的自动化节奏(cargo dev release 一键打 tag);
  • 决策文档文化:docs 下有 brainstorms/、ideation/、internal/ 分类——从「是否需要 scratch 制品缓存」到「事件 schema 要不要引入 reducer 契约」,每个设计决策都有完整的背景、取舍与结论记录。

八、对软件工厂赛道的观察与思考

Fabro 不是孤例——「AI 软件工厂」正在成为 2026 年基础设施层最拥挤的赛道之一:确定性流水线 + 代理执行 + 人在关键节点介入 + 全链路可审计,几乎是共识配方。作为对照,我自己的 ForgeFlow 项目也在做同一件事:需求 → AI 拆解实现 → 静态分析 → 按项目类型自动选编译工具链 → 测试 → 修复迭代 → 门禁评估 → 内容寻址发布清单,用 Jenkins 做调度。Fabro 与这类系统的差异很有意思:

  • 图模型 vs 阶段模型:Fabro 用完整的 DAG(分支、循环、并行、条件边)表达流程,传统工厂大多是线性/树状阶段;图模型表达力更强,代价是学习曲线——不过「流程即代码」意味着团队可以像维护源码一样演进它;
  • 嵌入式场景的适配:Fabro 的 agent 工具面偏通用代码库操作,对固件/嵌入式特有的交叉编译链、烧录、硬件在环(HIL)测试没有原生概念——这恰好是嵌入式软件工厂的差异化空间;
  • 验证层的确定性:两边都认同「确定性验证 + LLM 修复」的组合拳——测试套件、静态分析是裁判,LLM 是选手,裁判不能是选手的幻觉;
  • 事件与审计:单一日志 + seq 回放 + 拓扑关联的设计,与工厂场景的「证据可追溯」需求完全同构。

九、局限与挑战

Fabro 也有明显的不确定之处:45 万行 Rust 的维护成本不低;nightly 节奏下 API 与配置的稳定性需要观察;沙箱依赖 Docker 守护进程(文档明确说明这等价于宿主机 root 权限,只适合可信单租户部署);对 GUI 型工作流(如硬件工具链、烧录器交互)的支持有限。另外,图定义虽可版本控制,但「流程图的复杂度」本身会随团队规模膨胀——如何避免流程图变成无人能维护的意大利面,是所有图驱动工作流平台的共同考题。

结语

Fabro 真正值得学习的地方,是它对「信任」的工程化处理:用图定义边界、用闸门定义决策点、用 checkpoint 定义可回退性、用事件日志定义可审计性、用沙箱定义风险隔离——把 LLM 的不可预测性关进确定性的笼子里,然后让专家工程师只做机器做不了的事:在关键节点按下 A 或 R。对任何想把 AI 代理从「玩具」变成「产线」的团队,这份代码库都是一份高质量的参考答案。

(本文基于 fabro-sh/fabro 仓库 2026-08-05 主分支代码研究写成,数据截至当日。)

Leave a Reply

Your email address will not be published. Required fields are marked *