我希望把日常对话、QPC 知识库与日历逐步放进一个个人助理,同时控制小型 VPS 的资源占用。已有 Hermes 网关正在使用另一只 Lark 机器人。这个实验的目标是暂停 Hermes,在同一台共享小机上尝试运行 OpenCode,并使用 personal-assistant 的机器人验证接管链路。
**同日补充:**第一次窗口结束前的消息被中断;经再次授权,重开受保护的短时窗口后,真实 Lark 两轮私聊均收到回复,第二轮正确使用了前文。模型任务期间的内存峰值和压力依然偏高,尚不能据此判断适合在这台小机上长期常驻。
这次实验的边界很窄:测试短时对话、资源和回退;QPC 与日历不是这次已经实现的能力。两只机器人独立,暂停 Hermes 会暂时影响原机器人,不会自动把它的会话和权限迁移到新机器人。
为什么不能只比较一个 RSS
在决定切换前,观察到 Hermes 主进程的一次 RSS 约 341 MiB,另有进程数据进入 swap。本机 WSL 中 OpenCode 空闲服务的主进程 RSS 大约 224–262 MiB。但 Hermes 当时正在承担实际网关工作,OpenCode 的本机测试没有接真实 Lark 或模型。不同机器、不同负载和不同统计口径不能直接得出完整替代方案的节省量。
共享实例约有 952 MiB 可见内存,Hermes 运行时多次采样的可用内存只有一百多 MiB,还有明显 swap 使用。相比直接叠加一个服务,先暂停旧网关、在相同机器上测量完整链路,更接近实际问题。
把切换做成可回退试验
方案是由已有的轻量 Lark 入口负责本人身份检查、消息去重与回复状态,OpenCode 仅在本机回环地址提供模型对话接口。服务使用非特权用户、单独工作目录、内存和 CPU 限额;OpenCode 工具权限默认拒绝,试验不开放文件修改、Shell 或其他外部动作。模型凭证和机器人凭证分开提供,不放入仓库或文章。
切换前设置了十分钟自动回退,并持续观察内存余量、内存压力和关键服务状态。试验失败或达到时限时,停止试验服务,恢复 Hermes gateway 和 A2A bridge。两个服务独立恢复,是因为 bridge 没有声明会自动跟随 gateway 的依赖关系。
对话适配器每轮创建独立 OpenCode 会话,只加入已确认送达的有限历史;调用超时不自动重试。模型回答和 Lark 成功投递分开记录。OpenCode 自身会在状态目录写入会话数据,尝试调用 API 删除会话并不等于证明底层数据被彻底擦除,因此试验使用独立目录并在结束后清理。
两次启动失败
第一次启动遇到 systemd 226/NAMESPACE。逐项检查发现,PrivateTmp 隐藏了放在 /var/tmp 下的试验目录,使可写路径与工作目录无法同时建立。移除这一配置并保留非特权用户和其他文件系统限制后,最小短命进程能够正常启动。
第二次启动时 OpenCode 需要创建临时目录,但严格只读文件系统不允许写默认的 /tmp。为试验单独配置可写的 TMPDIR 并验证之后,OpenCode 健康检查通过,personal-assistant 机器人建立了 Lark 长连接。两次失败都触发了回退,Hermes 随后恢复。
同机观察
一次暂停 Hermes 后,主机可用内存约为 550–578 MiB。两项试验服务连接成功后的一次空闲采样中,OpenCode 的 cgroup 内存约 236 MiB,Lark 入口约 34 MiB,主机可用内存约 373 MiB;OpenCode 当次 cgroup 启动峰值约 272 MiB,Lark 入口约 43 MiB。这是短时采样,不能代表全天峰值,也不能把两个单独峰值简单相加视为同一时刻的总峰值。
随后用一条合成消息调用了配置的真实模型,OpenCode 返回了预期内容,耗时约 24.7 秒;响应报告的 token 总数为 1979。这是一次请求的观测,不代表长期平均成本,也不能证明包含了服务内部所有额外调用。
另外构造了一段已送达的合成历史,再向真实模型询问其中的代号;回答正确,耗时约 4.5 秒,响应报告 2013 tokens。这验证了适配器将短历史交给模型的路径,不能替代真实 Lark 多轮验收。
真实模型调用后的一次采样显示,OpenCode cgroup 内存约 359 MiB,达到配置的 360 MiB 上限附近;当次还用了约 68 MiB swap,memory.events 中 max 计数增加,而 OOM 和 OOM kill 仍为 0。主机当时可用内存约 263 MiB,memory full PSI 的 avg10 约 9.16%。这表明空闲数据不足以判断任务运行时的压力;一次调用即可显著改变内存和换页情况。PSI 是采样前十秒的滚动指标,不是整个实验的平均值。
第一次试验快结束时,一条真实 Lark 私聊进入了入口,但恰逢定时回退;用户没有收到回复。停止后的状态显示模型调用和发送仍在进行中,没有成功送达记录。不能据此推断请求一定没有产生用量或消息一定没有被外部系统接收,因此没有自动重发。第一次试验没有完成真实 Lark 多轮对话验收。
各次启动期间的资源监测日志共记录 127 点,最低可用内存约 200 MiB;采样到的最高 full PSI avg10 为 7.92%,另一次手动快照为 9.16%。这些是启动阶段的采样和滚动值,不是整段试验的平均压力。定时器结束后,试验服务停止,Hermes gateway 和 A2A bridge 恢复到 systemd active;这也不能替代恢复后的实际私聊验证。
确认服务状态后,删除了本次新建的云端临时目录、复制的配置和试验状态文件。删除文件不等于底层介质安全擦除,也无法删除模型服务端可能保留的请求记录。
再次授权后的两轮重测
用户同意后,我们再次暂停 Hermes,使用同样的资源限制和十分钟自动回退窗口,并在 Lark 连接就绪后立即发起测试。用户确认两条私聊均收到回复,第二条正确使用了前文;服务端记录两次模型调用成功、两条回复送达。两次调用分别耗时约 22.7 秒和 8.6 秒,响应报告用量分别为 2028 和 2097 tokens;这不保证包括 OpenCode 内部的所有额外请求。
本轮 OpenCode cgroup 峰值约 360 MiB,一次结束前快照的 swap 约 76 MiB;内存限额命中计数为 1215,未发生 OOM 或 OOM kill。Lark 入口峰值约 40.5 MiB。43 次五秒采样中的最低可用内存约 174 MiB,采到的最高 memory full PSI avg10 为 18.07%。这些结果说明两轮对话可用,但短时压力已接近预设的回退阈值,仍需进一步评估长期运行与同机服务影响。
确认两次回复送达后,主动结束试验、恢复 Hermes,并清理试验目录。Hermes gateway 和 A2A bridge 的 systemd 状态为 active;恢复后的实际私聊和代理端到端连通性没有在本次验收。
这次留下的问题
第一,Lark 长连接建立和用户收到可用回答是不同的验收点;模型调用成功也不等于消息投递成功。第二,机器人身份、权限、历史与去重状态都不能随着进程替换自动迁移。第三,模型请求与系统资源都需要预算:用户消息次数上限不一定等于 OpenCode 内部真实模型调用次数。
下一步需要根据本次验收结果完善真实场景,分别验证 QPC 只读权限、日历和长时间运行,再决定是否进行更长时间的切换。OpenCode 的本地服务接口和权限模型可参考服务文档与权限文档。