深入解析 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 调用的经济效益。

打造 MacBook 本地大模型代理中心:New API 与 LiteLLM 部署记录

随着各大云厂商接连推出极具性价比的大模型 API,手里不知不觉囤了各种厂商(如阿里云、腾讯云、DeepSeek 等)的多个 API Key。为了在本地各种 AI 工具(Chatbox、VSCode、Cursor)中无缝切换和聚合管理这些模型,在本地搭建一个 LLM API 网关(Proxy)成为了刚需。

“New API (可视化管理, golang) + LiteLLM (高阶路由容灾, python)” 是目前最理想的两个本地大模型代理解决方案。本文记录了在 MacBook 上的部署踩坑指北。

架构概览

  • New API:基于 Docker 部署。负责对接国内各家云厂商的私有协议,转换为统一的 OpenAI / Anthropic 标准协议,并提供直观的 Web UI 进行额度和令牌管理。
  • LiteLLM:基于 Python 虚拟环境 + Supervisord 本地部署。套在 New API 壳外,提供极客级别的按需路由(Routing)和故障自动转移(Fallback)。

一、部署 New API:OrbStack 与网络环境破局

在 Mac 上跑 Docker,强烈推荐使用 OrbStack 替代臃肿的官方 Docker Desktop,它不仅启动极速,且内存占用极低。

但由于大陆地区的网络原因,在执行 docker-compose up -d 拉取 New API 镜像时,大概率会遇到 context deadline exceeded 的超时报错。

💡 破局重点:配置加速镜像
不需要复杂的代理规则折腾,最直接有效的方案是在 OrbStack 中配置有效的镜像源。
打开 OrbStack -> Settings -> 左侧选 Docker -> 找到 Daemon 选项卡,填入以下配置并 Apply &amp; Restart

{
"registry-mirrors":[
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi"
]
}

~~配置完成后,镜像拉取速度还不错,但是可能不稳定,需要多重试几次。~~国内很多其他的镜像源(如阿里云、腾讯云等)目前都不可用了,只有上面这三个 jsDelivr 的镜像源还勉强能用,深感嘘唏……

2026-03-19 更新:连接很不稳定。最后调整为使用docker-pull-tar通过代理拉取取到本地后再导入,才算真正解决了这个问题。更加唏嘘……


附上精简版 `docker-compose.yml`: ```yaml services: new-api: image: calciumion/new-api:latest container_name: new-api restart: always ports: - "127.0.0.1:3000:3000" volumes: - ./data:/data

ports 部分强烈建议只绑定到 127.0.0.1,以确保服务只在本地可访问,提高安全性。


二、部署 LiteLLM:虚拟环境与 Supervisord 进程守护

LiteLLM 基于 Python 开发。为了极致节省 Mac 系统资源,我没有选择让它也跑在 Docker 里,而是直接在宿主机使用 venv 创建独立虚拟环境,并使用 supervisord 进行后台进程守护与开机自启管理。

1. 创建虚拟环境并安装

# 创建并激活虚拟环境
python3 -m venv ~/.litellm-env
source ~/.litellm-env/bin/activate
# 安装 litellm
pip install 'litellm[proxy]'

2. 💡 配置重点:Supervisord 与虚拟环境的结合

使用 Supervisor 管理虚拟环境中的 Python 应用,最大的踩坑点是路径问题:千万不能依赖系统的环境变量,必须在配置中直指虚拟环境的绝对路径!

通过 Homebrew 安装 Supervisor (brew install supervisor) 后,在配置目录(M芯片通常为 /opt/homebrew/etc/supervisor.d/)下创建 litellm.ini

核心配置写法如下:

[program:litellm]
# 【关键】不要直接写 litellm,必须写 venv 环境下的绝对执行路径!
command=/Users/你的用户名/.litellm-env/bin/litellm --config /Users/你的用户名/LLM/litellm/config.yaml --port 4000

# 指定工作目录
directory=/Users/你的用户名/LLM/litellm
user=你的用户名

# 自动重启与日志
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stdout_logfile=/Users/你的用户名/LLM/litellm/stdout.log
stderr_logfile=/Users/你的用户名/LLM/litellm/stderr.log

写好后执行:

supervisorctl update
supervisorctl restart litellm

总结

通过 OrbStack (Docker) + New API 搞定全网模型协议的标准化,再通过 venv + Supervisord + LiteLLM 搞定本地轻量化守护与高阶路由。整套架构完全跑在本地,逐步有了点本地的 token hub 的感觉,既满足了对多模型的无缝切换,又极大地节省了系统资源。

计划外的第一次川西环线

今年春节比往年长一些。妞儿很早就提议,我们是不是可以出去走走。回想起去年春节全废,以及自己最近的状态,本来想直接来个附议。但春节叠加长假,又是拖两个娃,实际体验可能是炼狱。因此,妞儿提了挺多出发目的地都被我否决了。直到有一天她说起毕棚沟,我一听,这不就是两年前我们理小路之行的折返点,同时也是我两次路过,但是从来没有想过要去的景点吗?

每次旅途出发前的时刻是最惬意的,虽然凌晨才把零食用闪购订好,起床也要比往常早一些。不紧不慢,加完油出发也是快十点了。路上偶遇了妞儿的哥哥一行,驱车4小时后,我们四人有回到了两年前理小路的折返点。毕棚沟景区前面的路依然拥堵,不同的是这次我们都没有丝毫的焦躁。虽然来的路上有过争吵的插曲,但是路过毕棚沟门口的时候,我和妞儿都决定,这次也不进景区了。相对于目的地,此刻的我们都一致认为最好的风景其实在路上。

于是,带着妻儿,我们续上了两年前的那个国庆没有走完的理小路。即使是童话公路,冬日的肃杀还是有的。一路上,我熟稔的给他们介绍这雷神瀑布和壮丽的魔戒峰。带他们在我上次的几乎每一个停车点驻足打卡。大二普没有了秋日的彩色,远处的雪山依然巍峨。尤其带他们搓了一顿现切的牛肉串,一切都刚刚好。跟上次自己单车不同的是,穿出理小路山谷段,我们没有左转返回成都,而是右转夜宿在了小金县。酒店楼下名曰“会师广场”。24年理小路通车,断断续续,来了三次;而这次是最接近初心的一次;完成这次会师是不经意的,但却跨越了3年。

前一天的右转更多是自驾人不喜欢走回头路的习惯,但第二天天亮总得为这个习惯买单:今天我们怎么走?本着一条道走到黑的原则,打开了我很喜欢的一个视频up主五月的天分享的奥尔地图。只用上厕所的时间就没有任何计划的规划出了一条路线。反正妞儿也判断不出这个路线行不行,出发了再说吧😄

第一站中路藏寨。最后几公里路很狭窄,回车其实比较费劲,但是我们似乎是那个村子当天为数不多的几个客人,一路上都非常顺利。在村子里转了几圈以后,一个回头弯,一座笔直碉楼的碉楼矗立蔚蓝天空。那一秒,钟灵魂有一种刷新的震撼。驻足碉楼之下,不在对“他人沧海桑田,彼之浮尘”耿耿于怀,而是一种时间尺度压缩的踏实感。

第二站同样出现在一个山路的回头弯上——虽然在专心的开车,但是眼前被一抹明亮所吸引——沐浴在灿烂阳光下的雅拉雪山。虽然雪山见过不少了,但是这一抹亮色在那个时候是如此的独特与震撼。停车以后,久久的驻足、回望。

严格来说其实没有第三站。因为天色渐晚,我们又该找住处了。有时候不仅是最美的风景在路上,更是没有计划是最好的计划。从雪山观景台往新都桥的路上,翻过垭口,广袤的高山草原,牛马洒落,溪水蜿蜒,天际雪山围抱。这难道是曲水流觞的高原江南!

晚上住在康定的时候,我跟妞儿说,今天路过的地方正好经过了五月的天的民宿,今晚住的城市是自己很喜欢的小祝的根据地。以前我通过他们的视频了解了川西之美,没想到今天一天就都完成了打卡,也把自己去年自己生日想走的路线顺带完成了。更没想到的是,回成都路上,偶然发现这三天没有任何计划的出行居然完成了自己和家人的第一次川西环线。而这距离自己拥有第一辆车,对川西起心动念,已经跨越了12年。

如果不是这次的恣意而行,这次旅途的邂逅又会是多少年呢?20年?25年?也许永远都不会……路就在那里,鄙人就在成都,有些路,不妨出发的时候就只有出发。