OpenWorkBuddy 源码拆解:一个零框架 Agent 的主循环长什么样

找学习材料这件事,技术人大概都有同感:讲原理的文章很多,但真能拿去读的代码很少。

大多数 Agent 项目的源码,你读的时候要先做一层抽象解压——主循环藏在某个框架库里,工具注册隔了三层,构建产物和源码对不上。你读到最后,其实还是在读文档。

OpenWorkBuddy(github.com/CatCatUncle/openworkbuddy)是个例外。它是个纯 Node.js 项目,没有 TypeScript 编译、没有打包工具,源码就是运行的代码。作者在文档里直接给了读代码的路线:从 server.js 进去,看 agent.js 怎么编排模型和工具。

我把它的主循环顺着读了一遍,这篇是拆解笔记。不是教你用它,是带你看一个真实 Agent 的主干长什么样。

一、为什么"零构建"这件事对读代码的人这么重要

先看它怎么跑起来:

git clone https://github.com/CatCatUncle/openworkbuddy.git
cd openworkbuddy && npm install
npm start # 浏览器开 http://localhost:3800

改一行,刷新,立刻生效。没有 webpack 编译等待,没有 HMR 状态错乱,没有 source map 对不上。

这件事的价值不在"开发快",在"读的时候不用做映射"。

你在读大多数框架代码时,脑子里其实一直在跑一个后台进程:"我改的这个文件,真的被加载了吗?构建产物是哪一份?"。这个后台进程吃掉的是理解力。

零构建把这个后台进程关掉了。你可以非常专注于"这段逻辑到底在干什么"。

一个纯 Node.js、无框架的项目,读起来的心理负担和读一个三层构建链路的前端项目,完全不是一个量级。

二、主循环:一句话怎么变成一串动作

从 server.js 进去,看 agent.js,就是 Agent 的主干:

用户输入一句话 → 交给模型 → 模型返回"我要调某个工具" → 执行工具 → 结果回灌给模型 → 模型决定下一步 → …… → 判断"做完了" → 交付文件

这个循环本身不复杂,任何一篇讲 ReAct 的文章都能给你画出来。真正值得看的是它外围的那些判断:

什么时候该停下来问用户,而不是自己硬做?
工具执行失败了,重试几次?重试的时候要不要告诉模型"上次失败了因为什么"?
什么时候判定"任务完成"?判据是什么?

这些才是 Agent 产品的真难点,也是玩具 demo 里根本不会有的东西。

三、工具层:看 tools.js 怎么定义 40+ 个工具

tools.js 里是全部工具的接口定义。这是你要加自己业务工具时最短的路径。

值得琢磨的是它的设计取向。一个工具是怎么被定义的?入参怎么描述?返回值怎么组织?错误怎么表达?

我看到一个很重要的细节:它对于"做了但没做成"这种情况,不是靠抛异常来处理的。

这一点很关键。因为在 Agent 场景里,"工具执行失败"和"工具执行了但结果是坏的"是两回事。前者是物理错误,后者是需要模型理解并继续决策的信息。如果全都抛异常,模型就失去了继续判断的机会。

这个设计取舍,你在文档里看不到,只能在代码里看到。

四、权限层:一个"敢让 agent 动手"的项目该怎么设闸

这是我判断一个 Agent 项目成熟度的隐藏指标。

很多项目会告诉你"它能执行命令",但不会告诉你"它凭什么敢执行命令"。

OpenWorkBuddy 的做法是真拦,不是提示:

四档权限档位,最高可以到"每步都问"
命令审批:批的是那几行真实 diff,不是一句"它想改文件"
文件黑名单、URL 白名单
完整审计日志
改文件落盘前留底,整步回退能撤销

有一个细节我印象很深:它会判断命令"撤不撤得回来"。像 git reset --hard、docker volume rm 这种不可逆的,会先弹一张审批卡。

而更聪明的是这个判断的实现方式。它不只靠"命令名黑名单"——因为黑名单永远补不完(每加一条都得先有人被坑过)。它在名单之外还加了一道判断:这条命令跑之前先问一句"撤不撤得回来"。

这个思路值得学:当你没法穷举所有危险情况时,就换一个维度提问。

五、记忆层:一个容易被忽略的污染问题

它的记忆是双层的。但我觉得更有意思的是它对"记什么"的处理。

问题的本质是:agent 自己调 remember 记下的每一条,都会跟着往后每一趟任务进系统提示词。

也就是说,一条垃圾记忆会污染之后所有的上下文。

而原本拦它的只有两条正则,认的是措辞。这意味着换个说法就拦不住,像"这次把第 3 行改成了 8081"这种过程细节更是没有固定措辞可认。

它的解法是:写之前先问一句"这句话下个月还用得上吗",说用不上、而且确定度到 80% 就不收,顺带告诉它该改成怎么记。你自己亲手敲的那份记忆不归它管。

这个设计背后是一个很实际的判断:正则拦不住语义问题,得用语义方法拦。

六、安全层:技能安装这件事比看上去危险

一个技能就是一份给 agent 看的指令,接到一个能在你机器上敲命令的东西上——这跟 npm install 完全不是一回事。

npm 包你得 require 才会跑,而技能是 agent 会自己去读、会照着做的。

所以它装技能之前会先体检:过 34 条静态规则,然后把看到的摊开给你,落到三档——直接装 / 看一眼再装 / 默认不装。

其中 10 条真拦:反弹 shell、curl | bash、读 SSH 私钥、抹盘、抹痕迹这些。

作者写得很诚实:这不是杀毒,公开标注集上纯静态规则大概七成五。最后一条比所有规则都重要——装之前自己读一眼 skill.md,它是 Markdown,不是二进制。

能把"我做到了多少、我做不到什么"写清楚的作者,比吹到天上的靠谱。

七、读完之后我的三个收获

第一,Agent 的难点不在模型调用,在外围那一圈的判断。

模型调用那部分,任何框架都能帮你封装。真正难的是:什么时候停、什么时候问、怎么判断做完了、失败了怎么办、什么该记什么不该记。这些东西没有任何框架能替你做。

第二,能"顺手写一行就验证"的项目,学习效率完全不一样。

零构建看起来是个工程选择,其实对学习者是巨大的礼物。

第三,一个项目的变更记录,比它的功能清单更能说明问题。

我去翻它的更新记录,看到一条讲手机按钮热区的:

手机上那排键,手指得贴着连点两三次才中:390 宽的屏幕上量了一遍,50 个能点的东西里 9 颗不到 36px——发送键 32 见方,附件、侧栏、模型选择器全是 30 高。手指的接触面 8–10mm,落到 390 宽屏幕上就是 40px 上下。这不是"小了点",是同一个动作有时管用有时不管用,而人分不清是自己没点准还是应用没反应。

一条变更记录里包含了产品设计、人体工学、以及一个诚实的工程判断。这种东西,比读十篇"Agent 十大趋势"有用得多。

八、关于这个项目的几个事实
GitHub Star:目前 177
提交次数:410 commits
发布版本:48 个 Tag,当前 v0.9.0
内置技能 / 连接器:35 条 / 52 个
专家团:15 位专家、4 个团队
开发语言:纯 Node.js,零构建零框架
协议:PolyForm Noncommercial 1.0.0(个人、学习、非营利用免费;商用需授权)
独立项目声明:与腾讯公司及其 WorkBuddy 产品无任何关联

项目地址:github.com/CatCatUncle/openworkbuddy

作者:开发者猫叔
数据取自项目公开仓库与文档,统计时间 2026 年 9 月

posted @ 2026-09-23 01:47  大道无形1998  阅读(26)  评论(0)    收藏  举报