深入解析 Claude Agent SDK:技能(Skill)加载机制与子智能体(Subagent)派生架构

在基于 LLM 的 Agent 开发中,如何优雅地扩展智能体的能力边界,同时避免长上下文带来的 Token 消耗与“注意力偏移”,是架构设计的核心痛点。

Claude Agent SDK(及其底层的 Claude Code 引擎)通过引入基于文件系统的技能(Skill)概念,并结合渐进式披露(Progressive Disclosure)子智能体派生(Subagent Forking)机制,给出了一套极具工程参考价值的解决方案。

本文将以一个具体的 frontend-design(前端开发)技能为例,假设历史会话中存在业务上下文(“我们的主题色是蓝色”),深度拆解技能从发现、触发到最终执行的完整生命周期与 Context 构造原理。


一、 阶段一:渐进式发现与触发

底层引擎对技能的处理遵循“元数据先行,按需加载实体”的渐进式原则。

1. 技能注册与 Context 构造

引擎启动时,扫描本地技能目录(如 .claude/skills/frontend-design/SKILL.md),仅提取文件的 YAML 元数据(name, description)。这些元数据被拼装成一个统一的底层原生工具——Skill Tool,并注入到 LLM 的上下文中。

此时,主 Agent (Main Agent) 的 Context 结构如下:

{
"system": "你是一个全能的AI编程助手...",
"tools":[
{
"name": "Skill",
"description": "调用外部专业技能以完成复杂任务...\n<available_skills>\n  - name: frontend-design\n    description: 编写React组件,包含严格的质量检查。\n</available_skills>"
},
{"name": "Bash", "description": "..."},
{"name": "Write", "description": "..."}
],
"messages":[
{"role": "user", "content": "我们的主题色是蓝色。"},
{"role": "assistant", "content": "记住了,主题色是蓝色。"}
]
}

2. 意图匹配与触发请求

当用户输入新指令 “帮我写一个 Login 组件”,主 Agent 通过推理,判定需求命中 frontend-design 技能的描述。主 Agent 中断文本输出,发起 Tool Call:

{"role": "assistant", "tool_calls":[{"id": "call_1", "name": "Skill", "input": {"command": "frontend-design"}}]}

二、 阶段二:执行引擎的两种模式分野

SDK 拦截到上述调用后,会从磁盘完整读取 SKILL.md 正文(即执行剧本)。此时,根据技能是否配置了 context: fork 参数,底层引擎将采用两种完全不同的上下文突变(Context Mutation)策略。

模式一:主 Agent 模式(In-place Execution)

若未配置 fork,技能将在当前上下文中原地展开。SDK 会将长篇剧本伪装成工具的返回结果(Tool Result),强制注入当前 messages 数组。

突变后的 Context 结构:

{
"messages":[
{"role": "user", "content": "我们的主题色是蓝色。"},
{"role": "user", "content": "帮我写一个 Login 组件。"},
{"role": "assistant", "tool_calls":[{"id": "call_1", "name": "Skill", "input": {"command": "frontend-design"}}]},
{
"role": "user",
"content":[
{
"type": "tool_result",
"tool_use_id": "call_1",
"content": "成功加载技能。请严格按照以下剧本执行:\n1. 检查目录...\n2. 编写代码...\n3. 运行 ESLint...\n[...此处省略数千字的长剧本...]"
}
]
}
]
}
  • 执行表现:主 Agent 读取到剧本后,开始循环调用 BashWrite 等工具干活。由于处于同一 messages 数组中,它自然能继承“蓝色主题”的上下文。
  • 架构缺陷:严重的上下文污染(Context Pollution)。执行期间产生的所有底层操作、试错日志和 ESLint 报错,都会被永久追加到主对话历史中。随着任务增加,Token 开销将呈指数级上升,且极易导致模型在后续对话中注意力失焦。

模式二:子智能体派生模式(Subagent Forking)- 推荐实践

若技能配置了 context: fork,SDK 会冻结主 Agent 的时间线,利用深拷贝(Deep Copy)在内存中拉起一个具备状态隔离的子智能体(Subagent)。

Subagent 被唤醒时的独立 Context 结构:

{
// 1. System Prompt 覆写:主 Agent 的通用人设被丢弃,直接替换为具体的技能长剧本
"system": "你是一个受限的子智能体。你的唯一任务是执行以下剧本:\n1. 检查目录...\n2. 编写代码...\n3. 运行 ESLint...\n[...省略数千字...]",

// 2. 权限沙盒:工具列表被严格阉割(例如移除 Skill 自身以防递归套娃)
"tools": [{"name": "Bash"}, {"name": "Write"}, {"name": "Edit"}],

// 3. 记忆继承:主 Agent 的历史会话被全量克隆,并在尾部追加强制触发指令
"messages":[
{"role": "user", "content": "我们的主题色是蓝色。"},
{"role": "user", "content": "帮我写一个 Login 组件。"},
{"role": "user", "content": "<skill_invocation>主Agent已委派任务,请基于上述上下文立即调度工具执行剧本,勿输出冗余寒暄。</skill_invocation>"}
]
}
  • 执行表现:Subagent 在这个被隔离的“沙盒”内,带着“蓝色主题”的先验记忆,高效地进行代码编写与纠错循环。
  • 状态销毁与上下文归并(合并成果):任务完成后,Subagent 输出最终的验收报告。此时,SDK 执行“阅后即焚”操作——直接从内存中销毁该 Subagent 及其产生的所有中间脏数据(几十轮的报错与调试日志)。
  • 唤醒主 Agent:SDK 仅将 Subagent 的最终报告作为 tool_result 交还给主 Agent。主 Agent 的 Context 依然保持极度清爽:
{
"messages":[
{"role": "user", "content": "帮我写一个 Login 组件。"},
{"role": "assistant", "tool_calls":[{"id": "call_1", "name": "Skill", "input": {"command": "frontend-design"}}]},
// 主对话历史保持干净,仅包含最终结果
{"role": "user", "content":[{"type": "tool_result", "tool_use_id": "call_1", "content": "组件已完成,沿用蓝色主题,代码校验通过。"}]}
]
}

三、 总结

Claude Agent SDK 的技能机制本质上是“对 LLM 上下文生命周期的精细化重构”

核心维度 主 Agent 原地执行 Subagent 派生执行 (context: fork)
技能长文本注入位置 注入至 messages 尾部(作为工具结果) 覆写 system prompt(作为最高指令)
上下文状态传递 数组自然延展,内存共享 messages 数组深拷贝(Deep Copy)传递
安全与权限控制 具有全量权限,存在越权执行风险 沙盒隔离,按需分配只读或特定工具
Token 与记忆管理 试错日志永久污染主状态机,不可伸缩 脏数据生命周期短(阅后即焚),主队列干净

在工程实践中,构建稳健的 Agentic 系统,应默认将复杂工序抽象为技能,并强制启用 context: fork 进行多智能体委派隔离。这种架构不仅保障了主状态机的稳定性,也极大优化了 API 调用的经济效益。

聊聊老罗的十字路口

上个月写随笔《李想的理想》的时候其实已经了解到老罗要进军播客赛道。相较于早年创办锤子科技以及近期宣布的泡面而言,这次大众都异常默契的认为老罗选择了“正确的道路”。节目名称《罗永浩的十字路口》是对乔布斯科技与人文的致敬,另一方面也是老罗自我阶段性的自我调侃吧。

截至这个月底,已经出了两期节目,虽然先前肯定早有谋划筹备和存货,但长谈内容达到这个更新频率,老罗还是挺拼的,看后期这个节奏能保持多久。

陆陆续续看完了前两期节目,没有错过任何一秒内容,有些段落会倒退回放。本身就是长谈的节目,两期节目完整听下来。第一期李想,第二期小鹏。按说下一期应该是李斌了。如果真的如此,我倒有点期待老罗能否从没有未来的公司创始人那里聊出一些能影响自己先前认知和判断的内容。

回到已经看过的两期内容,李想的内容其实把我之前已知的内容进行了完整的串联,没有太多的补充内容。但是其在节目中完整的表述的自我强化学习的理论、实践,以及基于这套方法论下对未来AI、机器人的判断还是让自己非常惊奇。而关于AI的发展有两个看法还是洞见的,一个业界其实不太看得上的朴素而精准的是OpenAI的关于AI的chatBot, agent, 管理者, 组织者的阶段划分;一个是模型能力不断内化提升,落地场景不断外化为流程的双循环进化理论。而后者其实也是自己已知在一些工作落地场景里面一直有模糊思考,但是第一次听到这样精确表达,后面做的一些事情其实也在验证这个理论。

李想的思维其实非常理工科,很多兴趣和观点让自己有很深同频共鸣感。但是反观其事,又是一个不太理工科的方式。而他总结这一期都是一次次深刻的痛苦和教训带来的。老罗问及他为什么很早就明明有机会选择小富即安,但是偏偏走上了更加艰险的创业之路,两者都动容了。某种程度上,任何个体的选择,只要守住了底限,本身无可厚非,但是很多时候我们又何尝不是新时代的井底之蛙,自以为知道和了解全球的资讯、历史,任何信息都在指尖触手可达。但是我们真的知道吗?我们真的有必要知道吗?看完节目,我有点明白为什么Tim在100小时生存上岛以后,会在总结里面不断提及所谓的“知道”。

而第二期小鹏,因为之前并没有系统看过何小鹏的信息,很多内容对自己而言都是全新的。整体听感上,小鹏的思维和表达就是自己更加熟悉的很理工男,甚至可以更加精确到计算机科学专业男。直率,知道就给直球,不知道就承认没想清楚不知道。这里有老罗提问的功底,更多是小鹏的个人特质。但是,如果从企业经营上看,跟李想比较,小鹏无疑还处在更加前期的成长阶段。但是,显然他更加的知道和理解技术细节,但是也有一种之前履职过阿里带着的一点“废话文学”味道。因此,如果从钱包投资的角度看,我会毫不犹豫的继续追加前者,而会对后者一直保持关注。如果说有所失望的话,应该就是小鹏其实有点故意的在梳理技术,会更加在意自己在宏大叙事上的表达和铺陈,而没有太多的细节和实操内容的分享。而老罗的节目也专门安排了这个环节来迎合观众的胃口,也不是不能理解。只是从上一代互联网红利中投身实业,在国内真的没有几个,还是希望小鹏能够走得更高更远一些。

两期节目听下来老罗提问的节奏和套路已经非常成熟,甚至可以说是炉火纯青了。无论是对话题的把控,还是对嘉宾的引导,都非常到位。尤其是对李想的提问,几乎没有任何废话,都是直击要点。对小鹏的提问则稍微有点宽松和铺陈,但是也在情理之中。老罗的提问其实是有技巧的,既不会让嘉宾觉得被逼问,也不会让观众觉得无聊。尤其是他会在关键节点上进行一些总结和升华,让整个对话更加有层次感。也会简短的讲一些自己的经历和感受。可能前两期嘉宾的行业和话题重合度比较高,总觉得这两期节目多元化缺了点,就看下期嘉宾是谁。如果内容10期以后,都能达到这两期节目的声量和传播量,商业化应该是个水到渠成,也是老罗做起来很舒服的一件事了。

近期LLM的一些趋势之二——MCP

书接上回,文末提到一个点:

当然也有不变的点:工具的建设依然很重要。只不过,今年需要更多的思考如何将这些基建工具与上述的flowgraph结合起来。

当时没有展开写,而最近随着MCP(Managed Context Protocol)的逐步普及和应用,今天来补一下当时挖的坑。

什么是MCP

参考MCP的官方文档,MCP是一个用于管理和使用上下文的协议,旨在帮助开发者更好地与大型语言模型(LLM)进行交互。它提供了一种结构化的方法来处理上下文信息,使得在与LLM进行对话时,可以更有效地传递和管理信息。

它的工作流程也很简单(LLM以Claude为例):

When you submit a query:

  • The client gets the list of available tools from the server
  • Your query is sent to Claude along with tool descriptions
  • Claude decides which tools (if any) to use
  • The client executes any requested tool calls through the server
  • Results are sent back to Claude
  • Claude provides a natural language response
  • The response is displayed to you

从工作流程来看,是不是感觉跟我们熟悉的Function Calling有些类似?

MCP vs function calling

MCP和Function Calling的区别在于:

  1. 功能范围:MCP不仅仅是一个函数调用的接口,它还包括了上下文管理、工具描述和结果处理等多个方面的功能。而Function Calling主要集中在函数调用本身。
  2. 上下文管理:MCP提供了更为全面的上下文管理功能,可以在多个工具之间共享和传递上下文信息。而Function Calling通常是针对单个函数的调用,缺乏跨函数的上下文管理能力。
  3. 工具描述:MCP允许开发者为每个工具提供详细的描述信息,以便LLM更好地理解如何使用这些工具。而Function Calling通常只提供函数名和参数,缺乏详细的描述信息。
  4. 结果处理:MCP在结果处理上也提供了更多的灵活性,可以根据不同的工具和上下文信息进行定制化的结果处理。而Function Calling通常是固定的结果处理方式,缺乏灵活性。
  5. 适用场景:MCP更适合于复杂的应用场景,尤其是需要多个工具协同工作的场景。而Function Calling更适合于简单的函数调用场景。
  6. 扩展性:MCP的设计考虑了未来的扩展性,可以方便地添加新的工具和功能。而Function Calling在扩展性上相对较弱,添加新功能可能需要较大的改动。
  7. 社区支持:MCP是一个开放的协议,得到了广泛的社区支持和参与。而Function Calling通常是由特定的公司或组织维护,缺乏广泛的社区支持。
  8. 文档和示例:MCP提供了详细的文档和示例,帮助开发者快速上手。而Function Calling的文档和示例相对较少,可能需要开发者自行摸索。
  9. 学习曲线:由于MCP的功能更为全面和复杂,学习曲线相对较陡。而Function Calling相对简单,学习曲线较平缓。
  10. 性能:在性能方面,MCP可能会因为其复杂性而引入一定的性能开销。而Function Calling通常是直接调用函数,性能较高。
  11. 安全性:MCP在设计上考虑了安全性,提供了一些安全机制来保护上下文信息。而Function Calling通常缺乏这样的安全机制,可能存在一定的安全隐患。
  12. 兼容性:MCP是一个开放的协议,可以与多种语言和平台兼容。而Function Calling通常是针对特定语言或平台的,兼容性较差。

此外,可以参考《MCP 与 Function Call 区别》。其中提到一个比喻非常形象:

  • MCP:通用协议层面的标准约定,就像给 LLM 使用的“USB-C规范”。
  • Function Call:特定大模型厂商提供的独特特性,就像某品牌手机的专属充电协议。

如何使用?

回到我们最开始的观点:不变的点:工具的建设依然很重要。对于MCP来说,主要是指MCP Server。作为一个gopher,推荐者以下两个项目:

两个项目都是golang传统的开箱即用。

要让LLM能够把提供工具、资源、prompt驱动起来,需要借助 MCP client 这个桥梁。而目前从官方推荐的Clients来看,MCP client 主要以两种形式出现:①面向普通用户的application应用,如Claude Desktop App;②面向开发者的agent框架库,如mcp-agent。这里推荐fast-agent.

MCP 的意义

MCP的意义在于它为开发者提供了一种结构化的方法来管理和使用上下文信息,使得与LLM的交互更加高效和灵活。通过MCP,开发者可以更好地利用LLM的能力,构建出更为复杂和智能的应用程序。

还是有点抽象,对不对?从过去技术发展历史来看,MCP跟当年的微服务架构有点类似。不同的是,微服务架构下更多的还是工程、业务逻辑驱动数据流和控制流,而MCP则是将LLM作为决策中枢。也就是说,MCP是一个面向LLM的微服务架构。

太阳底下没有新鲜事,以前微服务架构下的经验在MCP架构下会有一定的借鉴意义。另一方面,MCP的出现也意味着我们需要重新审视和设计我们的应用架构,以更好地适应LLM的特点和需求。