Skip to content

11 子智能体与技能系统原理(复杂任务怎么拆,怎么持续更新)

这篇把两个核心能力讲透:

  1. 子智能体编排(任务分治)
  2. 技能快照系统(能力热更新)

核心源码入口

  • src/agents/tools/sessions-spawn-tool.ts
  • src/agents/subagent-registry.ts
  • src/agents/subagent-announce.ts
  • src/agents/tools/sessions-send-tool.ts
  • src/agents/skills.ts
  • src/agents/skills/workspace.ts
  • src/agents/skills/refresh.ts
  • src/agents/skills/env-overrides.ts
  • src/infra/skills-remote.ts
  • src/agents/pi-embedded-runner/run/attempt.ts

模块一 子智能体 spawn 状态机

createSessionsSpawnTool(...) 的真实流程:

  1. 参数解析:task/agentId/model/thinking/runTimeoutSeconds/cleanup
  2. 递归防护:若当前会话是 subagent(isSubagentSessionKey(...))直接拒绝
  3. agent 白名单:subagents.allowAgents 校验跨 agent spawn 权限
  4. 创建子会话 key:agent:<target>:subagent:<uuid>
  5. 可选配置覆盖:
  • sessions.patch 写 model
  • sessions.patch 写 thinkingLevel
  1. 构造子系统提示:buildSubagentSystemPrompt(...)
  2. 调网关启动子运行:method=agent(lane=AGENT_LANE_SUBAGENT
  3. 注册生命周期:registerSubagentRun(...)

模块二 子运行生命周期管理

subagent-registry.ts 做了几件很工程化的事:

  1. 内存 + 落盘:subagentRuns + saveSubagentRegistryToDisk(...)
  2. 启动恢复:restoreSubagentRunsOnce(),重启后恢复未完成 run
  3. 等待完成:
  • 事件监听 onAgentEvent(lifecycle)
  • RPC 兜底 agent.wait
  1. 通知主会话:runSubagentAnnounceFlow(...)
  2. 清理策略:
  • cleanup=delete 删除子会话
  • cleanup=keep 保留结果
  1. 归档清扫:按 archiveAfterMinutes 定时清理历史 run

这就是“子任务不会丢、重启也能续”的关键。

模块三 子结果回传机制

runSubagentAnnounceFlow(...) 的关键设计:

  1. 先等待 child run 彻底 settled(避免压缩重试中提前汇报)
  2. 构造 triggerMessage 给主智能体,不直接对用户硬回写
  3. 由主智能体用自己的语气二次总结,保证对话风格一致
  4. 支持 NO_REPLY,允许内部子任务静默完成

模块四 sessions_send 的跨会话协同

sessions_send 不是简单转发,它支持:

  1. sessionKeylabel 定位目标会话
  2. sandbox 可见性限制(sessionToolsVisibility=spawned
  3. agent-to-agent 策略校验(tools.agentToAgent.allow
  4. 嵌套 lane 执行:AGENT_LANE_NESTED
  5. A2A 宣告流:runSessionsSendA2AFlow(...)

模块五 技能快照系统原理

skills/workspace.ts 负责把散落技能文件变成稳定快照:

  1. 多来源合并与优先级:
  • extra < bundled < managed < personal < project < workspace
  1. 生成快照:buildWorkspaceSkillSnapshot(...)
  • prompt
  • skills(含 primaryEnv
  • resolvedSkills
  • version
  1. 执行时取 prompt:resolveSkillsPromptForRun(...)(优先 snapshot)

模块六 技能热更新与环境注入

热更新

ensureSkillsWatcher(...)

  1. 监听 SKILL.md add/change/unlink
  2. debounce 后 bumpSkillsSnapshotVersion(...)
  3. 通过 getSkillsSnapshotVersion(...) 驱动新轮执行刷新

环境注入

applySkillEnvOverrides(...) / applySkillEnvOverridesFromSnapshot(...)

  1. 按 skill config 写入 env
  2. primaryEnv + apiKey 自动注入
  3. 返回 restore 函数,执行结束后回滚环境

模块七 远程技能能力同步(多设备场景)

skills-remote.ts 解决“技能依赖的系统命令在远程节点是否可用”:

  1. 维护远程节点缓存:remoteNodes(nodeId、platform、commands、bins)
  2. 启动预热:primeRemoteSkillsCache() 从 pairing 信息恢复节点能力
  3. 能力探测:refreshRemoteNodeBins(...) 通过远程命令探测可执行 bin
  4. 版本联动:远程能力变化后 bumpSkillsSnapshotVersion({ reason: "remote-node" })

意思是:不仅本地 SKILL.md 变化会触发快照更新,远程节点能力变化也会触发更新。

最小复刻骨架

ts
async function spawnSubagent(task: string, parent: SessionCtx) {
  if (parent.isSubagent) throw new Error("subagent cannot spawn subagent");
  const childSessionKey = `agent:${parent.agentId}:subagent:${crypto.randomUUID()}`;
  const runId = await gateway.agent({
    sessionKey: childSessionKey,
    message: task,
    lane: "subagent",
    extraSystemPrompt: buildSubPrompt(task, parent.sessionKey, childSessionKey),
  });
  registerSubagentRun({ runId, childSessionKey, requesterSessionKey: parent.sessionKey });
  return runId;
}

function buildSkillsContext(workspaceDir: string, cfg: Config) {
  const version = getSkillsSnapshotVersion(workspaceDir);
  const snapshot = buildWorkspaceSkillSnapshot(workspaceDir, { config: cfg, snapshotVersion: version });
  const restoreEnv = applySkillEnvOverridesFromSnapshot({ snapshot, config: cfg });
  return { snapshot, restoreEnv };
}

自检清单

  1. 子智能体是否被禁止再递归 spawn。
  2. 主进程重启后未完成子任务是否能恢复。
  3. 子任务结果是否稳定回传主会话。
  4. cleanup=delete/keep 是否行为可预测。
  5. 修改 SKILL.md 后下一轮是否拿到新 snapshot version。
  6. 技能注入的 env 是否在结束后正确回滚。

用工程视角拆解 AI 智能体框架