Agent 在工位电脑上加班,我在地铁里用手机审批,拆解 Agents Anywhere 的跨端控制面
- 解决跨设备 Agent 控制问题,实现边缘执行、云端传话
- 自托管架构,不依赖云端,保护用户数据和权限
- 支持多种 Agent,提供结构化时间线和审批操作
- 五端实时一致,设计复杂,但架构先进
- 开源项目,源码可查,但发布成熟度有待提升
周五晚上七点,我约的人八点到。出门前往 Claude Code 里丢了个重构任务,心想一个半小时怎么也跑完了。地铁上想看看进度,掏出手机,傻了。没有网页,没有通知,只有 SSH。我在手机上开了个终端连回家里电脑,黑底绿字滚了一屏,跑到一半它弹出一个权限确认,问我能不能执行一条 rm。我盯着那行小字看了十秒,按了 y,然后后悔了一路,因为我根本没看清它要删什么。说真的,那十秒比任何一篇讲 agent 安全的文章都让我清醒。
大家好,我是若风。
这个场景你大概率也熟。2026 年了,coding agent 早就不是一问一答的玩具,一个长任务跑半小时很正常。人偏偏不会一直坐在电脑前,买杯咖啡的功夫,agent 可能已经把半个仓库改了。那问题来了,它跑到哪一步了,它要不要执行那条危险命令,它停下来问你了,而你在哪?
Agents Anywhere 想解决的就是这个。827 星,2026 年 5 月建仓,四个月,MIT 协议。一句话定位,一个跨设备的 Agent 工作台。Codex、Claude Code、DeepSeek Harness 三种 agent 在你的工作电脑上跑,你用手机、平板、Web 或者另一台电脑,看时间线、审批操作、传文件、开终端,人走到哪都行。
先立一个最重要的设定,Server 不跑 Agent。
执行发生在你自己的设备上,模型账号也是你自己的,它不代理你的 Claude 订阅,也不碰你的 API key。中间那层服务器只是个信箱加账本。这个设定决定了它和一堆云端 agent 平台的根本分野,后面会反复回到这一点。
现有方案都差点意思
看到这你可能想问,SSH 加 tmux 不是一直能用吗,搞这么大一摊是为了什么。
我把手上能用的路子摆一摆,差异就出来了。
| SSH + tmux | 官方云版 | Agents Anywhere | |
|---|---|---|---|
| 审批 | 终端里一行 y/n | 结构化卡片 | 结构化卡片,可回填选项 |
| 时间线 | 滚动日志 | 好 | 结构化,断线可续读 |
| 代码在哪 | 你的机器 | 平台云上执行 | 你的机器 |
| 能用哪家 Agent | 随便 | 只能自家的 | 三家随便切 |
| 自托管 | 无平台概念 | 不行 | Docker 一套拉起 |
官方云版的体验其实很好,但代码要传到平台侧的沙箱里跑。在公司写过代码的人都懂,不少仓库是连第三方云都不让碰的。SSH 方案倒是代码不出门,可审批就是终端里一个字符的确认,时间线就是你眼睛追滚动条,手机上操作等于受刑。自己拿各家 CLI 的 headless 模式攒一个?能做,但配对、鉴权、断线重连、多端同步,每一项都是一个小产品,攒完你会发现你重造了它。
别问我怎么知道的。
它的刀刃就在这三件事的交集上,agent 无关,执行不出你的设备,还能自托管。三个词单看都不稀奇,叠在一起就稀有。
三层架构,中间那层不干活
这是个 3400 个源文件的 monorepo。服务端是 Python FastAPI(server/),设备端连接器也是 Python(connector/),Web 端 Next.js(web-next/),桌面端 Electron(desktop-workbench/),iOS 是 SwiftUI,Android 是 Compose,五端齐活。服务端底下压着 26 张 PostgreSQL 表,Redis 负责协调。
这张图里最值得盯的是中间层的姿态。它对外只暴露一个 /api/v2 命名空间,REST 管配置和查询,WebSocket 管实时推送;对内,所有真正碰文件、碰进程的事都发生在 Connector 上。你想想看,服务器要是挂了,你的 agent 还在跑,只是没人给你递话了,不会出现平台一崩任务全没的情况。
服务端内部分了 core、services、infra、api 四层,services 层禁止 import FastAPI。这条规矩不是写在 README 里的口号,tests/test_architecture_boundaries.py 每次跑测试都在拦。一个四个月的项目肯给架构边界写守护测试,这个细节我挺有好感。
Connector 才是灵魂
多数人第一眼会看五端客户端,其实吧,这个项目最值钱的代码在 connector/ 里,就是跑在你工作电脑上的那个守护进程。它要回答一个特别难的问题,Codex、Claude Code、DeepSeek Harness 三家 agent 的接口、能力、历史存储方式完全不同,怎么用一套协议管起来。
答案是能力探测式协议。connector/runtime_protocol/protocol.py 里的 AgentRuntime 抽象类,三十来个方法全部默认抛 RuntimeUnsupportedError,每个适配器只覆写自己支持的部分,上层靠「方法有没有被覆写」来探测能力。为什么这么设计?因为三家差异大到没法一刀切,Codex 支持 steering(任务跑着还能插话),DSH 只支持单次审批,硬定一个全集接口,适配器写起来全是空方法,探测反而干净。
三个适配器的接法,一个比一个野。
Codex 走官方 openai-codex SDK,子进程由 SDK 自己管,connector 只负责把流式事件聚合成时间线条目,光聚合逻辑就有 connector/runtimes/codex/timeline/ 下 11 个文件。Claude Code 走 claude-agent-sdk,历史同步更有意思,它直接扫本地会话的 JSONL 文件,用文件指纹加消息游标做增量,配合两阶段的 prepare、publish、commit,解决了「数据发出去了、游标没落地」的经典难题。DeepSeek Harness 最特别,它不嵌 agent 本体,connector/runtimes/dsh/bridge/client.py 用裸 TCP 加 8 MiB 长度分帧的 JSON-RPC,连到 DSH 桌面端插件的 bridge 上,断线 5 秒轮询重连。
本地操作面也齐,说实话齐全得有点超出预期。文件读写限制在授权的工作区根目录里,fs.readText 默认 1 MiB 上限带二进制探测,fs.writeFile 用 sha256 做乐观并发控制;shell 支持一次性命令和后台任务,终止时 Unix 走进程组信号,Windows 走 taskkill /T /F;交互式终端是货真价实的 PTY,512 KB 回滚缓冲,最多 32 个会话,空闲半小时自动回收。坦白讲,这套东西单拎出来就是一个轻量版远程运维工具。
两处设计,是这个项目的硬骨头
五端实时一致,才是这个架构真正的成本所在。挑两处讲。
设备连着谁,租约说了算
服务端是可以多实例水平扩展的,但一台设备的 WebSocket 同一时刻只连着其中一个实例。那别的实例收到发给这台设备的请求怎么办?它的做法是给每台设备设一把 Redis 租约,键里写着 owner 实例和连接 ID,所有变更都是原子比较再写(server/agent_server/infra/connector_rpc.py)。请求落到非 owner 实例时,它查租约,把请求转发到 owner 实例的专属频道,owner 执行完再把响应原路发回来。心跳 60 秒,实例下线走排水流程,把在途事件处理完才放锁。
这段代码坦率的讲我不建议细读,取消语义绕得头疼,但思路本身值得记住,连接所有权不写进数据库,用一把可重建的 Redis 租约表达,实例挂了租约自然过期,不需要任何人工干预。
序号永不重复,靠号段租约
agent 是流式输出的,一条消息会裂成几十个增量事件,五端看到的顺序必须一致,还不能重不能漏。它的发号方案在 server/agent_server/services/session_revision_allocator.py,PostgreSQL 一次租一段 4096 个序号,日常发号用 Redis 自增顶着,Redis 万一重启,靠服务纪元号(server_epoch)识别出来,弃掉缓存重新租号,保证任何情况下客户端看到的序号无洞无重复。配套的还有出站合并,connector 侧 20 毫秒攒一批、64 条一批发出、指数退避封顶 30 秒(connector/server/ingest.py),服务端入站按会话排队,旧版本的事件直接丢弃。
这条链路画出来比说清楚容易。你只要记住一个感受就行,两个多月的 git 历史里塞着这种密度的一致性设计,说明作者之前一定被序号重复和事件乱序咬过,而且是狠狠咬过。
协议当契约管
还有一件事我必须提。仓库根部有个 contracts/ 目录,放着协议的 JSON Schema 和带 sha256 的清单文件。服务端从 Pydantic 模型导出(scripts/export_protocol_schemas.py),Web 端用 generate-protocol-types.mjs 从 Schema 生成 TypeScript 类型,测试夹具三端共享。协议版本 1.0、产品版本 2.0、数据库 schema 版本 v2_x,三套版本号各自独立演进。
我一直觉得多端项目最容易烂的地方就是协议,五端手写类型定义,三个月后必然漂移。它把协议当构建产物管,类型是生成出来的,不是抄出来的。当然代价也在那摆着,服务端和 connector 各自维护一份协议模型,靠契约测试对齐,这是个维护税,不是免费的午餐。
827 星背后的账
吹完了,账也得算。我读源码时专门找了一圈不舒服的地方,还真不少,说真的比预想的多。
最扎眼的一条在 server/agent_server/core/auth.py 第 17 行,_secret() 函数在没有配置 AGENT_SERVER_SECRET 环境变量时,会静默退回一个硬编码的开发密钥,不报错、不拒绝启动。自托管的人要是漏配了这一项,所有用户 token 和 connector 凭据理论上都可以被伪造。README 的部署命令里确实提醒了要替换密钥,但代码层面不设防,我觉得不够。
安全边界也得说说。文件操作的沙箱是路径前缀级别的工作区约束,但 shell.exec 说到底就是允许在这个目录里全权执行命令,约束的强度取决于你信不信跑在这个目录里的东西。另外终端中继的鉴权 token 走 URL 查询串传输,会进各级代理日志,这在安全审计里算扣分项。
发布成熟度呢,README 的下载表格看着很全,细看就有落差。iOS 只有 TestFlight 测试版,应用内更新的地址还是占位符,Windows 安装包没做代码签名,所有平台的更新全靠手动下载。安装包托管在 ModelScope,插件依赖 DeepSeek 官方的 npm 包,加上服务器落在中国大陆,能看出这是个深度绑定 DeepSeek 生态的中国小团队作品,主力就两三个人,浅克隆窗口里 147 个提交有 88 个来自同一位作者。git 历史还是嫁接的,0.1.x 整体推倒重写成 2.0,旧代码只留了个合并父提交,想考古是考不动的。
老实说还有一条最容易被忽略,它是免费的,但你的 agent 不免费。它不提供任何模型额度,Claude 订阅、Codex 套餐、DeepSeek 账单,全是你自己的。
账要算在自己头上。
这些放在一起,结论其实挺清楚的,这是个架构超前于发布成熟度的项目,源码值得拆,生产要掂量。
能带走什么
如果只记一个东西,我建议记它的架构姿态,我叫它「边缘执行、云端传话」。执行面留在边缘,代码、凭据、权限一样都不上云;控制面做成无状态的,可以水平加机器,设备归属用租约表达而不是写进数据库;两面之间只流通一种货币,结构化的事件流,而不是原始终端字节。你以后要做任何「东西在 A 处跑、人在 B 处管」的系统,远程工控也好、家庭实验室也好,这三条都是可以直接抄的骨架。
选型建议也直给。代码不能出门、又想在手机上管 agent 的人,这就是目前开源里最完整的一块板子,自托管时把 AGENT_SERVER_SECRET 配上,Docker 一套拉起就能用。想要开箱即用、iOS 正式版、自动更新的,再等等,它的发布工程还在追架构。想学多端一致性设计的,直接去读 session_revision_allocator.py 和 connector_rpc.py,比读十篇讲分布式协调的文章收获都实在。
agent 跑在工位上,人在地铁里,这条缝隙以前是靠 SSH 硬扛的。现在有人把它做成了一个正经的控制面,还把图纸全公开了。下次在地铁上再收到那条审批请求,你可以慢慢看清楚它到底要删什么,再按 y。

评论互动