五种运行入口汇聚同一内核 本节摘要:Grok Build 有五种看起来截然不同的使用方式:在终端里跑全屏 TUI、在 CI 里无头执行、被 IDE 通过 stdio 调用、作为 WebSocket 服务器被客户端连接、作为共享 leader 给多个客户端当后端。它们各自有不同的入口函数、不同的传输方式、不同的客户端身份。但所有这些入口,最终都汇聚到同一个内核——SessionActor 加 sampler。本节会讲清这种「多入口单内核」架构的设计动机、五种入口各自的特点、以及它们如何通过不同的传输承载同一种 ACP 协议。理解这种架构,你就理解了 Grok Build 为何能同时胜任交互、自动化、集成三大场景。
本节摘要:Grok Build 有五种看起来截然不同的使用方式:在终端里跑全屏 TUI、在 CI 里无头执行、被 IDE 通过 stdio 调用、作为 WebSocket 服务器被客户端连接、作为共享 leader 给多个客户端当后端。它们各自有不同的入口函数、不同的传输方式、不同的客户端身份。但所有这些入口,最终都汇聚到同一个内核——SessionActor 加 sampler。本节会讲清这种「多入口单内核」架构的设计动机、五种入口各自的特点、以及它们如何通过不同的传输承载同一种 ACP 协议。理解这种架构,你就理解了 Grok Build 为何能同时胜任交互、自动化、集成三大场景。
一个 Agent 工具,如果只能跑全屏 TUI,它的使用场景会很受限:
这些场景的需求各不相同:有的需要交互、有的需要无人值守、有的需要被嵌入、有的需要被共享。如果为每种场景写一套独立的 Agent 逻辑,代码会大量重复,且难以保证一致性。
Grok Build 的解法是:入口多样,内核唯一。把「如何接入」(传输、协议承载、客户端身份)与「如何工作」(会话管理、思考-行动循环、工具调度)彻底分离。前者是入口层的变化,后者是共享的内核。
┌──────────────────────────────────────────────────────────┐ │ 入口层(各不相同) │ │ │ │ ① interactive ② headless ③ stdio │ │ (TUI 全屏) (CI/脚本) (IDE 集成) │ │ │ │ ④ serve ⑤ leader │ │ (WS 服务器) (共享后端) │ └───────────────────────────┬──────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ 共享内核(完全相同) │ │ │ │ SessionActor + ChatStateActor + sampler + tool_bridge │ │ + memory + hooks + plugins + mcp_state + ... │ └──────────────────────────────────────────────────────────┘
下面逐个看。
这是最常见的入口,直接敲 grok 不带子命令时触发。
触发方式
grok # 进入交互 TUI grok "修复这个 bug" # 带初始 prompt 进入 TUI
特点
传输方式:进程内直接连接(内存通道),或经 leader IPC socket(若启用了共享 leader)。
无头模式,适合 CI/CD 流水线、脚本自动化、批处理。
触发方式
grok -p "审查这些改动的 bug" # 单次 prompt,执行完退出 grok --prompt-file task.txt # 从文件读 prompt grok --output-format json ... # JSON 输出供脚本消费
特点
传输方式:同样不经过网络,但走 headless 专用的执行路径(run_headless 入口)。
被编辑器或桌面应用通过 stdio 拉起,作为它们的 Agent 后端。
触发方式
grok agent stdio # 在 stdio 上跑 ACP
特点
传输方式:ACP over stdio。
作为 WebSocket 服务器运行,供客户端通过网络连接。
触发方式
grok agent serve # 默认 127.0.0.1:2419 grok agent serve --bind 0.0.0.0:8080 # 自定义绑定
特点
--secret 或 GROK_AGENT_SECRET 环境变量,不提供则随机生成)--bind 0.0.0.0 并注意安全--remote 选项让它代理一个远端 agent传输方式:ACP over WebSocket。
作为共享后端进程,给多个客户端提供 Agent 能力。
触发方式
grok agent leader # 作为共享 leader 运行
特点
传输方式:客户端通过 IPC socket(unix socket 或类似)连接 leader。
关键问题:这五个入口的代码各不相同,怎么保证它们用同一套内核?答案在于入口的职责边界——入口只做三件事:
入口层做的事(各入口不同): 1. 接入准备 - 解析入口特定参数(端口、secret、绑定地址等) - 建立传输通道(stdio / WS / IPC / 进程内) - 完成入口特定的鉴权 2. 构造内核 - 创建 SessionActor(传入工作目录、权限模式、配置等) - 这一步所有入口都一样 —— 内核不关心自己被哪种入口拉起 3. 桥接 - 把入口的传输(stdin/stdout、WS、IPC)与内核的命令/事件通道接起来 - 入口负责「翻译」:把传输上的消息翻译成 SessionCommand, 把 SessionEvent 翻译成传输上的消息
内核本身不知道入口是谁。SessionActor 收到的是 SessionCommand,它不关心这个命令来自 TUI、IDE、还是 WS 客户端;它发出的 SessionEvent,也不关心谁在接收。入口层负责所有的「翻译」与「适配」。
这种分离的好处显而易见:
入口与内核之间的「翻译」依据,是 ACP(Agent Client Protocol)。ACP 是一个 JSON-RPC 风格的协议,定义了客户端与 Agent 后端之间的消息集合。
客户端 → Agent 的典型消息:
NewSession:创建新会话SendPrompt:向会话发送 promptCancel:取消当前操作session/update(标准 ACP)或 _x.ai/session/update(xAI 扩展):会话更新Agent → 客户端的典型通知:
关键设计:ACP 是传输无关的。同一套消息,可以承载在:
这正是「多入口单内核」能成立的技术基础——只要传输能可靠地传递 JSON 消息,ACP 就能在上面跑。
关键概念:ACP 是 Grok Build 内部解耦的关键抽象。它让「用户接入方式」与「Agent 工作方式」彻底分离——任何能产生 ACP 消息的客户端,都能驱动同一个 Agent 内核。这也是为什么 Grok Build 能同时支持 TUI、IDE、CI、服务化、共享后端等多种形态。
理解了五种入口,实际使用时如何选?可以按场景对照:
| 场景 | 选哪个 | 命令 |
|---|---|---|
| 日常交互编程 | interactive | grok |
| CI/CD 自动化 | headless | grok -p "..." |
| IDE 集成(被编辑器调用) | stdio | grok agent stdio |
| 本地服务化(多客户端) | serve | grok agent serve |
| 共享后端(资源复用) | leader | grok agent leader |
几点提醒:
第一,大多数用户只需要 interactive 与 headless。stdio 主要给 IDE 开发者、serve/leader 主要给平台工程师用。普通开发者把它们当作「Grok Build 还能这么用」的扩展视野即可。
第二,入口可以组合。比如一个 leader 后端可以同时被多个 interactive 客户端连接(每个客户端是一个 pager 进程,共享同一个 leader 内核)。
第三,入口的稳定性各异。interactive 与 headless 是最成熟、测试最充分的入口;stdio、serve、leader 相对小众,行为细节可能在不同版本有调整。生产使用前建议充分测试。
把这种「多入口单内核」架构放回更大的设计语境,它体现了几个值得借鉴的工程价值:
价值一:关注点分离
「如何接入」与「如何工作」是两个正交的关心点。把它们分离,各自可以独立演进——新增一种接入方式不需要动内核,改进内核不影响现有接入。
价值二:协议优于实现
ACP 这个明确的协议,比任何具体实现都稳定。只要协议不变,客户端与服务端可以各自升级。这是分布式系统设计的经典原则。
价值三:渐进式扩展
新入口可以渐进添加。比如未来若要支持 Web 客户端,只需写一个新的 WS 入口适配层,内核不动。这种可扩展性是应对未来需求的关键。
价值四:复用的极致
同一套内核,服务于五种截然不同的场景,这是复用的极致形态。它让 Grok Build 不需要为每种使用方式维护一份独立代码,大幅降低了复杂度。
下一节进入本章重心——用伪代码逐段拆解那个让 Agent 真正转起来的核心循环:process_conversation_turn。