> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Grok Bot 用法拆解：一条消息之后，服务端发生了什么
- URL: https://www.hubwiz.com/blog/grok-bot-message-lifecycle-usage/
- Published: 2026-10-22T17:38:46.000Z
- Updated: 2026-10-22T17:41:53.000Z
- Description: 你可以连发一百条把它打断一百次，它却不会重做任何已完成的工作。这条性质决定了很多使用细节——也解释了它为什么能"一直在，却几乎不耗钱"。
- Author: admin
- Tags: Grok Bot, AI Agent, 架构, 上下文工程

**一句话结论**：一个"随时在线"的聊天 Agent，真正难的地方不是模型，而是**把一次对话做成一个可打断、可崩溃、可恢复、还不烧钱的分布式系统**。你发给 Grok Bot 的每条消息，先落本地并带一个唯一 ID（连接抖动重发不会变成两条），进该会话的队列；主循环是 **Temporal 上的持久化工作流**，每次模型调用、每次工具调用都是一个**已落库的步骤**——所以你连发一百条把它打断一百次，它也不会重做任何已经完成的工作。

**披露**：本文编译自 Peter Piekarczyk《What actually happens when you message Grok Bot》（2026-10-14，11 分钟阅读）。原文主要依据 Lee Robinson 关于 Grok Bot 内部实现的公开分享，作者自己补了一部分分布式系统经验。**必须提醒**：文中有大量"我猜/据我记忆（IIRC）/最可能是这样"的推测（数据库选型、Firecracker 是否为同款、批次窗口、helper 是否可再起 helper 等），作者本人在文末列了 11 个待确认问题。本文忠实保留这些不确定性标注；未做独立验证。

---

## 一、按下发送的那一瞬间

界面立刻显示你发的消息，**它不等服务器**。App 在本地保存这条消息，并生成一个唯一 ID。

这个 ID 在服务端有实际作用：**服务器会丢弃任何它已经见过的消息 ID**。所以当你在地铁里网断了一下、客户端自动重发时，你不会收获两条一样的消息——一个很小的乐观更新设计。

然后这条消息进入**你这个会话的队列**。

## 二、每条会话一条队列：谁能插队，谁只能排队

每个会话都有一个队列，任何想引起 Agent 注意的东西都往这里放。但不是所有消息享受同等待遇：

| 来源              | 行为                             |
| --------------- | ------------------------------ |
| **你直接发的消息**     | **打断**。它正在跑一个回合，你发新消息，它就停下接你这条 |
| helper（子代理）跑完回报 | 排队，不打断                         |
| Slack 里被 @      | 排队，不打断                         |
| 定时工作流触发         | 排队，不打断                         |

理由很直白：**你是那个在主线程上等着的人**——字面意义上的"等"。其余都是后台事件，没有人在屏幕前盯着。

还有个细节和体感有关：**如果你飞快地连发三条，它们很可能不会变成三个独立回合**。作者推测存在一个很短的时间窗，把挨得很近的消息合并成一个回合处理。

> 用的人能立刻得出的第一条结论：**别把聊天框当命令行连打**。你以为在"补充信息"，它可能在反复重启一个回合。

## 三、"被打断"和"白干了"是两件事

主 Agent 的循环是一个**跑在服务器上的持久化工作流（durable workflow），底层是 Temporal**。每一次模型调用、每一次工具调用都是一个 step，**每一步一完成就把结果存下来**；对话历史则单独存在自己的数据库里。

先解释一下 Temporal：一个开源引擎，它在代码运行过程中把每一步的结果存下来。服务器崩了，另一台机器从断点接着跑，不会重做已完成的工作；它还负责重试，并允许工作流"睡到被某个事件叫醒"。

于是有两个容易被混为一谈的性质，其实是独立的：

- **可打断（interruptible）**：你的新消息能中断正在进行的回合；
- **持久化（durable）**：已做完的工作不会被丢掉，下一个回合从存下的步骤继续。

合起来的效果就是：**你可以发一百条消息，它被打断一百次，但一次都不会重做已经干完的活**。同一套机制也让它扛得住崩溃——服务器挂了，工作流从最后一个已保存的步骤恢复，而不是从头发车。

## 四、这个循环到底怎么跑（作者的推测）

原文作者说，Lee 只讲了"用了 Temporal"，没讲循环具体怎么挂在上面，所以这段是**他的推断**，而我觉得推断得挺合理：

- 服务器是**常驻的 worker 进程，所有用户共享**；两次回合之间，**你没有任何东西在跑**；
- 循环就是一段写一次的普通代码，类似 `agentTurn(conversationId)`；
- 你发消息 → 前门把消息存下并给 Temporal 一个信号 → Temporal 建一个任务 → 某个空闲 worker 领走 → 该 worker 从数据库读出你的对话历史，跑一个回合。

所以就一个回合而言，它很像你熟悉的无状态 API 请求：

```
workflow agentTurn(conversation):
  messages = loadContext(conversation)   // saved step
  loop:
    reply = callModel(messages)          // saved step
    if no tool calls: break
    for toolCall in reply:
      result = runTool(toolCall)         // saved step
      messages.append(result)
  saveTurn()
  waitForSignal()                        // sleep

```

Temporal 在这里同时是**调度器**和**记账员**：一步只交给一个 worker，结果当场记账。worker 中途崩了，它对这一步的"认领"会超时，另一个 worker 从已存步骤重放工作流。**"每次模型与工具调用都写库"这件事，正是重放能成立的原因。**

回合结束后，工作流停在"等待信号"上：**内存里没东西，也没有进程在跑，它只是数据库里的几行记录**。原文说 Agent 在空闲约两分钟后被报告为睡眠——他猜这是 worker 在保温，以防你马上回一句。

这就是"一直在"却几乎不耗钱的做法：**睡眠很便宜，因为状态根本不在 worker 上**。

## 五、小活自己干，重活交给 helper

消息到了 Agent 手里，它怎么处理？前门的 router 先做触发去重、塞进会话队列；然后主 Agent 用提示词里的一条经验法则自行决定：先回你一句"收到"，接着要么自己干，要么转出去。

- **小活留在主循环**：改一个 Notion 页面、更新一条 GitHub 评论，算"快"，丢到后台反而更贵更慢。
- **主 Agent 也能跑 shell**，但据作者记忆，shell 跑在 VM 上，所以**即使一条"很快"的命令也会把 VM 唤醒**；凡是 shell 密集的活，都算长任务，转给 helper。
- **长任务交给四类 helper**：**general（通用）、computer use（操作电脑）、video（视频）、cloud coding（云端写码）**。每个 helper 是**自己的一条持久化工作流**，有自己的 harness 和工具集，全程在后台跑。跑完把结果投回队列——也就是前面那条"不打断你"的消息。

这里有个使用上的反直觉结论：**inline 干的活，你的打断是直接打在它身上的**。你一边催一边发消息，那条 GitHub 评论就改得更慢，因为循环被反复切断。原文说他相信 Meta 的 Muse 也是这样。

> 所以：**想让事情并行，就让它开 helper，而不是在主线里刷屏。**

## 六、VM：把"你的东西"和"跑循环的机器"分开

Agent 循环跑在共享服务器上；**VM 是另一台机器，是"你的 Agent 自己的电脑"**，循环需要时用一个工具把它叫起来。

这套分层里，"谁是真相源"说得非常清楚：

| 层            | 存什么                                       | 特点                           |
| ------------ | ----------------------------------------- | ---------------------------- |
| **服务器（数据库）** | 会话、例行任务（routines）、工作流步骤                   | 真相源（作者假设是 Postgres 或 SQLite） |
| **对象存储**     | 文件、记忆、技能                                  | 备份（作者假设是 S3 或 R2）            |
| **VM**       | 它正在处理的文件副本 + 工作文件（下载的视频、SEC 文件、clone 的仓库） | 可丢弃；同步到对象存储                  |

VM 睡眠时，**内存和磁盘会被快照**，所以你的登录态和其它状态都能留着。反过来说，**VM 是可弃的**：Grok Bot 团队要为 0-day 打补丁时，直接换掉就行，什么都不丢——因为真相源在服务器，文件都在对象存储里备份着。

作者说这些是 **Firecracker microVM**（据他所知和 AWS Lambda、Fly.io 用的是同一种）：很小、大约 **125 ms** 就能启动、从快照恢复也快，所以"唤醒 VM"感觉是瞬时的。

技能和记忆走的是同一条思路：**内置技能与插件技能来自平台本身；你的自定义技能是 VM 上的 markdown 文件**（就跟你存在笔记本上一样），并备份到对象存储；记忆也是，Agent 用 **grep** 去搜它。

## 七、"多个机器人，一台电脑"

这条对使用方式影响很大，也最容易被忽略：

> 你可以建任意多个 Grok Bot，但它们**不会各拿一台 VM**——**你所有的 bot 共用一台电脑**。

这意味着什么：

- 共享**同一批文件、同一套已安装的工具、同一批浏览器登录态**。一个 bot 装了某个东西、登录了某个站点，**其它 bot 都能用**。
- 每个 bot 有的是**自己的桌面**：自己的屏幕、自己的浏览器窗口。一个 bot 看不见、也开不了另一个 bot 的屏幕，所以两个 bot 可以同时用浏览器而不抢鼠标。
- 作者的原话比喻：**很像几个人共用一台笔记本**——每人有自己的用户会话，但硬盘是共享的。每个 bot 的会话、记忆、例行任务存在服务器上，共用那台电脑只是工作区。

> 使用含义：**隔离是"桌面级"而不是"机器级"**。你做实验时装的包、登的账号会串到别的 bot 上。要干净，就自己负责清理。

## 八、安全：审的是"动作"，不是你的提示词

和 ChatGPT / Claude 的自动审查类似，Grok Bot 有一个**独立的模型在动作执行前做审查**，主要针对 shell 命令。它审的是**Agent 准备做什么**，不是你的提示词。

另外两条规则：

- **来自外部来源的内容（邮件、网页）永远被当作"数据"，不被当作"指令"**——这是防提示词注入的基本姿态；
- **不可逆的动作**（发邮件、往 Slack 发帖）会变成**草稿回到你这里等批准**。作者括号里补了一句略带调侃的话：大概是在某位 CEO 的银行账户信息被泄露之后加上的。

## 九、一个出口：`SendToUser`

不管活是怎么干完的，结果都从同一个口子回来：有一个全局工具叫 **`SendToUser`**。你在桌面端、手机端还是 Slack 里，Agent 都只调它，各客户端自己决定怎么呈现。

这个设计值得抄：**"怎么通知人"不写在 Agent 的逻辑里，而是收敛成一个工具 + 客户端渲染**。

## 十、上下文的四道防线

一个"永远在线、什么都记得"的 Agent，很容易变得又慢又贵还没用。原文列了四种对抗手段，我按"对使用者有什么影响"重排：

**1）稳定的提示词前缀（缓存）** 模型供应商从第一个 token 开始缓存。只要开头（系统提示词 + 工具列表）每回合都一样，就能被便宜地复用；变化的东西（新消息）放最后。这件事比听起来重要：**每回合都要重发整段对话，缓存命中就是它能既快又便宜的原因**。开头一变，后面全部失效，成本和延迟一起跳。

作者在这里认了个错，值得抄：他之前推算某人每月在 AI 上花 **$11M**，后来发现算错了——**忘了提示词缓存**；把缓存算进去，真实数字接近 **$1M/月**。

**2）工具与技能懒加载** 提示词里只放**技能的名字和一句短描述**，完整技能在真正需要时才加载。这正是 Agent Skills 标准的工作方式（他说 Claude、Codex、Pi 都遵循）。所以——

> **一句技能描述要写"什么时候该用它"，而不是"里面有什么"。** 因为模型决定要不要加载时，能看到的只有这句描述。

技能不应该自动加载。他提到 `pstack` 里有个布尔值 `disableModelInvocation`：开启后模型没法自己加载这个技能，你只能显式调用（比如 `/hello-world`）。

**3）主线上下文保持小** 重活都丢给 helper，主线程的上下文自然就小。让子代理各自去拉它们需要的东西。

**4）上下文压缩（两级触发）**

| 触发条件                                                 | 行为             | 为什么这样设计                   |
| ---------------------------------------------------- | -------------- | ------------------------- |
| 上下文超过 **100K token**，且你**离开 10–60 分钟**               | 后台压缩           | 压缩要把整段对话重新喂一遍模型；趁缓存还热做，便宜 |
| 撞到上下文窗口上限（Grok Bot 约 **200K**；Codex/Claude 约 1M 但可配） | 立即压缩，**阻塞主线程** | 没法延后，只能停下来做               |

重要的一点：**你的对话历史永远不会被删**，可以像翻 iMessage 一样往回滚。**被压的只是模型的工作上下文**。

> 使用含义：**别等它撞窗口**。你离开的那 10–60 分钟，正是它便宜地整理上下文的最佳窗口。

## 十一、它怎么越用越好：两个循环

- **内环，按天**：团队找 bug，改 harness、提示词或推理栈，跑几个 eval，然后发给你。
- **外环，按月或几个月**：拿收集到的失败样本训练新模型。

作者猜测，像"这次该自己干还是转给 helper"这类判断，会有可观测量喂进外环。长期看，**模型是围绕这个产品训练出来的，两者一起变好**；原本住在提示词和 harness 里的经验，会被搬进模型本身。

这也是为什么有人说：**你那些精心维护的 `AGENTS.md` 和自定义技能，可以扔了**——下一代模型可能已经被训练成会自己这么干。

## 十二、读完就能改的六个用法

以下是我们根据这套机制整理的落地建议，不是原文观点：

1. **要补充信息，攒成一条发。** 连着发会反复打断正在进行的回合，inline 的活只会更慢。
2. **要并行，让它开 helper**，别在主线里催；helper 的结果走队列，不会打断你。
3. **不可逆动作先看草稿再批。** 这是你唯一的人工闸门，别养成"无脑点同意"的习惯。
4. **多 bot 共用一台机器**：装包、登录账号会互相影响；实验前想清楚隔离边界。
5. **技能描述写"何时用"**，否则模型根本不会想到加载它；需要确定性的技能，就禁掉自动调用、走显式命令。
6. **长会话主动在离开时让它压缩**（>100K 且闲置 10–60 分钟），别等阻塞式压缩。

## 十三、作者自己还没搞清的问题（选译）

原文结尾列了 11 个问题，挑几个最能说明"这是外部观察"的：

- 主循环的每一步是独立工作流，还是整个会话一条长工作流？（他倾向前者）
- 打断一个回合时，正在跑的工具调用是直接被丢弃吗？
- "启动 helper"是不是一个"起子工作流、立刻返回 ID"的工具？helper 能不能再起 helper？
- 不同 helper 是否跑在不同模型/不同设置上？
- 快照恢复到底多快？内部有没有 VM 管理器、怎么选宿主机？
- 压缩是"替换整个上下文"，还是只替换上次摘要之后的部分？

## 十四、边界

- 原文为**外部观察 + 一次公开分享**的整理，作者多处明说"这是我的推断"；数据库、对象存储、microVM 型号、批次窗口都是**推测**。
- 数字（100K / 200K / 1M token、125 ms、2 分钟空闲、$1M/月）来自原文或作者引用，**本文未独立验证**，产品也可能随时调整。
- 这套机制是 Grok Bot 的实现，**不等于"所有 Agent 都该这么做"**；但"队列 + 持久化步骤 + 懒加载 + 稳定前缀"这套骨架，已经被几家前沿产品反复验证。
- 关于 Firecracker 的 125 ms 启动，可以对照我们写过的另一种路线：[Hyperlight 把启动压到 1–2 ms](https://www.hubwiz.com/blog/hyperlight-018-ring-buffer-arm64-windows/)，代价是只能跑专门编译的客体。

---

**相关阅读**：[Agent / MCP / 自动化完全指南](https://www.hubwiz.com/blog/agent-stack/) ｜ [Agent 上线复盘：重启失忆、重复退款、超时当失败](https://www.hubwiz.com/blog/agent-restart-replay-idempotency-retro/) ｜ [1–2 毫秒起的 microVM：Hyperlight 0.18 换掉主机通信层](https://www.hubwiz.com/blog/hyperlight-018-ring-buffer-arm64-windows/) ｜ [Agent 说"做完了"，数据库说没有](https://www.hubwiz.com/blog/agent-delivery-verification-gates/) ｜ [给编码 Agent 一份你自有的记忆](https://www.hubwiz.com/blog/give-your-coding-agents-a-memory-you-own/)

**Sources**

- Peter Piekarczyk, *What actually happens when you message Grok Bot*, 2026-10-14：[https://www.peterp.me/articles/what-actually-happens-when-you-message-grok-bot/](https://www.peterp.me/articles/what-actually-happens-when-you-message-grok-bot/?ref=hubwiz.com)（文中所引的 Lee Robinson 分享逐字稿与截图，由原文作者整理在同一篇内；我们未取得原视频）
- 对照阅读（本站）：[Hyperlight 0.18](https://www.hubwiz.com/blog/hyperlight-018-ring-buffer-arm64-windows/)、[Agent 上线复盘](https://www.hubwiz.com/blog/agent-restart-replay-idempotency-retro/)

*本文由 hubwiz 编译整理，转载请注明出处。*

> **这是「Agent / MCP」专题的一部分。**完整地图见：[Agent / MCP / 自动化完全指南](https://www.hubwiz.com/blog/agent-stack/)