第 1 章:Grok Build 是什么
这一章先不钻进实现细节。我们的目标是建立一个足以承载后续 14 章的心智模型:Grok Build 的产品边界是什么,一次请求经过哪些角色,复杂度为什么会自然出现。
1.1 不只是一个 TUI
根目录 README 把 Grok Build 描述为运行在终端中的 AI coding agent,但源码提供了更多表面形态:
| 表面形态 | 主要入口 | 典型使用者 |
|---|---|---|
| 全屏或 minimal TUI | xai-grok-pager | 终端中的人 |
| Headless | run_headless | 脚本、CI、自动化 |
| ACP stdio agent | run_stdio_agent | IDE 或其他 ACP 客户端 |
| Leader 服务 | run_leader | 多个本地客户端与长生命周期会话 |
| Serve / relay 等模式 | 二进制命令分派 | 网络或远程集成 |
这里最重要的设计选择是:UI 不是 Agent 本体。TUI、Headless 和 ACP 都在使用 xai-grok-shell 中的 Agent/Session 能力。这样,业务状态不会被锁在某个终端渲染循环中。
源码入口:
main.rs:二进制组合根,main在约 1654 行,async_main在约 1735 行。agent/app.rs:run_stdio_agent、run_headless、run_leader。app/mod.rs:TUI 启动与终端生命周期。
1.2 一次请求中的七个角色
把整个系统想象成一家公司,比把它想成一个循环更准确。
角色一:Client
Client 收集用户输入并显示结果。TUI 只是一个 Client;IDE 也可以通过 ACP 成为 Client。
角色二:Leader
Leader 是可选的本机常驻入口。它维护共享 MvpAgent,接受多个客户端连接,按 session 路由请求和通知。它解决的是进程生命周期、多客户端附着与断线重连,而不是模型推理。
角色三:MvpAgent
MvpAgent 是 ACP Agent 实现和会话目录。它知道有哪些 session、如何新建/载入/分发 session 命令,以及认证、模型目录、MCP、插件等共享服务。
角色四:SessionActor
SessionActor 是单个会话的业务核心。它拥有会话状态、当前 prompt、工具桥、权限句柄、上下文状态、压缩、记忆、目标与工作流等。绝大多数“Agent 为什么这样行动”的答案都在这里。
角色五:ChatState 与 Sampler
ChatState 管理要发给模型的规范化对话、token 估算、修剪和请求快照;Sampler 负责网络协议、流式解析、重试、取消和供应商差异。
角色六:Tool Runtime 与 Workspace
工具运行时把模型产生的 JSON 调用还原为类型化参数,Workspace 则提供文件、终端、VCS、权限和代理访问。两者共同构成“Agent 能对世界做什么”。
角色七:Persistence 与 Updates
状态改变会变成可持久化更新。它们既服务 UI,也服务恢复与重放。模型文本只是更新的一种,不是整个系统的状态。
1.3 完整请求旅程
下面是一条省略错误与旁路后的主流程:
这个图最容易被误读的地方有两个:
- 模型流不会直接写 TUI。
SessionActor需要先建立语义边界、保存状态并产生 ACP 更新。 - 工具调用不是一条同步函数链。预检按顺序进行,批准后的多个调用可并发执行,进度和完成顺序也可能不同。
1.4 系统的三条平面
理解大型 Agent 最有效的方法,是把它分成数据面、控制面和恢复面。
数据面:完成当前工作
用户消息 → 模型请求 → 流式响应 → 工具调用 → 工具结果 → 下一次模型请求。
主要源码:
session/acp_session_impl/turn.rssession/acp_session_impl/sampler_turn.rssession/acp_session_impl/tool_calls.rsxai-grok-sampler/src/actor/request_task.rs
控制面:决定如何工作
模型选择、权限模式、Plan 模式、MCP 状态、Hook、插件、技能、goal、workflow、插话与停止策略都属于控制面。
它们通常不会替代主循环,而是在主循环的关键节点插入约束或额外输入。
恢复面:让工作可延续
会话事件、聊天缓存、文件检查点、compaction checkpoint、Leader 重连状态、工作流 journal 和目标状态都属于恢复面。
成熟 Agent 与演示脚本的核心差别,经常不在“能不能调模型”,而在“中断后还能不能知道发生过什么”。
1.5 为什么采用 Actor
源码中的 actor 不是为了套用一种架构风格,而是在解决具体并发问题:
| Actor/所有者 | 独占状态 | 避免的问题 |
|---|---|---|
MvpAgent | session map、共享服务 | 多请求同时创建/加载同一 session |
SessionActor | 单会话业务状态 | prompt、取消、工具完成、模型流互相踩状态 |
ChatState | 规范化对话与 token 账本 | 并发更新导致历史和持久化次序分离 |
SamplerActor | 活跃采样请求与重试 | 多网络流的取消、终止和事件归属混乱 |
| Permission manager | 授权状态与会话 grant | 并发工具请求重复或越权 |
SessionActor 甚至运行在独立 OS 线程上的 current-thread Tokio runtime + LocalSet 中。这使它可以安全持有 !Send 状态,而外部只通过 mailbox 与 handle 交互。
设计代价也很明确:一次操作会跨多个消息边界,调用栈不再完整表达执行顺序。Grok Build 用 typed command、event ID、prompt ID、request ID 和持久化更新补回可追踪性。
1.6 与最小 Agent Loop 的差别
最小实现通常是:
while true:
response = model(messages, tools)
if no tool calls:
return response
messages += execute(tool calls)2
3
4
5
Grok Build 的等价结构更接近:
receive prompt
prepare turn metadata and dynamic capabilities
loop:
drain interjections, reminders, completions and control signals
maybe compact
build normalized request
sample through independent actor
persist response and usage
if no tool calls:
evaluate stop hooks, todos, goals and pending work
either continue, pause, or finalize
else:
preflight all calls in model order
run approved calls with bounded concurrency semantics
persist results and re-enter loop2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
复杂度来自产品承诺,而非单纯代码风格:
- 用户可以随时取消或插话;
- 多个工具可以并行,但权限提示必须可理解;
- 模型后端可能断流、限流或改变上下文窗口;
- UI/IDE 可以断线后重新附着;
- 会话可能持续到必须压缩;
- 长任务不能只相信主模型说“完成了”;
- 项目插件和 Hook 不能天然获得无限信任。
1.7 本章结论
Grok Build 的核心不是一个函数,而是一组明确的状态所有者。最关键的架构关系是:
Client 负责交互,Leader 负责连接,MvpAgent 负责会话目录,SessionActor 负责一场对话,ChatState 负责可发送上下文,Sampler 负责模型网络流,Tool/Workspace 负责外部副作用,Persistence 负责让一切可恢复。
下一章从 80 个 workspace member 入手,把这些角色映射到 crate 层级。