这是"框架理解自检"系列的第 1 篇,共 5 篇。基于 Claude Code (v2.1.76) 和 OpenClaw 的源码分析, 50 道题帮你验证学习深度。本篇覆盖 Claude Code 的 8 个核心概念。
你花了两周读完 Claude Code 的反混淆源码,感觉自己已经"通了"。
但如果有人突然问你:"Skill 和 Tool 到底什么区别?"你能不看笔记、从实现层面说清楚吗?
这就是这个系列要做的事——不是教新知识,而是帮你检验那些你以为已经掌握的东西。规则很简单:先看问题,在心里组织答案,再看下方的参考答案对照。
Q1 : Agentic Loop 比经典 ReAct 多了什么?
经典 ReAct 是 Reason → Act → Observe 的线性串行循环。 Claude Code 在三个维度做了增强。
并行工具执行。模型一次回复中的多个 tool_use block 会被 partitionToolCalls() 按并发安全性分批——concurrencySafe=true 的工具合并为并行 batch ,非安全工具独占一个 batch 。更激进的是 StreamingToolExecutor: API 还在流式返回时工具就开始执行。
多级自愈状态机。循环有 7 个 continue 原因和 10 个 return 点。 prompt-too-long 时先尝试 collapse drain 再做 reactive compact ; max-output-tokens 截断时先 escalate 8k→64k ,再注入 "Resume directly" 让模型从断点继续。不是简单 retry ,而是根据错误类型选择不同恢复路径。
上下文管理 + 嵌套递归。 4 层递进式上下文管理让循环理论上可以无限运行。 Agent 工具递归调用 query(),形成嵌套循环,每层有独立的上下文管理和 abort 控制。
Q2 : Skill 和 Tool 的本质区别
Tool 是模型直接调用一个函数,得到执行结果。Bash("ls") 执行后返回 stdout ,就这么简单。
Skill 完全不同:模型调用 SkillTool → 加载一段 Markdown 文件 → 展开为 newMessages 注入对话 → 模型看到这段指令后自己按指令继续工作。
打个比方: Tool 是"替你干活的工人", Skill 是"递给你一张操作手册"。 SkillTool 自己不执行任何实际操作,它是 42+ 个工具中唯一的"元工具( meta-tool )"。
更有趣的是, Skill 调用后还返回一个 contextModifier,可以临时切换模型、临时授权工具、调整 thinking effort——所以 Skill 本质上也是一个运行时配置修改器。
Q3 :三种 Sub Agent 形态
普通 Sub Agent:独立身份、独立 system prompt 、独立工具集,有自己的 agentic loop 。适合需要特定角色和约束的子任务,比如 Explore(只读搜索)和 Plan(禁写规划)。
Fork Agent:继承父 agent 的完整对话上下文和 system prompt 。字节级相同的请求前缀共享 prompt cache——这是它的核心价值。所有 fork 子代用相同的占位符消息,配合 useExactTools: true 保证缓存命中。适合需要理解当前对话、且可以廉价并行的任务。
Teammate ( Swarm ):完全独立的 Claude Code 实例,有自己的 REPL 循环。通过文件邮箱系统( JSON 文件 + 文件锁)通信,轮询间隔约 500ms 。可以在 tmux/iTerm2 分屏并行工作,持续存在直到被关闭。适合大规模迁移、多模块改造等需要持续协作的场景。
Q4 :为什么 Tool 数组的"有序"很重要?
getAllBaseTools() 返回有序数组,这个顺序直接影响发给 API 的 tools JSON Schema 排列。
改变顺序 = schema 字节表示不同 = 打破 prompt cache。
Anthropic 的 prompt caching 要求前缀字节级相同。一次 cache miss , 100K tokens 的 system prompt 就从 1/10 价格变成全价。 Fork Agent 甚至用 useExactTools: true 来确保子代使用父的精确工具列表——工具顺序就是钱。
Q5 : System Prompt 哪些静态、哪些动态?
静态部分(scope: "global",跨用户全局缓存): Intro ("You are Claude Code...")、 Doing Tasks (编码风格)、 Executing Actions with Care 、 Using Your Tools 、 Tone and Style 。这些对所有用户都一样。
动态部分(每会话可能变化): Environment ( cwd 、 git 状态、平台信息)、 Memory ( MEMORY.md 内容)、 Session Guidance 、 MCP Instructions 。
两者之间有一个 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ 分界线。
为什么要分开?如果混在一起,你改了一个 cwd 路径,整个 100K tokens 的 system prompt 缓存就全部失效。分层让静态部分的缓存不受动态内容影响。
Q6 : Compaction 管道的四层
第一层 microCompact(零 LLM 成本):纯字符串替换,把旧 tool output 替换为 [Old tool result content cleared]。越老的结果越积极截断。这是唯一不需要调 LLM 的层。
第二层 Session Memory 持久化:压缩前先把关键记忆写到磁盘文件,保留 10K-40K tokens 。关键上下文通过磁盘跨越多次 compaction 存活。
第三层 Summarization( 3 种模式): Full 全量总结、 Partial(from) 只总结最近消息、 Partial(up_to) 只总结前缀保留后面原文。模型先输出 <analysis> 深度分析,再输出 <summary>,然后 <analysis> 被丢弃——用思考换质量,但不占上下文。
第四层 Post-compact 恢复:重读最近 5 个文件( 50K token 预算),重新注入 Skill 内容( 25K 预算),重新加载 Plan ,告诉模型转录文件路径作为自救通道。
Q7 : Plan Mode 的技术本质
不是靠 prompt 说"请先想再做"。而是系统级权限收紧 + prompt 反复注入。
权限收紧:进入时切换到 mode = 'plan'。 Edit 、 Write 、 Bash 写操作全部被权限系统拦截,只允许写入 plan file 。模型不是"选择不写",而是"写不了"。
Prompt 反复注入:通过 attachment 机制,每 1/5 轮交替注入完整指导和简短提醒,防止模型在长对话中"忘记"自己在 plan mode 。
审批门控:必须调用 ExitPlanMode → 用户审批 → 才能退出。
口头说"先写计划"是 prompt engineering (模型"选择"遵守), Plan Mode 是系统级约束(系统"不允许"违反)。这是它和所有"思考链"方案的根本区别。
Q8 :消息组装为什么分层?
System prompt 在 getSystemPrompt() 中构建,在 API 调用层被切分为多个 text block 并加上 cache_control 标记。
User/Assistant 消息在 queryLoop() 中组装。 CLAUDE.md 内容前置为第一条 user 消息,附件以 <system-reminder> 标签注入。
为什么分开?还是缓存。 system prompt 的静态部分需要跨用户全局缓存,会话级部分需要会话内缓存。如果所有内容塞到同一层级,一个动态字段的变化就会打破整个前缀的缓存。
你可能发现了——这 8 道题的答案里,"prompt caching"出现了至少 5 次。这不是巧合。 Claude Code 的很多看起来古怪的设计决策,背后都是同一个动机:省钱。
下一篇预告:"OpenClaw 源码自检(二)"——OpenClaw 的默认模型居然不是 Claude ?通道适配为什么不在 Agent Runtime 层? compaction 质量守卫和 token 效率问题, 8 道题带你拆解。
夜雨聆风