Back to list
·21 min read·

用 OMP + Herdr,打造一个 Grok Bot 平替

前阵子 xAI 推出的 Grok 桌面客户端(Grok Bot)在技术圈引起了很大反响。网络上大家讨论最多的核心亮点,是它并没有停留在常规对话框,而是真正给每个用户分配了一台持久化的云电脑。

与一般每次任务开一个临时沙盒、用完即毁的容器不同,Grok Bot 的架构是在云端挂载一台长驻的 Linux 桌面虚拟机。它不仅能在上面跑浏览器、执行命令行,自主进行桌面级的「Computer Use」,更关键的是支持随时人工接管:当 Bot 在云端自动操作时遇到了图形验证码、2FA 或登录阻碍,它可以暂停执行,把云电脑的实时画面推给用户;你在客户端里全屏接管鼠标键盘,顺手把滑块划过去或敲完验证码,点一下交还控制权,Bot 就能在云端继续干活。

我在 Grok Bot 里挂过一个春运机票监控任务:设定出发地与备选到达城市,让它每周一、三、五自动联网比价,降到预算线或出现大跌时向我推送通知,直到买到票为止。

这个产品形态确实令人眼前一亮,但我没用多久就退了。主要就是嫌贵、额度少:为了盯几张机票每月交一笔昂贵的订阅费,还要看着宝贵的高级模型额度被后台定时任务悄悄扣光,拿来干这种长期低频的跑腿事务很不划算。

某天我把这个机票任务提示词复制出来贴到终端,问了本地的 Agent 一句:「你能做到吗?」

接下来的几天里,我把这套自动化任务与助理工作流全部收回了本地。依托终端 AI Agent 框架 OMP 与终端复用中枢 Herdr,在不花额外月租、不烧昂贵额度的前提下,搭建了一套完全自主可控的平替系统。

核心机制对齐:Grok Bot 背后是哪几块拼图

抛开商业包装与云电脑的概念,Grok Bot 提供的底层能力在工程实现上可以清晰拆解为四个模块:

  1. 确定性的定时调度:脱离人工干预,按日历周期精准触发任务;
  2. 浏览器自动化与网页交互:拉起真实浏览器环境,解析动态渲染的内容,完成实质上的 Computer Use;
  3. 状态保留与条件决策:跨周期持久化数据基准,执行数值计算与增量比对;
  4. 即时外部通知:判断达标后,将结构化结论推送到随身通讯工具。

本地复刻不需要复杂的远端基建,Linux 系统与成熟的本地工具链本身就提供了更自洽的对应组件:

  • 执行内核:OMP(Oh My Pi),单二进制的终端命令行 Agent,原生具备全功能的 Chromium 控制、文件读写与命令执行能力;
  • 调度中枢:systemd user timer,系统级定时器,支持睡眠唤醒与错峰补偿,没有任何常驻运行时代价;
  • 交互与生命周期组织:Herdr,专为 Coding Agent 设计的多窗口终端工作区管理器;
  • 交付通道:Telegram Bot API,二十行脚本直连个人频道。

至于云电脑里的「随时人工接管」,本地环境反而具备天然优势:所有的浏览器窗口、会话终端全都在自己的显示器上,真遇到阻碍时直接切屏即可操作,完全省去了远端视频流推流的网络延迟。

本地执行链路:调度、门禁、执行、比对与触达五个环节
本地执行链路:调度、门禁、执行、比对与触达五个环节

第一块:定时任务,Prompt 即代码

传统自动化爬虫最怕目标网站改版,一段硬编码的选择器往往两周就会失效。而 Agent 化调度的优势在于能够自适应页面语义。

我将监控任务写成一份自包含的 Markdown 文件(task.md),包含了航线组合、白名单过滤、基准价格和计算要求。每次调度由 systemd 用户定时器触发无头模式的 OMP 执行:

[Timer]
OnCalendar=Mon,Wed,Fri 10:30
Persistent=true
omp -p @~/stewards/travel/fare-watch/task.md --auto-approve --max-time 20m

为保证系统严谨可靠,任务设计上固化了三个工程规范:

静默期是硬要求:正式开跑前严禁打扰。调度虽然保持心跳,但启动前先由一行 bash 检查当前日期:未到窗口直接退出,连模型进程都不拉起,避免空耗 Token。

证据留存与防幻觉。大模型做数值监控必须建立强约束:提示词中明令禁止推测价格,提取到的每一条数据都必须从快照文本中逐字印证。每次执行自动抓取 DOM 原文写入 snapshots/ 目录备查。

状态机隔离。同目录下只放一个轻量的 state.json,保存基准价、首跑标记与购票终止位。差值比对强制调用系统内的 Python 算术计算,消除模型自身的口算误差。

数据源博弈:无头环境下的对抗与收敛

实际接入航线抓取时,各平台的表现差异很大:

最先测试的去哪儿 PC 端在无头 Chromium 下触发了反爬指纹脚本,列表区域直接阻断渲染。

随后接入同程旅行。同程的国内常规航线可以稳定抓取,但在第二项任务(需要覆盖香港、澳门到达)中遇到限制:其 Web 端未开放港澳航线路由,请求直接返回 404。

最终的解法是接入携程国际与中转页面。实测表明携程在无头模式下表现稳定,能直接检索出一票到底的联程机票(如佳木斯经北京转机至香港)。原本需要自行分段拼票、面对航变风险的组合,直接被检索到了成套联程方案,价格从自拼的 ¥2730 降到了 ¥2121,自带转机保障。

根据实测结果,两项监控形成了稳定分工:常规国内往返走同程,跨区域联程走携程。

数据源实测与分工:三个平台各跑一轮真实抓取
数据源实测与分工:三个平台各跑一轮真实抓取

交付设计:高信噪比的信息排版

在即时通讯工具里看通知,如果第一眼抓不到重点,监控就失去了意义。通知样式经历了两次迭代:

初版直接丢出长链接和平铺文字,长 URL 在手机屏幕上自动折成多行,杂乱无章; 第二版引入 HTML 标记,但由于没有做段落呼吸,所有关键信息依然挤在一起。

最终落地的排版规范如下:

🎯 西安票 ¥3260
 
触及目标价(≤¥3280)| 较上次 ↓¥340
 
去 02-04 / 回 02-13 · 东航 MU2332
 
打开同程查看 →

排版原则直接约束在 Agent 的提示词中:

  1. 首行必须是「标记 + 核心价格 + 达标结论」,手机锁屏通知栏不用点开就能看清底牌;
  2. 段落之间强制空行留白,分离关键参数与航班信息;
  3. 原始链接全部折叠进内联文本,避免破坏阅读节奏。

第二块:多 Agent 如何在 Herdr 间自主对话与协作

定时任务负责「没人的时候悄悄干活」,而日常开发中,我更需要的是一个各司其职的常驻专家团队。我在 Herdr 中划分了一个独立工作区,跑着七个专职会话:一个主控总管,外加六个垂直领域的助理(旅行规划、网盘管理、片库整理、Windows 机器运维、VPS 服务器 SRE、本机工作站诊断)。

传统多 Agent 框架(如 AutoGen、CrewAI)往往需要在 Python 运行时里维护一套繁重的心跳、消息总线和上下文代理,代码复杂且容易因单点崩溃导致全部瘫痪。

而在 OMP + Herdr 的体系下,多 Agent 相互通信的实现方式出奇地轻巧:直接利用终端原生的进程隔离与 Socket CLI,把每一个 Agent 变成系统的命令行公民。

上下文隔离与角色自治

每个助理拥有独立的工作目录(如 ~/stewards/travel、~/stewards/vps)与专属于自己的 AGENTS.md 治理文件。每个 Agent 启动时只读取自己的一隅上下文,不堆砌无关信息:

  • 旅行助理精通高铁机票、境外签证与行程账本,但遇到系统故障时绝不擅自推理;
  • 服务器运维助理只掌握主机指标、容器守护与防火墙规则;
  • 总管助理不承担具体技术搬砖,专门负责任务拆解与全局裁决。

点对点跨领域路由

当助理在处理业务时遇到了越界问题,它不需要人类人工转手,而是直接借助 OMP 自带的 bash 工具调用 Herdr 命令行向同伴求助:

herdr agent prompt vps "检查自托管 travel 账本容器状态与端口占用情况" --wait --timeout 600000

Herdr 捕获到目标窗格处于就绪状态后,将输入内容原子化灌入对应助理的终端输入流,等待对方运行得出结论。如果对方正在被审批弹窗阻断(blocked 状态),调用方不会盲等超时,而是能通过 herdr agent read 读出同伴当前卡在什么具体的确认界面上,把真实处境转交人类决策。

非阻塞广播与异步收敛(统一发令)

当总管需要向全体助理批量下发指令时(例如「让各助理用一句话汇报各自职责」),如果串行等待,七个会话累加起来需要数分钟。我们在调度中采用了三步流水线:

  1. 并发瞬时投递:读取在线名单,逐个执行 herdr agent prompt <name> "<instruction>"(不带 --wait),瞬间将多路指令全量灌入各个助理的终端输入队列;
  2. 状态屏障等待:通过 herdr agent wait <name> --timeout 600000 并发监听,等待所有会话的状态归于 idle 或 done;
  3. 结果提取与清洗:调用 herdr agent read <name> --source recent-unwrapped --lines 120 精准提取各终端最新渲染的答复文本,汇总成结构化清单统一输出。

每个助理在自己的终端里真实地执行命令、敲击代码,助理之间的「对话」在外界看来就是一次次干净利落的 CLI 数据管道。

第三块:长驻助理群与 1.3 GB 内存难题

这套多 Agent 协作体系跑顺之后,带来了一个意料之外的现实负担:七个终端 Agent 会话长期挂载,直接吃掉了 1.3 GB 内存。在笔记本移动办公场景下,这笔开销必须优化。

如果纯靠人工退出,体验会非常割裂:

  • 退出后重新启动,需要重新绑定终端窗格的身份别名;
  • 重新拉起的会话容易丢失上一轮对话上下文;
  • 经常容易将「关闭 Agent 进程」误操作成「关闭终端标签页」,直接拆毁精心摆好的工作区布局。

为了解决这个问题,我建立了一套自动休眠与无感拉起流程。

厘清层级避免破坏布局

首先明确终端复用器里的三层结构:

Tab(标签页,承载业务职责分类)
 └── Pane(终端窗格,维持窗口排布)
      └── Agent 进程(运行在窗格内的 OMP 实体)

内存是由最内层的 Agent 进程占用的。只要让内部的 OMP 退出,窗格便会回退到干净的 shell 提示符,而外部的 Tab 和窗格布局不受任何影响。在 OMP 交互界面中,连按两次 Ctrl+C(或单次 Ctrl+D)即可完成干净退出。

状态判定与静默休眠

编写后台管理脚本 stewards-hibernate,由每 10 分钟执行一次的 systemd timer 唤起。脚本抓取 Herdr 的运行状态表,在本地维护时间戳:

  • 仅针对处于 idle 或 done 的空闲状态;
  • 当连续无活动时间达到 45 分钟,且该窗格当前没有被用户聚焦注视(focused == false);
  • 脚本向目标窗格发送退出序列使 OMP 安全落盘并退出,同时将该窗格记录进休眠名单 hibernated.tsv;
  • 正在执行命令(working)或等待审批(blocked)的会话绝对不碰。

挂载事件钩子实现聚焦唤醒

休眠之后,如果重新唤醒还需要手动输入命令,依然不够理想。

Herdr 的插件系统原生支持事件钩子。我编写了一个轻量的本地插件 stewards.auto-wake,挂载 pane.focused 事件(插件规范中事件名需使用点号格式,下划线命名不会被识别):

id = "stewards.auto-wake"
name = "Stewards Auto Wake"
version = "0.1.0"
min_herdr_version = "0.9.0"
 
[[events]]
on = "pane.focused"
command = ["bash", "wake.sh"]

插件捕获到窗格获得焦点的事件后,检查该窗格是否处于休眠名单中。如果确认处于休眠状态,立即调用启动命令:

herdr agent start "$name" --kind omp --pane "$PANE" --timeout 30000 \
    -- --continue --cwd "$HOME/stewards/$name"

通过附带 --continue 参数,OMP 自动衔接上一次的历史会话,Herdr 重新为窗格贴上原有别名。

在实测中我们还消除了一处时序竞态:OMP 退出大约需要一秒的收尾耗时,若用户恰好在此刻切回标签页,脚本容易误判为进程尚在而跳过拉起。在判断逻辑中加入短暂的二次复核,即可彻底解决漏唤醒的问题。

最终效果完全自适应:长时间不用的助理退回后台释放内存;当你切到对应标签页想要交代事项时,窗格自动复苏,上下文完整保留。如果需要手动干预,配套的 stewards-sleep 和 stewards-up 也能一行命令收放自如。

会话的自适应生命周期:活跃、休眠与唤醒
会话的自适应生命周期:活跃、休眠与唤醒

踩坑清单

在本次重构中,几处实际踩过的工程细节记录如下:

  • 无头 Chromium 的反爬敏感度:大型 OTA 的主站页面对无头浏览器封控极为严厉,单页应用容易直接白屏;相比之下,面向国际航线的搜索接口往往对动态反爬更宽容。
  • Herdr 插件事件命名的语法差异:Socket API 输出的事件在 JSON 中通常使用下划线(如 pane_focused),但插件清单 herdr-plugin.toml 的 [[events]] on 配置项必须严格写为点号(pane.focused),否则链接插件时仅给出一句弱警告,运行时完全不触发。
  • systemd-run 调试时的虚拟终端隐患:使用 systemd-run --user 临时验证后台服务时,切忌随意附加 --pty 选项。一旦发起测试的外层会话超时关闭,虚拟终端释放引发的 SIGHUP 信号会连带掐死后台跑着的系统服务。
  • 退出控制序列的执行边界:在 OMP 环境中,单次 Ctrl+D 与双击 Ctrl+C 具备相同的退出效果。但在任务执行期间按下 Ctrl+D 会直接打断任务退出,手动干预时应在会话空闲阶段触发。

总结

回顾整套平替方案,关键在于把自动化能力从远端商业平台收回到了本地工作站:

换了哪些部件:云端依赖与本机实现的对应关系
换了哪些部件:云端依赖与本机实现的对应关系
  • 成本自洽:调度由系统自带的定时器驱动,执行调用已有的模型订阅,不产生额外的平台月租;
  • 资源受控:通过事件流让多会话在常驻与休眠间自适应切换,消除了 1.3 GB 内存闲置负担;
  • 数据与权限闭环:没有向外穿透的本地后门,没有挂在第三方平台的抓取脚本,执行环境、决策逻辑和历史记录完全留在本地磁盘中。

现在我的机器上,只有系统定时器按部就班地执行抓取,Herdr 里的各个助理在需要时随手唤醒。那个又贵、额度又少的云端 Bot,自然也就没有继续留着的必要了。