读了一个开源 AI Agent 的源码后,我重新思考了"文件验收"这件事

6 阅读10分钟

不是项目推荐文。是读完一个 40 天、159 star 的开源 Agent 后,关于 Agent 工程里几个具体设计取舍的笔记。

先交代一下背景,免得误解。

我最近在翻一个开源项目:OpenWorkBuddygithub.com/CatCatUncle/openworkbuddy),一个本地优先的 AI 办公 Agent。它做的事是:你说一句话,它自己规划、调工具、验收,把 PPT / Word / Excel / 网页这些文件落到你磁盘上。

star 不算多,159 个。但它的代码结构对我有点启发,尤其是一个我原本没太重视的环节——文件验收

这篇主要聊三件事,都是我觉得值得单独拿出来讨论的设计问题:

  1. Agent 怎么知道自己"真的干完了"?
  2. 给 Agent 提权时,"档位"和"闸门"哪个更靠谱?
  3. 一个"装别人插件"的入口,安全边界应该划在哪?

一、"我完成了"——Agent 最不可信的一句话

先说一个我踩过的坑。

用 Agent 干活,最常见的翻车不是它做不出来,而是它说自己做完了。你去目录里找文件,没有。回头问它,它很诚恳地道歉,然后再说一遍"已完成"。

这个问题的根源不难理解:LLM 的输出是文本,而"文件写了吗"是一个外部世界的事实。这两者之间没有天然绑定——除非你在工程上强制绑定。

大部分 Agent 框架的做法是让模型输出一个工具调用(比如 write_file),工具返回成功,流程继续。这看起来已经闭环了,但中间有一个容易被忽略的缝隙:

工具返回"成功",不等于文件真的在磁盘上。

比如路径写错、目录权限不够、写入被中断、或者工具实现本身有 bug——这些情况下工具可能仍然返回一个看起来正常的结果,模型据此认为任务完成。

OpenWorkBuddy 的做法可以概括成一句话:

模型声称写了文件,就去磁盘上验;验不到,任务不算完成,退回重做。

这是个很朴素的思路,朴素到几乎不值得写出来。但它把一个"信任模型"的问题,转换成了一个"检查事实"的问题。这个转换本身才是关键——因为一旦你决定去磁盘上验,后面所有的工程动作都有了锚点。

我把这个思路抽象一下,它是可迁移的:

环节常规做法验收式做法
生成文件工具返回 200 即通过校验目标路径上文件真实存在且非空
生成图片返回 URL 即通过回读图片尺寸 / 解码是否成功
生成文档返回"已保存"即通过重新打开文档,核对结构完整性
修改代码返回 diff 即通过跑一遍编译或测试

核心区别是:验收的依据来自被改造的对象本身,而不是执行者的自述。

这个模式我认为普适性很强。任何"Agent 产出物 vs 不确定的执行过程"的场景,都可以套这个结构。而它最大的成本,往往只是多写一个检查函数。

二、权限模型:档位比开关更有用

Agent 要干活就得有权限。给权限这件事,我见过两种典型做法。

第一种是二元开关:要么全开(能执行任何命令),要么全关(只能聊天)。这种设计的体验是:全开时你心里发慌,全关时它什么也干不了。

第二种是逐条审批:每一个命令都弹窗问你。安全感拉满,但用半天你就崩溃了——审批疲劳之后你会开始无脑点"允许",安全性反而低于全开。

OpenWorkBuddy 用的是第三种:四档权限档位。

text

plan  →  只读不写,只能看和规划
ask   →  关键动作前征求同意
auto  →  常规操作自动执行,高风险动作仍拦截
full  →  完全放开

我觉得这个设计有意思的地方在于:它把"授权"做成了一个随任务切换的连续变量,而不是一次性的开关决定。

这里有个细节值得注意——它不是全局设置,而是每次调用可以单独指定

bash

openworkbuddy --perm plan "分析这份数据能得出什么结论"
openworkbuddy --perm full "把项目跑起来,自己修错"

差别在哪?我让 Agent 读一篇文章写总结时,plan 就够了,它连写权限都不该有。而让它自动修 bug 时,full 是必要代价。

同一个用户,在不同任务上需要的信任级别完全不同。 把权限绑到用户身上(要么都放开要么都收着),不如绑到任务上。

这个视角我觉得可以推广到很多 Agent 产品的设计里。权限的粒度不该是"这个用户可不可信",而应该是"这个动作值不值得信任"。

另外它还有一层闸门机制,和档位是并行的:命令审批、文件黑名单、URL 白名单、审计日志。

档位管的是"这一轮给多大自由度",闸门管的是"哪些动作无论如何不许做"。档位可以放宽,闸门不能突破——这两层分开,我觉得比揉成一个"安全等级"要清醒。

三、插件入口:一个被低估的风险面

第三个问题想聊清楚一点,因为它涉及一个很具体的安全设计。

OpenWorkBuddy 的扩展方式是丢一个 Markdown 文件进 skills/ 目录。这是它体验上最舒服的地方——加个能力不用改代码、不用重启、不用打包,存盘后下一条任务就生效。

但这个设计有一个隐含前提:你信任往这个目录里放文件的人。

因为一个 skill 本质上是什么?是把一段陌生人写的自然语言指令,接到一个能在你机器上敲命令的 Agent 上。

这个组合的风险等级,我认为比很多人以为的要高。它不是"读了一段文本"那么简单——文本会变成行动。

所以这个项目在安装前做了一层静态检查(34 条规则),其中 10 条是真拦:反弹 shell、curl | bash、读 SSH 私钥、磁盘擦除、痕迹清除这类直接挡下,其余的把原文摊给用户看。

但真正让我觉得有意思的,不是这个检查器做了什么,而是它怎么说自己。

项目公开写清了自己的检出率:公开标注集上约 74.9% ,判定"不建议安装"的准确率约 60.1% ——说白了,四个漏一个

并且给了一句我认为很实在的解释:

这就是静态检查的天花板,这也是强装入口必须保留的原因。

这句话把设计的取舍讲透了。

静态检查本质上是在用模式匹配去追一个对抗性的目标——恶意指令可以改写法、可以混淆、可以分散在多个文件里。只要攻击面是对抗性的,检测率就不可能收敛到 100%。承认这一点,然后据此保留"用户强制安装"的口子,同时把风险明确告知——这比宣称"我们全面拦截了恶意插件"要负责任。

我见过不少项目在安全能力上的表述是"已支持 XX 防护",具体检出率多少、漏判率多少,一个字不提。对使用者来说,这种模糊表述其实比明确写"我只有 74%"更难评估——因为你不知道该给它多少信任。

给出可量化的能力边界,本身就是产品成熟度的一部分。

顺带说一个实现细节:它的检查逻辑是基于行为组合而非关键词的。单独的 curl 不算问题,单独的 printenv 也不算;但同一个文件里既读取密钥又向外发送,构成完整外带特征时才拦。

这个思路比单纯的黑名单要聪明——黑名单的问题是误报高、绕过容易,而基于"读敏感数据 + 外发"这个行为组合来判定,鲁棒性会好很多。

四、几个顺带看到的工程细节

写完上面三块,还有一些零碎的点也值得记一笔,不算结论,算观察。

扩展成本的下限。  上面提到的 skill 机制,我认为它对二次开发者的价值被低估了。传统的插件体系要先定义 manifest、注册钩子、走生命周期;Markdown 技能跳过了全部这些,代价是表达力受限,收益是几乎零摩擦。对一个"想让用户自己造能力"的产品来说,这个取舍是划算的。

部署脚本不假装成功。  它的 Docker 部署脚本会等健康检查真正通过才报成功,起不来就把日志打出来。这是个小事,但"部署失败时明确告诉你失败"在很多项目里是要额外做的工作。

"离职闭环"这个功能的存在本身。  它把员工离职时要关的入口列出来:扫码连接的设备、名下定时任务、未使用的邀请码、绑定的二次验证、正在运行的任务。一个 Agent 一旦能自己执行任务、自己连设备,它就变成了一个需要被管理的主体。 "离职时怎么把它收回来"这个问题,我认为是 Agent 走向企业场景时必须回答的,而它在开源版里就给了答案。

运行过程有本地 Trace。  模型、工具、耗时、Token、输入输出全部记在本地,可选接 Langfuse。对调 prompt 的人来说,这个比日志有用。

五、我从中提炼的三条

如果只带走三句话:

1. 验收标准要落在被改造的对象上

不要落在执行者的自述上。模型说完成不算完成,磁盘上文件存在才算。这个原则适用于一切 Agent 产出。

2. 权限的粒度应该绑任务,而不是绑用户

用档位表达连续的信任级别,用闸门守住绝对底线,两者分开设计。

3. 安全能力要敢于给出量化边界

说清"我只有 74%",比说"我已全面防护"更可信,也更有用。


关于项目本身,补几句必要的信息,免得看着像软文。

它 2026-08-10 建仓,最新提交 2026-09-18,40 天内迭代了几十次,star 159。JavaScript 写的,Node 18+ 直接跑,零构建。协议是 PolyForm Noncommercial——个人、学习、非营利用免费,商用要授权。购买授权不解锁功能,因为只有一份代码,没有功能开关和灰按钮。

部署有三条路径:本机装(五步向导)、VPS + Docker(一条命令)、企业落地(SSO / 审计外送 / 内网 / SLA)。

想读代码的话,从 server.js 进去,再看 agent.js 怎么编排模型和工具,主要逻辑不长。

bash

git clone https://github.com/CatCatUncle/openworkbuddy.git
cd openworkbuddy && npm install && npm run app

本文所有数据取自仓库公开信息,获取时间 2026-09-19。

如果你也在做 Agent 相关的东西,尤其对上面"文件验收"那块有别的实践,欢迎评论区聊聊——我更好奇的是别人怎么解这个问题的。