我拆了一个 Agent 仓库,发现真正难的从来不是让 AI 会写代码

我拆了一个 Agent 仓库,发现真正难的从来不是让 AI 会写代码

我这两天翻一个 Agent 项目的源码,看到一个很容易被忽略、但技术上特别关键的区分。

run.completed,不等于 session.idle

前者只代表 Agent 的输出结束了,后者还要等持久化、重试、上下文压缩和订阅处理都真正收束。

就差这么一个状态,背后却是两种完全不同的产品思路。

一种思路是,模型把字吐完了,任务就算结束。

另一种思路是,模型只是完成了它的一段工作,系统还要确认工具有没有收尾、事件有没有丢、文件有没有写进去、会话能不能恢复,等这些都收束了,才敢告诉你,这件事做完了。

Agent 真正难的地方

这两年大家都在做 Agent。

模型越来越强,工具调用越来越自然,写代码、改文件、做表格、生成 PPT,演示视频里看起来都已经顺滑得不像话了。

但是你真的把它放进一个真实工作流里,很快就会发现,最麻烦的地方往往不是模型不会回答。

而是它回答完以后,谁来管它。

它能读哪些文件,能不能碰工作区外的路径,能不能直接执行一条 Shell 命令,改文件之前有没有给你看 Diff,模型请求的动作和真正获得的权限是不是一回事,任务完成和数据落盘是不是一回事。

再往后一点,网络断了怎么办,事件少了一条怎么办,模型换了怎么办,长会话超过上下文窗口怎么办,刚刚生成的表格和 PPT 能不能继续在精确选区上修改。

这些问题没有一个能靠多写几段 Prompt 解决。

我以前也会下意识地把 Agent 项目理解成三块东西,模型、工具,再加一个聊天界面。

这次翻完 Wordless 的代码以后,我觉得这个理解得改一改。

真正能拿来工作的 Agent,长得更像一个有权限系统、有事件协议、有本地数据库、有恢复机制的工作台。聊天只是它最外面那层皮。

从聊天窗口到工作台

Wordless 这个名字,翻译成产品口号就是,少说废话,把工作做完。

这句话听起来像一句很轻的产品文案,但顺着源码往下看,会发现它其实在约束整个架构。

它不是又做了一个只返回文本的聊天窗口,而是做了一个运行在 macOS 和 Windows 上的本地优先 Agent 工作台。

你选择工作区、模型和工作模式,Agent 在明确的权限边界里读取上下文、调用工具,然后把代码变更、电子表格、演示文稿、研究结果和媒体产物留在同一个工作界面里。

本地优先这件事也不是把数据留在本地这么简单。

Wordless 的工作区、会话和产物默认保存在设备上,Google 登录和云同步都是可选能力。没有登录,或者网络暂时不可用,本地工作不会跟着一起瘫掉。

这就带出了第一个很有意思的地方。

它没有把整个 Agent 运行过程塞进一个远程后端里。

在当前架构中,Electron 是桌面宿主,React Renderer 负责界面,Preload Bridge 负责暴露受限能力,Electron Main 负责可信的本地能力,@wordless/runtime 负责会话、运行和编排。

没有单独的本地 HTTP 后端,也没有单独的 Agent 进程。

链路大概是这样,React Renderer -> 受限 Preload Bridge -> Electron Main -> Wordless Runtime -> Profile -> Driver -> Pi 派生的 Agent loop -> Capability -> 产物工作台。

先把桌面边界立住

这个设计听着没那么炫,甚至有点朴素。

但桌面 Agent 最容易出事的地方,恰恰就是为了省事,把 Renderer 直接和 Node.js、文件系统、任意 IPC channel 连在一起。

一旦这样做,界面里一段看起来只是用户输入的文本,转眼就可能一路摸到本地文件、系统命令和凭据。

Wordless 的做法是,Renderer 通过 DesktopBridge 调用明确列出的能力,Preload 里使用白名单化的 wordless:* 通道,Renderer 不能自己拼任意 IPC channel,也不能直接获得 Node.js 权限。

权限不是弹窗,是执行前的边界

模型提出动作,不等于拿到权限

这个边界不是为了让架构图好看。

它是在提醒你,模型提出一个动作,不等于这个动作已经拿到了执行许可。

很多 Agent 产品讲工具调用时,喜欢把重点放在模型能调用多少工具上。

Wordless 反过来把一个更容易被忽略的问题放到了前面,工具到底在什么条件下才能真的执行。

这件事在 packages/agent-workspace-policy/src/index.ts 里写得很直白。

工具执行前会经过 preflightWorkspaceOperation

如果是 bash,系统会先拿命令去匹配 Shell 安全规则。当前会话不是完全放行,而且命中了规则,就需要用户确认。

如果是 writeedit,系统会读取文件当前内容,计算修改前后的预览,判断目标路径是不是受保护路径,然后把 Diff、匹配到的规则和文件基线一起放进审批定义里。

也就是说,模型说我要改这个文件,真正发生的流程不是直接写入。

更像是,先读一下,算出要改成什么样,展示给你,等你确认,再产生副作用。

这才是 Agent 和普通自动化脚本之间很大的区别。

脚本一般默认你已经写好了所有判断。

Agent 面对的是不确定的自然语言请求,它会自己选择路径、工具和下一步动作,所以它更需要一个会在关键位置踩刹车的系统。

默认访问级别下,工作区外的路径也不会悄悄放行。

如果一个工具请求里出现了工作区之外的 pathsourcePathoutputPathfilePathcwd,系统会把它识别出来,生成一次性的外部访问审批,告诉你哪些路径、什么操作、从哪个工作区发起。

这类设计看起来有点麻烦。

但你想想看,一个 Agent 如果能替你写文件,却不能让你知道它到底要写到哪里,那它越聪明,风险就越大。

审批要能解释,也要能追溯

Wordless 甚至会为已批准的文件写入保留基线。

这个细节很小,但我挺喜欢。

因为系统不只是记住用户点过同意,还记住了当时文件是什么样。后面如果要生成变更、恢复状态或者解释一次写入,至少有一份可追溯的依据。

安全不是多弹一个确认框。

安全是把动作、范围、理由和结果放在同一条链路里。

真正好用的 Agent,知道什么时候问

说到这里,可能有朋友会觉得,既然每一步都要确认,那 Agent 不就变得很慢了吗?

这个担心完全合理。

真正的桌面工作也不可能每读一个文件就让人点一次确认,否则人类很快只剩下无脑点允许。

所以 Wordless 不是所有操作都一刀切地拦住,而是把访问级别、工具类型、命令规则、文件规则和风险等级组合起来。普通的工作区内读取可以继续走,越过工作区边界、命中安全规则或者产生高风险副作用的动作,再回来找人。

它在自动化和可控之间留了一条缝。

这条缝很重要。

因为一个真正好用的 Agent,不是完全不问你,也不是每一步都问你,而是知道什么事情必须问。

上下文不是越多越好

上下文也是同一个问题。

很多产品为了让模型看得更多,转头就把整个项目、整个会话、整个文件夹一股脑塞进去,然后再祈祷模型能自己找到重点。

Wordless 的思路更接近精确引用。

Composer 里的 @ 可以引用工作区文件和文件夹,$ 可以选 Skill,PPT 可以引用具体页面或对象,Spreadsheet 可以引用当前选区,产物引用里还会带上 revision、surfaceId 和 locator。

这个设计对技术人来说特别熟悉。

它不是让模型拥有一个模糊的「你自己看着办」,而是尽可能把用户的意图编译成结构化上下文。

比如一个表格用户说,请把这个区域的公式改成按月汇总。

系统真正传给 Agent 的不应该只是这句话,还应该包含当前工作簿、工作表、精确选区和操作意图。

否则模型很容易把「这个区域」理解成整张表,然后顺手把旁边的数据也一起动了。

上下文越精确,模型需要猜的东西越少。

猜得越少,工具调用越稳定,Token 也更容易花在真正的工作上。

不同任务,不该共用一个万能 Agent

这也是为什么 Wordless 没有把所有场景都做成一个万能 Agent。

它有 General、Coding、Presentation、Spreadsheet 和 Data Analysis 这些 Profile。

Profile 不是欢迎语,而是工作边界

Profile 不是换一个欢迎语,也不是在系统提示词里加几个标签。

它会明确改变上下文、工具、权限声明、执行指导、产物类型和验证界面。

Coding 需要索引搜索、文件编辑、Shell、测试和 Diff。

Presentation 需要 OfficeCLI、质量扫描和可交互的 PPTX 预览。

Spreadsheet 需要工作簿选区、公式、图表、质量检查和发布流程。

Data Analysis 则需要按维度拆分研究、并行委派、追踪状态、保留来源和生成报告。

这些任务当然都可以被一个大模型用文字回答。

但如果你真的要把工作交付出去,它们需要的工具和验收方式完全不一样。

一个能写出代码的 Agent,不一定知道一张 PPT 的对齐问题,也不应该凭空拥有发布数据报告的权限。

所以,所谓多场景 Agent,不是复制五份聊天窗口。

而是在同一套运行内核上,装配五套更贴近任务的工作边界。

把底层模型和产品边界拆开

这里又会回到 Wordless 的一个技术取舍。

它没有重新发明一个通用模型循环,而是使用 MIT License 的 Pi Agent Harness 作为 Agent 底座,把自己的能力放在适配层上。

@wordless/ai 隔离 Provider 协议和模型能力。

@wordless/agent 负责 loop 和事件类型。

agent-driver-sdk 定义 Runtime 和具体内核之间的合同。

Coding Driver 只需要声明自己支持 steer、follow-up、thinking、compact、branch、commands、artifacts、approval 和 user-request,然后组装 Headless Coding Tools,再接入工作区预检策略。

这件事的价值在于,底层内核可以替换,桌面界面的会话、审批、存储和产物体验不必跟着一起重写。

很多 Agent 项目早期都喜欢把所有东西揉成一个大文件。

模型调用在里面,文件操作在里面,权限判断也在里面,连 UI 都被绑到某个上游事件长什么样。

一开始确实快。

等到要加第二个工作模式,或者换一个模型 Provider,或者把长任务搬到 Worker,整个人就会被历史包袱按在地上摩擦。

Wordless 现在的模块化单体路线,至少把这些变化留在了边界之外。

模块化单体听起来不像当下流行的微服务,但桌面软件里它是很务实的选择。

只要依赖方向清楚,运行时不依赖 Electron,协议不依赖具体 UI,能力服务不反向依赖 Profile,单进程也可以保持相当好的可替换性。

事件协议决定任务能不能恢复

再往下看事件协议,这个项目更像一个认真做过长任务的人写出来的。

Runtime 发出的每个事件信封里,会带上 protocolVersionruntimeInstanceId、全局唯一的 eventIdsessionId、可选的 runId、单会话递增的 sequence、时间戳和具体事件内容。

这几个字段不是为了给类型定义凑数。

它们分别回答了,当前事件来自哪一版协议,来自哪一次 Runtime 启动,属于哪个会话和运行,前后顺序是什么,以及界面该把它还原成什么状态。

如果 Renderer 发现事件序列出现缺口,它会重新请求一份新快照。

这就比「来一条消息就 setState 一下」靠谱多了。

因为真实世界里,消息可能被合并,进程可能重启,窗口可能晚一点才订阅,长任务也可能同时有工具、审批、压缩和子任务在跑。

相邻的文本和思考增量可以合并到下一帧再刷,工具完成、审批、错误和运行完成则要立即刷新。

该合并的合并,该立刻落地的立刻落地,而且不能把生命周期边界打乱。

这就是工程和 Demo 的差别。

Demo 只要看起来在动。

工程要保证它动完以后,状态还说得清楚。

输出结束,不等于会话空闲

前面提到的 run.completedsession.idle,就是一个很好的例子。

模型已经停止输出,只能说明 Agent 这一次调用结束了。

但持久化、重试、上下文压缩和订阅者处理可能还没结束。界面如果把这两个状态混在一起,就会出现很经典的假完成,按钮已经恢复可用,历史还没写好,用户下一条消息却已经进来了。

这种问题平时很难在演示里看出来。

一到网络抖动、机器休眠、长会话或者连续追问,就会开始冒出来。

历史、索引和凭据要各归其位

持久化层也没有把所有东西压成一个 JSON 文件。

Wordless 用 JSONL 保存追加式的 Agent 历史,用 SQLite 保存可查询的应用元数据。

JSONL 是会话历史的权威来源,记录完整消息、工具结果、模型和思考深度变化、上下文压缩、分支、Profile 身份和稳定的自定义条目。

SQLite 则负责设置、项目、可搜索的会话元数据、模型选择、凭据引用、产物索引和权限决定。

写入顺序也有明确约束,先追加并 flush JSONL,再更新 SQLite 索引。

启动时如果发现索引缺失或过期,还会根据会话头部和稳定条目进行重建。

这套设计的好处是,搜索很快,历史又不会因为一次索引写入失败就丢掉。

凭据不能混进会话

凭据更不能混在会话里。

API Key 和 OAuth token 在 AI 层之外由凭据抽象管理,Electron 的 safeStorage 负责加密,明文密钥不进入 JSONL、日志、协议事件、Renderer 持久化和 SQLite 元数据。

这部分没有什么花哨的模型能力。

但技术人应该知道,真正让一个 Agent 能进入日常工作流的,往往就是这些不适合放在发布会上的细节。

图片

别把路线图写成现成功能

当然,Wordless 也不是把所有问题都解决了,更不是装上以后就可以对着模型说一句「帮我把公司流程全自动化」然后躺平。

模型请求仍然会发送到用户选择的 Provider,发送范围取决于当前任务和显式引用的上下文。本地优先不等于所有数据永远不离开设备。

长任务仍然可能失败,模型仍然可能误解,工具仍然可能返回异常,自动审批也不应该被当成无风险模式。

当前产品是桌面端模块化单体,未来长时间运行或不稳定的能力可以迁移到 Worker,但这不是说今天已经有一个独立 Worker 集群在背后默默扛着。

这个边界说清楚,反而比把路线图写成现成功能更让人放心。

还有一个很容易被忽略的许可边界,Wordless 自己使用的是 Source-Available License,而不是 OSI 定义的开源许可证。个人、教育、研究、评估和非商业内部使用可以免费进行,商业使用、收费服务、SaaS、转售和商业托管需要事先获得书面授权。Pi、OfficeCLI 和其他第三方项目继续遵循各自的许可证。

这些信息看着有点扫兴。

但技术产品最怕的就是只展示能让人兴奋的那一半。

真正能长期使用的项目,一定也愿意把限制、成本和边界写在明面上。

给正在做 Agent 的人几个检查问题

所以,如果你自己正在做 Agent,我觉得不妨把问题往前挪一点。

别只问模型能不能多调用几个工具,先问它请求的动作和真正的执行权限是不是分开的。

别只问上下文窗口有多大,先问用户能不能精确指出当前任务需要哪几个文件、哪一页幻灯片、哪一块表格。

别只问流式输出看起来顺不顺,先问事件丢了一条以后,界面能不能从快照恢复。

别只问任务什么时候显示完成,先把输出结束、持久化收束和会话空闲拆成不同状态。

别只问数据库能不能存下聊天记录,先问历史、索引、凭据和产物是不是各自有清楚的归属。

这些问题,才是 Agent 产品走出 Demo 的分水岭。

把话说完,不等于把工作做完

过去的软件工程喜欢谈 API、状态机、事务和权限。

现在我们把模型接进来以后,这些词没有消失,只是换了一个更容易失控的入口。

模型可以帮你提出动作,但它不应该自动继承动作的权力。

模型可以帮你理解上下文,但它不应该替用户决定上下文的边界。

模型可以把一段文字生成出来,但系统要负责确认这段文字有没有变成真正可编辑、可验证、可恢复的产物。

从这个角度看,Agent 工作台更像一个有审批、有 journal、有回滚依据的本地操作系统,而不是一个更会聊天的输入框。

我很喜欢 Wordless 的地方,也就在这里。

它没有把「少说废话」理解成让模型少输出几个字,而是把过程播报交给界面,把模型的输出留给决策、结果和异常。

它也没有把「把工作做完」理解成模型回复了一句完成,而是继续追问,工具有没有执行,文件有没有落盘,事件有没有完整抵达,结果能不能被人检查,下一次还能不能从这里接着做。

这才是我觉得 Agent 产品真正有意思的地方。

模型能力的上限当然重要。

但决定一个 Agent 能不能进入真实工作流的,常常是那些模型之外的东西。

权限,边界,事件,存储,恢复,还有当系统不确定时,愿不愿意停下来问你一句。

以前我们担心软件不够聪明。

现在更值得担心的,是它已经足够聪明,却还没有学会什么时候不能自作主张。

所以,下一次你再看到一个 Agent Demo,不妨多问一句。

它能不能写出代码,只是第一关。

写完以后,谁批准它,谁验证它,谁保存它,谁能在出错以后把它找回来,这才是后面的世界。

至少,别让你的 Agent 只会把话说完。

要让它把工作做完。

以上,既然看到这里了,如果觉得这篇文章对你有点启发,随手点个赞、在看、转发三连吧。如果你也在做 Agent,欢迎从 docs/architecture/overview.mddocs/architecture/runtime-protocol.mdpackages/agent-workspace-policy/src/index.ts 开始看,很多真正有价值的答案,都藏在这些不太起眼的边界里。

谢谢你看我的文章,我们,下次再见。

相关推荐
webor20061 小时前
<六>ChatGPT到底叫什么?——语言模型
人工智能·ai·语言模型·chatgpt·claude
dunge20261 小时前
ChatGPT Plus / Pro + Codex 技术深度解析:从 API 集成到性能优化与实战案例
人工智能·chatgpt
ʜᴇɴʀʏ1 小时前
ICCV 2025 | STEP-DETR:基于超级教师与伪标签引导文本查询的半监督目标检测
人工智能·目标检测·计算机视觉·transformer
必须会一定会1 小时前
用纯 HTML/JS 做一个 AI 需求澄清器:把模糊想法转换成可执行任务书
开发语言·前端·javascript·人工智能·html·ai编程
HyperAI超神经1 小时前
基于 Strassen 与 LCMA 低复杂度矩阵乘,腾讯 FalconGEMM 探索超越硬件峰值的矩阵乘优化
人工智能·线性代数·矩阵·智能体·推理·ai编译器
DeepIntelli1 小时前
品牌百科词条建设:从词条命名到提交的完整技术指南
人工智能
MindUp1 小时前
企业网盘选型的技术评估维度与主流产品架构简析
人工智能·安全·架构
狂师2 小时前
用AI做自动化测试,哪些是真不行,哪些是你不会用?
人工智能·面试·测试
小鹿软件办公2 小时前
微软 MAI-Image-2.6 正式发布,文字渲染与 3D 能力显著增强
人工智能·microsoft