认知减负过滤台:
* 鼠标悬停卡片,翻转查看“Why”与“设计巧妙之处”
0. 理论支点:Harness Engineering
评估 Agent 的对象不能是模型单体,而必须是 "Model + Harness"(模型+安全带/外挂系统)。
基于 npm claude-code-2.1.88.tgz 逆向分析。
真正的难点不在模型的单步推理,而在 Durable state (持久化状态)、Tool mediation (工具中介)、Feedback loops (反馈循环) 等外层治理。
支撑系统运转的「四大不变量」 (Invariants)
🔗
轨迹拓扑不能破
Trajectory StabilityWhy & 巧妙设计
- Why 如果 API 消息格式不合法(如缺少 tool_result),后续循环直接崩溃。
- 巧妙设计 Synthetic Error 补全:即使发生异常,系统也会伪造一个
tool_result塞回消息流,确保闭环不断,防止 SDK 暴露于半成品状态。 - Thinking block 保护:在错误边界截断时,宁可保留整个思维块,也不随意裁剪破坏结构。
🧊
缓存前缀不能漂
Prompt Cache FreezeWhy & 巧妙设计
- Why Context Token 非常贵,打断缓存会导致 API 延迟和成本非线性飙升。
- 巧妙设计 Fate Frozen:一旦模型“看到”了某段内容,它的字节串命运就被完全冻结。
- 系统强行规定工具必须按名称排序,确保内置工具永远作为稳定前缀,以最大化命中 Cache。
🚪
能力面延迟敞开
Deferred CapabilityWhy & 巧妙设计
- Why 一次性加载所有能力(如数百个MCP工具),会引爆 Token 并让模型分心产生幻觉。
- 巧妙设计 按需展开 (ToolSearch):初期只告诉模型“有这个工具的名字”,不加载 Schema 参数。
- 明确提示模型:“只有获取后才能调用”。这是一种极具工程成熟度的能力暴露语义。
💾
连续性多态外化
Polymorphic ContinuityWhy & 巧妙设计
- Why 仅靠 Messages 数组(Transcript)无法承载长时间工作,会爆掉窗口。
- 巧妙设计 分离工件:
-Daily logs: 高频原始追加。
-MEMORY.md: 低频蒸馏的“大纲”。
-Session memory: 记录“工作卡断点”用于恢复。
1. 宿主与主循环 (Host & God Loop)
QueryEngine 不仅转发 prompt,更是会话宿主;query.ts 则是维持轨迹合法性的“状态机图”。
主流程的核心不是“提问并解析 JSON”,而是“不断修正和修补同一条对话轨迹”。
📥
落盘优先原则
Transcript PersistenceWhy & 巧妙设计
- Why 若等待模型返回再记录,一旦断网或崩溃,用户的输入和上下文就彻底丢失了。
- 巧妙设计 BEFORE entering query loop:用户消息一旦接受,哪怕 API 还没请求,先落盘 Transcript。确保随时可进入“可恢复轨迹”。
🧩
合成工具 (Structured Output)
Synthetic ToolWhy & 巧妙设计
- Why 直接让模型输出 JSON 往往需要事后解析并处理报错,流程易碎。
- 巧妙设计 宿主把外部 JSON Schema 即时编译成一个一次性的合成工具 (Synthetic Tool)。
- “输出必须满足Schema” 这一约束被前移到了工具执行期,利用 AJV 校验,不合法直接触发 Tool Error 让模型自行重试。
🩺
错误分流即轨迹保护
Recovery LoopWhy & 巧妙设计
- Why Agent 会遇到各类越界(Token过多、图片太大),简单抛错会导致应用死锁。
- 巧妙设计 两级恢复机制:
Prompt 过长:先尝试保留结构的 Context collapse,失败再走破坏性的全局 Reactive compact。
这不是异常处理,这是上下文精细调度。
2. 提示词与系统指令栈 (System Prompts)
System prompt 不是一段静态文案,而是控制 Agent 行为的“第一控制面 (Runtime Law)”。
引入了独立的 Memory Selector、Auto Mode Classifier 等“专用 Prompt Worker”辅助主模型。
🚧
缓存切分边界
Cache-Break ArchitectureWhy & 巧妙设计
- Why 混合静态系统指令和动态运行时状态(如当前连接的 MCP),会导致巨大的 Prompt 缓存失效。
- 巧妙设计 DANGEROUS_uncachedSystemPromptSection:显式拆分结构。
- 系统强制规定,只有真正跨 turn 漂移的、无法作为附件的内容才允许放入动态区,以此死守静态前缀的缓存命中率。
⚖️
纠偏模型天性法则
Behavior PromptingWhy & 巧妙设计
- Why LLM 天生喜欢“编造抽象”、“未看先改”、“打包返回半成品”。
- 巧妙设计 Prompt 中预置了硬核纠偏:
1. "没读过的代码不准改"
2. "不要写一次性的 Helper 函数"
3. "如果有专有工具,不要直接用 Bash"
这些并非“文笔好”,而是把工程偏差补丁灌入了模型世界观。
📨
第二指令通道
Attachments / RemindersWhy & 巧妙设计
- Why 如果把所有当前任务相关的约束都写进系统 Prompt,它将变得无比臃肿且难以管理。
- 巧妙设计 Context Router (attachments.ts)
- 将短期的强提示(如 critical_system_reminder)包装为 User Meta Message 或 Attachment 注入当前 Turn。实现了法则(长期)与约束(临时)的完美解耦。
3. 能力、工具与策略 (Capabilities & Tools)
ToolUseContext 过于庞大,甚至成了跨界访问宿主状态的万能胶。
权限系统被设计成独立的 Policy Control Plane,支持替换同步 (Replacement Sync)。
🚦
执行与并发控制
Execution PipelineWhy & 巧妙设计
- Why 简单地并发执行所有工具会导致严重的状态竞争(比如多工具同时修改文件上下文)。
- 巧妙设计 读并发,写串行:
- 只读工具(如查询)可以并发收集结果。
- 但上下文的副作用 (Context Modifiers) 必须按模型调用工具的原顺序严格排队提交,避免后续状态被乱序污染。
🎭
能力的虚拟与隐藏
REPL VirtualizationWhy & 巧妙设计
- Why 基元工具(Bash, Read, Edit, Glob)如果全部平铺,会大幅增加模型的决策成本,也破坏前缀稳定。
- 巧妙设计 REPL 虚拟层:将海量小工具收束为一个统一的 REPL 虚拟入口。
- 模型表面只看得到一个入口,但在内层(VM Context)原始能力依然可用,权限系统照样细粒度拦截。
🧠
降维旁路召回
Side Query (Memory)Why & 巧妙设计
- Why 让昂贵的主模型 (如 Sonnet) 直接阅读庞大的历史文档并挑选记忆,极其浪费。
- 巧妙设计 小模型相关性过滤:
- 不使用 RAG 向量检索,而是发起一个
sideQuery。 - 将文档 Manifest (只带头信息不带正文) 喂给辅助模型判断相关性。再通过
readFileState拦截,避免把刚看过的文件又当成“记忆”注入。
4. 连续性、缓存与恢复 (Continuity & Cache)
这套系统没有单一的 "Memory" 模块,连续性被拆解为指令、能力、语义、操作四大维度。
工具返回结果被替换后,会存入 Exact String 以维持后续重放时字节级一致。
🛡️
部分视图保护
Partial View GuardWhy & 巧妙设计
- Why 为了省 Token,记忆注入往往会裁掉大文件尾部或头信息。如果模型以为这就是“全量文件”并用 Write 工具覆写,就会破坏代码。
- 巧妙设计 Raw/Diff 拦截机制:
- 当注入内容与磁盘不一致时,将其标记为
isPartialView。 - 模型试图修改时,系统拦截并强迫其进行真实的 Read 全量操作,这是极具生产价值的一致性防线。
🪢
因果链与逆向回溯
Causality RecoveryWhy & 巧妙设计
- Why 大文件的 JSONL 日志解析极慢,且包含大量
progress冗余帧。 - 巧妙设计 Serialization Invariant:
- 源码死定
parentUuid必须是 JSON 序列化后的第一个键 (First Key)。 - 恢复时无需完整解析 JSON 结构,仅靠前缀扫描和
parentUuid链表逆向回溯,即可快速重建剔除无效节点的“对话因果链”。
❄️
精确字符串替换
Exact String ReplaceWhy & 巧妙设计
- Why 如果仅保存重试状态,一旦 SDK UI 模板、换行格式更新,重建的 Prompt 就会与之前请求 API 时的完全不一致,导致缓存断裂。
- 巧妙设计 命运冻结:
- 直接将替换后的 Exact String 原样落盘。后续任何会话恢复,不重新计算格式,原封不动贴回。确保 Wire Prefix (网络层前缀) 绝对稳定。
5. 任务底座与远程执行 (Task Substrate)
Task 框架根本不是 UI 层面的附属品,它是支撑异步 Agent 的底层执行底座 (Substrate)。
Teammate 之间的通信必须依赖 SendMessage 工具 (RPC 调用),而非共享文本流。
📪
邮箱排水机制
Actor Mailbox DrainWhy & 巧妙设计
- Why 若其他 Agent (Teammate) 的消息随时注入,会打断当前主模型正在进行的连续思考和工具调用,导致上下文错乱。
- 巧妙设计 Tool-Round Boundary:
- 引入 Actor Mailbox,消息先进入
pendingMessages队列。 - 系统只在“上一轮工具执行完毕,下一轮即将开始”的边界时刻进行 Drain (排水注入)。牺牲即时性,换取推理轨迹安全。
🌿
缓存友好的分叉
Cache-Safe ForkWhy & 巧妙设计
- Why 创建 Subagent (子代理) 时,如果重新拼接 Prompt,相当于完全浪费了父进程累积的上下文缓存。
- 巧妙设计 Placeholder Padding:
- 完整拷贝父线程的 Assistant 消息和工具调用,用统一的占位符 (Placeholder) 补齐未完成的 Tool Result。
- 只让最后一段 Directive (指令) 发生变化,最大化利用共享的 Prompt Cache 树干。
☁️
跨端会话追踪
Remote Agent PollerWhy & 巧妙设计
- Why 远程任务可能会因为网络波动断开,如果简单认定为失败,会导致昂贵的远程运行丢失。
- 巧妙设计 精细错误辨析:
- 组合本地 Task Registry + 远端 Session Handle。
- 恢复时区分 `404 Not Found` (真丢了,需归档) 和网络/认证错误 (可能还活着,保留重连机制)。扩展了 Durable Execution 的边界。
6. 结构债与下一代工程化建议 (Debts & Advice)
最亮眼的实现往往首先是“疤痕”,证明系统的边界曾被突破。过度依赖 Vibe Coding 最终会催生庞大的 God Loop。
为什么要强烈建议引入 XState (显式状态机)?
核心痛点
在 Claude Code 中,由于长期采用 "Vibe Coding"(凭感觉打补丁快速迭代),控制流散落在各种布尔变量中 (如 stopHookActive, hasAttemptedReactiveCompact, pendingToolUseSummary)。
后果
导致 query.ts 变成了一个庞大且脆弱的 God Loop。出现 progressBridge, orphaned permission replay 等极其精巧但也极其危险的“幽灵补丁”。局部问题修了,全局所有权 (Ownership) 却丢失了。
架构升级 从隐式补丁走向显式状态流转图:
- 利用 XState,将 Agent 复杂的流转 (如:
申请权限→分类预检→等待用户→重放工具调用) 定义为严格的数学状态。 - 它消除所有的“中间非法状态”,当请求被拒绝或中断时,系统只能沿着合法的图边退回,无需手工编写繁琐的重置逻辑。
- 结论:生产级 Agent 的下一代形态,必须从“一团提示词和胶水代码 (Middleware)”,进化为“显式状态机驱动的执行引擎 (Runtime)”。
🔭
引入可观测性
Observability Plane- 代码中
queryProfiler会详尽统计 Context 装配、API往返、工具执行各自的耗时。 - 诊断 Cache Break (前缀变动、工具增减)。
- 没有可观测性,就没有可演化的 Harness。
🚫
万能胶陷阱
Context BloatToolUseContext当前过胖,工具能轻易越权修改宿主系统。- 建议明确分离只读查询、事件提交、状态所有权。
- 不要让所有子系统都能直接 Mutate 同一片共享内存。
💬 关键金句与引言萃取
The rules of thinking are lengthy and fortuitous... Thinking blocks must be preserved for the duration of an assistant trajectory.
— 源码中关于 Thinking block 的神圣约束。
解读:模型思考过程不是富文本,它是 Agent 认知拓扑的一部分,切断它等同于破坏其短期智力。
Do NOT use the Bash tool when a relevant dedicated tool is provided... You can call multiple tools in a single response. If there are no dependencies between them, make all independent tool calls in parallel.
— 工具并行的 System Prompt 法则。
解读:高阶并发语义并非仅靠代码调度,必须首先植入模型的世界观中,实现“知行合一”。
Until fetched, only the name is known — there is no parameter schema, so the tool cannot be invoked.
— ToolSearch 工具的坦白局提示词。
解读:非常直白地向 LLM 声明“延迟加载工具”的半激活状态,防止模型产生“以为自己能用”的幻觉。
Just writing a response in text is not visible to others on your team - you MUST use the SendMessage tool.
— Teammate 协作的 Actor 模型规约。
解读:用 Prompt 强制将纯文本对话扭转为显式的 RPC 协议调用,这是实现 Swarm (群体智能) 的关键门槛。