第一性原理视角:slock 的 system prompt 设计给 LLM 构建了一个基于类 Slack 消息机制的异步协作工作流。本文分析这套设计与直接运行 claude/codex CLI 相比,在执行效率和效果上的核心差异。
用 cl100k_base tokenizer 对 docs/08-message-delivery-flows.md 中的实际 prompt 计算:
| 场景 | tokens | 说明 |
|---|---|---|
| 完整系统提示(Claude 冷启动) | 4,083 | buildBaseSystemPrompt() 输出 |
| MCP tool definitions(11 个工具) | ~2,063 | tool description + input_schema JSON |
| 固定 context 小计 | ~6,146 | 每次 spawn 必须携带 |
| wake message(无 unread) | 170 | 首次 DM / dead idle 唤醒 |
| wake message(有 unread) | 210 | 多频道积压时 |
| idle 唤醒(in-process idle) | 60 | deliverMessagesViaStdin 输出 |
| busy 通知字符串 | 22 | [System notification: ...] |
| resume + unread only | 128 | 离线期间积压 |
| resume 无新消息(just stop) | 61 |
直接 claude CLI:
用户消息 + tool call + 分析结果 ≈ 405 tokens
slock(首次 DM,dead idle):
系统提示 4,083 + MCP tools 2,063 + wake prompt 170
+ MEMORY.md 读取 80 + claim_tasks 40 + send_message 60
+ 消息格式头 30 + MCP JSON 包装 150 + 实际任务内容 380
= ~7,056 tokens
slock / 直接 CLI ≈ 17x token 倍数(首次)
| 轮次 | 累计 context | 占 200k 窗口 |
|---|---|---|
| 1 | 6,976 | 3.5% |
| 5 | 10,296 | 5.1% |
| 10 | 14,446 | 7.2% |
| 20 | 22,746 | 11.4% |
| 50 | 47,646 | 23.8% |
in-process idle(Claude/Kimi):系统提示只算一次,随轮次线性增长,50 轮后仍在 25% 以内,可接受。
Codex(每轮 exit+restart):每轮都把系统提示重新载入,第 10 轮 context ≈ 51,193 tokens(3.5x 于 Claude 同轮)。
slock 的系统提示为多 agent 协作组织设计,包含大量在单一任务场景下完全无用的内容:
| 章节 | tokens | 在"查 auth.ts 安全问题"任务中是否用到 |
|---|---|---|
| MCP 工具列表 | ~600 | 部分(只用到 3 个工具) |
| Task 系统详解(create/claim/status) | ~500 | 不需要(纯回答问题不需要 task) |
| Splitting tasks for parallel execution | ~150 | 不需要 |
| Channel awareness | ~120 | 不需要(只有一个 DM) |
| Thread 机制详解 | ~200 | 不需要 |
| URL 中文 formatting 规则 | ~80 | 不需要 |
| Memory/MEMORY.md 详细指南 | ~400 | 间接需要(startup 步骤要读) |
| @Mentions 规则 | ~100 | 不需要 |
| Conversation etiquette | ~150 | 不需要 |
保守估计 ~1,700 tokens(约 42% 的系统提示)在该任务中完全是噪声。
更深层的问题:这些无关章节不仅浪费 token,还会稀释任务相关的 attention。LLM 的注意力机制在长 context 中对"中间"内容的权重天然偏低(Lost in the Middle 效应),而 slock 的消息格式规则、thread 机制等内容恰好在系统提示的中部。
直接 claude 执行任务的工具调用路径:
用户消息 → [Read auth.ts] → 分析 → 输出结果
工具调用次数:1
slock 在同一任务上强制要求:
wake message → [Read MEMORY.md]
→ [claim_tasks] ← 额外 1 次(即使不需要 task 管理)
→ [Read auth.ts]
→ [send_message 回复] ← 额外 1 次(不能直接输出,必须走 MCP)
工具调用次数:4(比直接 CLI 多 3 次)
每次额外的工具调用意味着:
- 一次 HTTP round-trip(
/internal/agent/{id}/...) - 额外的 tool_call + tool_result JSON 进入 context
- 模型需要决定下一步,消耗额外推理时间
claim_tasks 的强制性尤其低效:系统提示说"始终在开始工作前 claim",但大量对话型请求(回答问题、code review、解释代码)根本不需要 task 管理。这是把组织工作流规范直接硬编码进了所有任务的执行路径。
每条消息都有固定格式头:
[target=dm:@alice msg=a1b2c3d4 time=2026-04-11 18:00:00] @alice: 实际内容
在多轮对话中,这些 header 会随历史消息累积在 context 里。10 轮对话后,context 里充斥着大量 target=/msg=/time= 的元数据,而模型实际上只需要"谁说了什么"。
这是为了让 agent 能够精确地 reply to thread(需要 msg= 作为 thread ID)而不得不做出的 tradeoff。但对于没有 thread 操作的普通对话,这些信息纯粹是噪声。
当 Claude 正在工作时收到新消息:
1. 消息进入 inbox
2. 3 秒 debounce 等待
3. 发通知:[System notification: You have 1 new message waiting.]
4. Claude 读到通知(但不知道消息内容)
5. Claude 决定"何时"调用 check_messages
6. check_messages → HTTP GET /receive → 返回消息
7. Claude 才真正读到消息内容
问题在于步骤 5:Claude 自己决定什么时候去 check。系统提示说"at natural breakpoints",但在执行复杂任务时 Claude 可能认为"完成当前步骤更重要",导致:
- 用户发了紧急的"停止!改方向"消息,Claude 可能要等完成当前工具链才会 check
- 如果消息是"我 typo 了,我是说 X 不是 Y",但 Claude 已经基于错误理解执行了几步
对比 Kimi 的 steer 机制——直接把新消息内容打断注入,Claude 立即知道发生了什么。这是 Claude 在 slock 里相比 Kimi 的一个结构性弱点。
Claude 的 context 压缩(compaction)会丢失对话历史,slock 用 MEMORY.md 作为恢复点。但这引入了新问题:
MEMORY.md 的质量完全依赖 agent 自身的"记忆习惯"
- 如果 agent 没有按指示更新 MEMORY.md,compaction 后会丢失关键上下文
- MEMORY.md 的信息密度取决于 agent 上轮写得是否到位
- 在任务执行途中如果发生 compaction,agent 可能在 MEMORY.md 里只写了"正在做 X"而没有记录已完成的具体步骤、遇到的问题等
对比直接 claude CLI:Claude 的 native compaction 由模型自身管理,压缩后仍能保留任务关键上下文(因为模型知道什么重要)。slock 把这个责任转移给了 agent,而 agent 的记忆行为不可控。
Codex 每轮退出,每次重启需要:
- spawn 新进程
- 检查/初始化 git repo
- 启动 MCP server(chat-bridge)
- MCP 握手(
initialize+ tool discovery) - 通过
codex exec resume {sessionId}加载历史 session
这个启动序列大约需要 5-15 秒,加上每轮都重载系统提示(4,083 tokens),第 10 轮的 context 约是 Claude 同轮的 3.5x。
对于快速交互任务(用户期望秒级响应),Codex 在 slock 里几乎无法用于实时对话。
系统提示第 3 条 startup step:
"If there is no concrete incoming message to handle, stop and wait."
直接 claude CLI 可以持续运行,agent 可以主动:
- 探索代码库
- 发现潜在问题后主动报告
- 在等待用户回复时做准备工作
slock 的 agent 被设计为纯响应式——没有消息就不工作。这是为了控制 API 成本和防止 agent 失控,但代价是 agent 失去了自主性。
当两个 slock agent 需要协作时:
Agent A 完成工作 → send_message → HTTP POST /internal/send
→ Slock Server 存储消息
→ WebSocket 推送到 daemon
→ daemon 决定是否唤醒 Agent B
→ B 可能需要重启进程(dead idle)
→ B 读取消息 → 执行 → 回复
端到端延迟:秒级到分钟级
对比直接的进程间通信或函数调用:毫秒级。
这意味着在需要 Agent A 和 B 快速迭代交互的任务(如 A 生成代码 → B 测试 → A 修改 → B 再测试)中,延迟会显著累积。
直接 claude 每次新 session 从零开始。slock 的 MEMORY.md + session resume 让 agent:
- 记得用户的编码习惯和偏好
- 知道项目架构(无需每次重新探索)
- 追踪长期进行中的任务状态
对于长期驻留场景(agent 作为"同事"持续数周/月工作),这个优势非常实质。
单一 claude session 只能串行执行。slock 允许:
- Agent A 做 code review,Agent B 同时写测试,Agent C 处理文档
- 复杂任务分解后 wall clock 时间大幅缩短
对于有明确任务边界的并行工作,多 agent 的效果确实超出单 agent,不是线性叠加,而是因为每个 agent 的 context 更专注,质量也更高。
slock 的消息流天然提供了完整的可审计轨迹:
- 所有 agent 的行动都经过 Slack-like channel
- 人类可以实时观察、随时发消息干预
- task status 流(in_progress → in_review → done)强制了 review 环节
直接 claude CLI 执行过程对团队其他成员不可见,也无法协作干预。
用户发一条消息后关电脑,agent 继续在后台运行(甚至可以在服务器上跑)。直接 claude 需要终端保持活跃。
多个项目/话题分开在不同 channel,每个 agent 在当前 channel 里保持 focused context,不会被其他话题的消息干扰。这比单 session 里混杂所有话题要更干净。
| 维度 | 直接 claude/codex CLI | slock |
|---|---|---|
| 单任务 token 效率 | ✅ 高(~400 tokens) | |
| 启动延迟 | ✅ 秒级 | |
| 上下文相关性 | ✅ 100% 任务相关 | |
| 跨 session 记忆 | ❌ 无 | ✅ MEMORY.md 持久化 |
| 多 agent 并行 | ❌ 不支持 | ✅ 原生支持 |
| 用户干预能力 | ✅ 任何设备发消息 | |
| 可审计性 | ❌ 仅本地 terminal 输出 | ✅ 完整消息历史 |
| Agent 响应延迟(忙时) | ✅ 立即 | |
| Codex 多轮 context | ❌ 每轮重载系统提示(3.5x) |
核心矛盾:slock 的系统提示为"10 个 agent 协作管理一个工程组织"设计,但当用户只是想快速问一个问题时,这套设计带来了 17x 的 token overhead,而收益为零。
slock 真正发挥价值的工况:
- 需要多个专业化 agent 并行工作
- 任务周期以天/周计,需要跨 session 记忆
- 团队多成员需要可见地与 agent 协作
- 需要人工 review 环节的工作流(in_review → done 需要人批准)
不适合的工况:
- 单次问答或短期任务(token overhead 显著)
- 需要快速迭代交互的实时任务(Codex 启动延迟,Claude 的 check_messages 轮询)
- 个人独立使用(多 agent 协作优势不存在,只剩 overhead)
一个有意思的副作用:由于 slock agent 被强制通过 send_message 输出(不能直接输出到 terminal),且每次都要读 MEMORY.md 和维护上下文,agent 被迫养成了"先回顾再行动"的工作习惯,这在某种程度上减少了 LLM 的"幻觉式自信"——它每次都会重新确认自己知道什么、在做什么。这个副作用可能部分抵消了 token overhead 的负面影响。