后台任务、loop 与 monitor · 让 agent 边等边干

长命令、定时任务、盯日志——agent 怎么不被它们卡住?这一章看 grok 的后台任务:monitor 把日志流成通知、/loop 交给调度器、后台命令完成后用一条合成 prompt「叫醒」模型。

作者 David更新于 第 53 篇(共 60 篇)

后台任务、loop 与 monitor · 让 agent 边等边干

一个能自己动手的 agent,常要跑长命令(启服务、跑测试)、盯日志、做定时任务——还不能被这些卡住。grok 有一套后台执行机制。

monitor:把日志流成通知

monitor 工具(run_monitor_pipeline)盯一条命令的输出,每有新行就发一个 MonitorEvent 通知给模型(包成 <monitor-event> 标签)。两个生产级细节:

  • 速率限制:一个令牌桶(TokenBucket),事件太多先压制,持续过载 30 秒以上 → 直接 auto-kill,防日志刷屏把上下文冲爆;
  • 持有 Weak 终端引用:一个「持久」monitor 不能跨会话把终端进程/actor 钉住(共享运行时的主机上会泄漏)——用 Weak 而非 Arc,会话一放手它就停。

/loop:交给调度器

/loop [间隔] <prompt> 定时重复一个 prompt。有意思的是宿主侧没有默认间隔——若你不给 5m 这种 token,宿主也不去解析「every hour」这类自然语言,而是原样交给模型自己推断节奏(或问你)。真正的调度落到 scheduler_create 工具 + 一个调度器 actor:ScheduledTask(可重复/持久/一次性),会话恢复后调度器会把已有任务重新播报给客户端(announce_existing_tasks),上限 50 个(MAX_SCHEDULED_TASKS),重复任务 7 天后过期(RECURRING_TASK_TTL_DAYS)。

写作之后变了的一点:每次触发都跑在一个脱离对话的后台 subagent 里(fire_as_loop_subagent),不再是你对话里的一轮。它看不到对话上下文,所以存下来的 prompt 必须自成一体,回到对话里的只有结果。

后台命令 + 「叫醒」模型

命令带上 is_background(bash 工具的参数)→ run_background 立刻返回一个 task_id,不阻塞。跑完发 TaskCompleted。关键是怎么让模型知道它完了:notification_bridge 把 TaskCompleted 转成一条合成 prompt(task-completed-<id>)塞进队列——这条合成 prompt 就是「叫醒」。

图表加载中…

正因为完成会主动叫醒,阻塞等待才敢设得宽:模型面的 get_command_or_subagent_output(内部 id 仍叫 get_task_output)一次最多等 20 个任务、全部完成才返回,正数 timeout_ms 封顶 1 小时(MAX_WAIT_BLOCK_MS_DEFAULT,写作时是 600 秒,可用 GROK_MAX_WAIT_BLOCK_MS 调低);原来单独的 wait_commands_or_subagents 已并进它。等超了也不会真卡死,任务完成自会 ping。等待是事件驱动的(Notify,不轮询)。

TUI 侧(这两个快捷键和写作时对调了):Ctrl+B 把正在跑的前台命令转到后台(SendToBackground;命令还在跑时直接发新消息,也会让它转后台而不是被杀)、Ctrl+G 开关任务面板(后台命令 + subagent + monitor/loop 统一列)、dashboard 总览多会话。

和《从 LLM 到 Coding Agent》对照

对照 subagents 与 Claude Code 的 /loop、后台任务:最小实现里没有「边等边干」。grok 的增量是把后台执行做成完整能力:monitor 流式 + 速率保护、调度器、以及「完成主动叫醒」这个让阻塞等待变安全的关键设计。下一章总览它的 CLI 与启动。


上一篇:ACP · 编辑器后端 · 下一篇:CLI 与启动

本页目录