Claude Code泄漏的文件分析的Agent Skills等使用

4 阅读6分钟

Ai分析结果

—— 大模型如何调用 Agent、Skills 与上下文管理

基于 v2.1.88 源码的技术分析


目录

  1. Agent 调用机制
  2. Skills 调用机制
  3. 上下文管理机制
  4. 完整调用链路
  5. 关键设计模式

1. Agent 调用机制

1.1 AgentTool 输入参数

位置: src/tools/AgentTool/AgentTool.tsx (228KB, 1398 行)

核心输入 Schema:

const baseInputSchema = z.object({
  description: z.string().describe('3-5 字任务描述'),
  prompt: z.string().describe('要执行的任务'),
  subagent_type: z.string().optional().describe('使用的代理类型'),
  model: z.enum(['sonnet', 'opus', 'haiku']).optional().describe('模型覆盖'),
  run_in_background: z.boolean().optional().describe('是否后台运行')
})

1.2 三种执行模式详解

模式 A:同步执行(默认)—— 共享进程,独立对话

// src/tools/AgentTool/runAgent.ts:56-384
for await (const message of runAgent({
  agentDefinition,
  promptMessages,
  toolUseContext: { ...context },
  canUseTool,
  isAsync: false,
  querySource: 'agent:custom',
})) {
  agentMessages.push(message)
}

特点:

  • ✅ 共享同一进程,内存开销小
  • ✅ 共享文件缓存,减少重复 IO
  • ✅ 独立的消息历史 (messages[])
  • ⚡ 适合快速任务(读取文件、简单修改等)

模式 B:Fork 子进程 —— 完全隔离,资源独立

// src/tools/AgentTool/forkSubagent.ts:130-256
async function runForkedAgent(...) {
  // 1. 创建独立进程
  const child = forkAgentProcess({
    agentId,
    messages: buildForkedMessages(parent),
    tools: availableTools,
    cwd: worktreePath  // 可选的 git worktree 隔离
  })
  
  // 2. 共享文件缓存,独立消息历史
  return child.result
}

特点:

  • ✅ 独立进程空间,完全隔离
  • ✅ 共享文件缓存(性能优化)
  • ✅ 完全独立的对话历史
  • ✅ 可配置 git worktree 物理隔离
  • ⚡ 适合长期任务(功能开发、测试等)

模式 C:远程代理 —— 云端执行,资源弹性

// src/tasks/RemoteAgentTask/RemoteAgentTask.ts:88-267
async function launchRemoteAgent() {
  // 通过 Bridge 协议启动远程会话
  const session = await bridgeApi.createSession({
    type: 'remote_agent',
    resources: { cpu: 4, memory: '8GB' }
  })
  
  return { status: 'remote_launched', sessionUrl }
}

特点:

  • ✅ 远程服务器执行,不占用本地资源
  • ✅ 资源配置灵活(CPU/内存可调)
  • ✅ 可监控的会话 URL
  • ⚡ 适合重型任务(大型重构、数据分析等)

1.3 Agent 孵化的完整流程

graph TB
    A[用户请求] --> B[AgentTool.validateInput]
    B --> C[检查权限]
    C --> D{运行模式?}
    
    D -->|同步 | E[runAgent - 主线程]
    D -->|Fork| F[spawn 子进程]
    D -->|远程 | G[Bridge 远程会话]
    
    E --> H[独立的 query 循环]
    F --> H
    G --> H
    
    H --> I[工具执行]
    I --> J{需要权限?}
    J -->|是 | K[询问用户]
    J -->|否 | L[执行工具]
    
    K --> L
    L --> M{还有工具调用?}
    M -->|是 | I
    M -->|否 | N[返回结果]
    
    N --> O[追加 tool_result]
    O --> P[父代理继续]

1.4 多代理协作协议

团队管理 Schema:

// src/tools/AgentTool/AgentTool.tsx:89-97
const multiAgentInputSchema = z.object({
  name: z.string().optional().describe('可寻址的代理名称'),
  team_name: z.string().optional().describe('团队名称'),
  mode: permissionModeSchema().optional().describe('权限模式')
})

代理间通信工具:

// 通过 SendMessageTool 进行代理间通信
SendMessageTool.call({
  to: 'teammate-name',
  message: '请审查这个 PR'
})

2. Skills 调用机制

2.1 SkillsTool 架构与输入

位置: src/tools/SkillsTool/SkillsTool.ts (1109 行)

核心输入 Schema:

export const inputSchema = z.object({
  Skills: z.string().describe('技能名称,如 "commit", "review-pr"'),
  args: z.string().optional().describe('可选参数')
})

2.2 两种执行方式对比

方式 A:Inline 扩展 —— 轻量级提示词注入

核心流程 (call() 函数,第 634-775 行):

// 1. 加载 Skills 提示词
const command = findCommand(Skills, commands)

// 2. 处理提示词(!command 替换、$ARGUMENTS 插值)
const processedCommand = await processPromptSlashCommand(
  Skills, args, commands, context
)

// 3. 生成新消息注入对话
const newMessages = tagMessagesWithToolUseID(
  processedCommand.messages,
  toolUseID
)

// 4. 修改上下文(允许的工具、模型覆盖、努力程度)
return {
  data: { success: true, commandName: Skills },
  newMessages,
  contextModifier: ctx => ({
    ...ctx,
    options: {
      ...ctx.options,
      mainLoopModel: resolveSkillsModelOverride(
        command.model, 
        ctx.mainLoopModel
      )
    }
  })
}

特点:

  • ✅ 轻量级扩展,无额外进程开销
  • ✅ 直接注入对话,立即生效
  • ✅ 可动态修改上下文(工具权限、模型、努力程度)
  • ⚡ 适合简单工作流(代码审查、提交信息等)

方式 B:Fork 子代理 —— 隔离执行,实时进度

核心流程 (executeForkedSkills() 函数,第 122-289 行):

async function executeForkedSkills(command, args, context) {
  // 1. 准备隔离的上下文
  const { modifiedGetAppState, promptMessages, SkillsContent } = 
    await prepareForkedCommandContext(command, args, context)
  
  // 2. 在独立代理中运行
  for await (const message of runAgent({
    agentDefinition: { ...baseAgent, effort: command.effort },
    promptMessages,
    toolUseContext: { ...context, getAppState: modifiedGetAppState },
    querySource: 'agent:custom'
  })) {
    agentMessages.push(message)
    // 报告进度
    onProgress?.({ toolUseID, data: { message, type: 'Skills_progress' }})
  }
  
  // 3. 提取结果
  return {
    status: 'forked',
    agentId,
    result: extractResultText(agentMessages)
  }
}

特点:

  • ✅ 独立 token 预算,不占用父代理上下文
  • ✅ 隔离的执行环境,避免干扰
  • ✅ 实时进度报告(Skills_progress)
  • ✅ 可配置努力程度(effort)
  • ⚡ 适合复杂工作流(PR 审查、PDF 处理等)

2.3 Skills 发现与加载机制

三级 Skills 来源:

  1. 本地 Skillss: ~/.claude/Skillss/ 或项目 .claude/Skillss/
  2. MCP Skillss: 通过 MCP 协议连接的外部服务
  3. 远程 Skillss: AKI/GCS云存储(实验性,仅内部)

MCP Skillss 集成:

// src/tools/SkillsTool/SkillsTool.ts:81-94
async function getAllCommands(context) {
  // 从 AppState 获取 MCP Skillss
  const mcpSkillss = context.getAppState()
    .mcp.commands.filter(cmd => cmd.type === 'prompt' && cmd.loadedFrom === 'mcp')
  
  // 合并本地 Skillss
  const localCommands = await getCommands(getProjectRoot())
  return uniqBy([...localCommands, ...mcpSkillss], 'name')
}

远程 Skillss (实验性,仅内部):

// src/tools/SkillsTool/SkillsTool.ts:969-1108
async function executeRemoteSkills(slug, commandName, parentMessage, context) {
  // 从 AKI/GCS 加载远程 Skills
  const loadResult = await loadRemoteSkills(slug, meta.url)
  
  // 注入到对话
  return {
    data: { success: true, commandName, status: 'inline' },
    newMessages: [createUserMessage({ content: finalContent, isMeta: true })]
  }
}

2.4 Skills 权限检查流程

四步权限检查 (checkPermissions() 函数,第 432-578 行):

async function checkPermissions({ Skills, args }, context) {
  const commandObj = findCommand(Skills, commands)
  
  // 1. 检查拒绝规则(优先级最高)
  const denyRules = getRuleByContentsForTool(
    permissionContext, SkillsTool, 'deny'
  )
  if (denyRules.matches(Skills)) return { behavior: 'deny' }
  
  // 2. 检查允许规则
  const allowRules = getRuleByContentsForTool(
    permissionContext, SkillsTool, 'allow'
  )
  if (allowRules.matches(Skills)) return { behavior: 'allow' }
  
  // 3. 安全检查(仅允许安全属性)
  if (SkillsHasOnlySafeProperties(commandObj)) {
    return { behavior: 'allow' }
  }
  
  // 4. 默认:询问用户
  return {
    behavior: 'ask',
    suggestions: [
      { type: 'addRules', rule: { toolName: 'Skills', ruleContent: Skills } }
    ]
  }
}

安全属性白名单 (28 个):

const SAFE_Skills_PROPERTIES = new Set([
  'type', 'model', 'effort', 'source', 'context',
  'name', 'description', 'isEnabled', 'aliases',
  'paths', 'version', 'disableModelInvocation',
  // ... 共 28 个安全属性
])

匹配规则示例:

  • 精确匹配:commit → 允许 commit Skills
  • 前缀匹配:review:* → 允许所有 review- 开头的 Skillss

3. 上下文管理机制

3.1 三层压缩策略详解

阈值配置 (src/services/compact/autoCompact.ts):

export const AUTOCOMPACT_BUFFER_TOKENS = 13_000
export const WARNING_THRESHOLD_BUFFER_TOKENS = 20_000
export const ERROR_THRESHOLD_BUFFER_TOKENS = 20_000
export const MANUAL_COMPACT_BUFFER_TOKENS = 3_000

策略 A:autoCompact(自动总结)—— API 调用,智能压缩

触发条件:

function getAutoCompactThreshold(model: string): number {
  const effectiveContextWindow = getEffectiveContextWindowSize(model)
  return effectiveContextWindow - AUTOCOMPACT_BUFFER_TOKENS
}

压缩流程:

if (tokenCount >= autoCompactThreshold && !tracking.compacted) {
  // 1. 调用 Claude API 总结旧消息
  const { summary, boundaryMessage } = await compactConversation(messages)
  
  // 2. 重建消息数组
  messages = [summary, boundaryMessage, ...recentMessages]
  
  // 3. 标记已压缩,防止重复压缩
  tracking.compacted = true
}

特点:

  • ✅ 智能总结,保留关键信息
  • ✅ 需要 API 调用,有成本
  • ✅ 保留 compact_boundary 标记,支持恢复
  • ⚡ 适用于长对话场景

策略 B:snipCompact(剪切僵尸消息)—— 本地过滤,零成本

功能实现 (src/services/compact/snipCompact.js, feature-gated):

function snipCompact(messages) {
  // 移除过时的标记和僵尸消息
  const snipped = messages.filter(msg => {
    return !isZombieMarker(msg) && !isStaleProgress(msg)
  })
  
  const tokensFreed = countTokens(messages) - countTokens(snipped)
  return { snipped, tokensFreed }
}

特点:

  • ✅ 本地过滤,零 API 成本
  • ✅ 清理无效消息(zombie markers, stale progress)
  • ✅ 快速释放上下文空间
  • ⚡ 作为 autoCompact 的前置优化

策略 C:contextCollapse(重构上下文)—— 实验性结构优化

实验性功能 (src/services/contextCollapse/index.js, feature-gated):

async function contextCollapse(messages) {
  // 重构上下文结构以提高效率
  const restructured = await restructureContext(messages)
  return restructured
}

特点:

  • ✅ 重构消息结构,提升检索效率
  • ✅ 实验性功能,需 feature flag 开启
  • ⚡ 适用于超长对话场景

3.2 Session Memory(会话记忆)—— 跨会话学习

配置参数 (src/services/SessionMemory/sessionMemoryUtils.ts):

export const DEFAULT_SESSION_MEMORY_CONFIG = {
  minimumMessageTokensToInit: 10000,      // 初始化阈值
  minimumTokensBetweenUpdate: 5000,       // 更新阈值
  toolCallsBetweenUpdates: 3              // 工具调用间隔
}

提取流程:

async function extractSessionMemory(messages, config) {
  // 1. 检查是否达到初始化阈值(10K tokens)
  if (!sessionMemoryInitialized && 
      currentTokenCount >= config.minimumMessageTokensToInit) {
    await initializeSessionMemory()
    sessionMemoryInitialized = true
  }
  
  // 2. 检查是否达到更新阈值(5K tokens 增长)
  if (tokensSinceLastExtraction >= config.minimumTokensBetweenUpdate) {
    await updateSessionMemory(messages)
    recordExtractionTokenCount(currentTokenCount)
  }
  
  // 3. 持久化到磁盘(~/.claude/projects/<hash>/sessions/)
  await writeSessionMemory(memoryPath)
}

特点:

  • ✅ 自动提取会话关键信息
  • ✅ 双阈值控制(初始化 10K,更新 5K)
  • ✅ 每 3 次工具调用检查一次
  • ✅ 持久化到磁盘,支持崩溃恢复
  • ⚡ 实现跨会话学习和记忆

3.3 Memory Directory(记忆目录)—— 结构化知识库

目录结构:

~/.claude/projects/<hash>/memory/
├── MEMORY.md          # 入口文件(行为指令)
├── user/              # 用户记忆
├── feedback/          # 反馈记忆
├── project/           # 项目记忆
└── reference/         # 参考记忆

提示词构建 (src/memdir/memdir.ts:199-250):

export function buildMemoryLines(displayName: string, memoryDir: string) {
  return `
## ${displayName} (${memoryDir})

${DIR_EXISTS_GUIDANCE}

### 记忆类型(封闭分类)
1. **用户记忆**: 偏好、沟通风格、目标
2. **反馈记忆**: 对之前输出的明确反馈
3. **项目记忆**: 项目特定的知识(非代码可推导)
4. **参考记忆**: 外部资源、文档链接

### 何时访问
- 开始新任务时检索相关记忆
- 遇到模糊需求时查询用户偏好
- 收到反馈时更新反馈记忆
`
}

特点:

  • ✅ 四类封闭分类(user/feedback/project/reference)
  • ✅ 明确的访问指导
  • ✅ 目录存在性自动保证(无需 mkdir)
  • ⚡ 构建项目专属知识库

3.4 上下文字典管理 —— 主循环中的压缩逻辑

主循环实现 (src/query.ts:365-420):

async function* queryLoop(params) {
  let messages = params.messages
  
  while (true) {
    // 1. 获取压缩边界后的消息
    let messagesForQuery = [...getMessagesAfterCompactBoundary(messages)]
    
    // 2. 应用工具结果预算(限制 tool_result 大小)
    messagesForQuery = await applyToolResultBudget(
      messagesForQuery,
      contentReplacementState
    )
    
    // 3. 应用 Snip 压缩(如果启用 HISTORY_SNIP)
    if (feature('HISTORY_SNIP')) {
      const { snipped, tokensFreed } = await snipCompact(messagesForQuery)
      messagesForQuery = snipped
    }
    
    // 4. 检查是否需要自动压缩
    const tokenCount = tokenCountWithEstimation(messagesForQuery)
    if (tokenCount >= autoCompactThreshold) {
      const { summary } = await compactConversation(messagesForQuery)
      messagesForQuery = [summary, ...recentMessages]
    }
    
    // 5. 调用 Claude API
    const response = await claudeAPI({
      messages: messagesForQuery,
      systemPrompt,
      tools
    })
    
    // 6. 处理工具调用
    if (response.stop_reason === 'tool_use') {
      const toolResults = await runTools(response.content)
      messages = [...messagesForQuery, ...toolResults]
      continue
    }
    
    // 7. 返回最终响应
    yield response
    break
  }
}

压缩顺序:

  1. getMessagesAfterCompactBoundary() → 获取有效消息
  2. applyToolResultBudget() → 限制工具结果大小
  3. snipCompact() → 移除僵尸消息(可选)
  4. autoCompact() → 总结旧消息(如超过阈值)
  5. claudeAPI() → 调用模型

4. 完整调用链路

graph TB
    User[用户输入] --> QueryEngine[QueryEngine.query]
    
    QueryEngine --> BuildSystemPrompt[组装系统提示词]
    BuildSystemPrompt --> LoadMemories[加载记忆]
    
    LoadMemories --> SessionMemory[Session Memory]
    LoadMemories --> MemoryDir[Memory Directory]
    LoadMemories --> CLAUDEmd[CLAUDE.md 文件]
    
    BuildSystemPrompt --> NormalizeMessages[标准化消息]
    NormalizeMessages --> CheckCompact[检查压缩]
    
    CheckCompact --> AutoCompact{超过阈值?}
    AutoCompact -->|是 | Compact[压缩对话]
    AutoCompact -->|否 | CallAPI[调用 Claude API]
    
    Compact --> CallAPI
    
    CallAPI --> StreamEvents[流式事件]
    StreamEvents --> TextBlock[文本块]
    StreamEvents --> ToolUseBlock[工具使用块]
    
    TextBlock --> YieldToUser[返回给用户]
    
    ToolUseBlock --> FindTool[查找工具]
    FindTool --> AgentTool{AgentTool?}
    FindTool --> SkillsTool{SkillsTool?}
    FindTool --> OtherTool[其他工具]
    
    AgentTool --> RunSubAgent[运行子代理]
    RunSubAgent --> ForkContext[Fork 上下文]
    ForkContext --> IndependentLoop[独立 query 循环]
    IndependentLoop --> ReturnResult[返回结果]
    
    SkillsTool --> LoadSkills[加载 Skills]
    LoadSkills --> ExpandPrompt[扩展提示词]
    ExpandPrompt --> InjectMessages[注入消息]
    InjectMessages --> ContinueLoop[继续循环]
    
    OtherTool --> ExecuteTool[执行工具]
    ExecuteTool --> AppendResult[追加 tool_result]
    
    ReturnResult --> AppendResult
    ContinueLoop --> AppendResult
    
    AppendResult --> RecordTranscript[记录到磁盘]
    RecordTranscript --> LoopBack{还有工具?}
    
    LoopBack -->|是 | CallAPI
    LoopBack -->|否 | YieldFinal[返回最终结果]

5. 关键设计模式

5.1 上下文隔离与共享

子代理的上下文设计:

const forkedContext = {
  ...parentContext,
  messages: [],           // 空消息历史(隔离)
  fileCache: shared,      // 共享文件缓存(性能)
  workingDirectory: worktreePath  // 独立工作目录(可选)
}

设计优势:

  • ✅ 保持对话清洁(独立 messages[])
  • ✅ 避免上下文污染(独立 token 预算)
  • ✅ 共享资源减少重复 IO(共享 fileCache)
  • ✅ 独立工作目录避免冲突(worktree 隔离)

5.2 懒加载与预取

技能发现预取:

// 不阻塞的异步预取(利用工具执行时间)
const pendingSkillsPrefetch = SkillsPrefetch?.startSkillsDiscoveryPrefetch(
  null, messages, toolUseContext
)

// 等待完成(在工具执行后)
await pendingSkillsPrefetch?.consume()

记忆预取:

using pendingMemoryPrefetch = startRelevantMemoryPrefetch(
  messages, toolUseContext
)
await pendingMemoryPrefetch?.consume()

设计优势:

  • ✅ 利用工具执行时间(隐藏加载延迟)
  • ✅ 异步预取,不阻塞主流程
  • ✅ 提升用户体验(减少等待感)

5.3 权限传递与覆盖

Skills 动态修改权限上下文:

contextModifier(ctx) {
  if (allowedTools.length > 0) {
    return {
      ...ctx,
      getAppState() {
        const appState = previousGetAppState()
        return {
          ...appState,
          toolPermissionContext: {
            ...appState.toolPermissionContext,
            alwaysAllowRules: {
              ...alwaysAllowRules,
              command: [...new Set([...alwaysAllowRules.command, ...allowedTools])]
            }
          }
        }
      }
    }
  }
}

设计优势:

  • ✅ 细粒度权限控制(按 Skills 定制)
  • ✅ 动态调整策略(contextModifier)
  • ✅ 安全的权限继承(Set 去重)
  • ✅ 作用域限定(仅当前 Skills 执行期间)

5.4 渐进式压缩与降级

多层压缩策略:

const compressionStrategies = {
  autoCompact: '总结旧消息(API 调用,智能但昂贵)',
  snipCompact: '移除僵尸消息(本地过滤,零成本)',
  contextCollapse: '重构上下文结构(实验性)'
}

降级机制:

if (autoCompactFailed) {
  trySnipCompact()  // 尝试轻量级压缩
  if (stillOverLimit) {
    throw PromptTooLongError  // 最终抛出错误
  }
}

设计优势:

  • ✅ 多层次策略应对不同场景
  • ✅ 成本梯度(snip → auto → collapse)
  • ✅ 降级机制保证可靠性
  • ✅ 最大化利用上下文窗口

5.5 持久化与恢复

对话记录:

// src/utils/sessionStorage.js
async function recordTranscript(message) {
  // 追加写入 JSONL 文件
  await appendFile(sessionLogPath, JSON.stringify(message) + '\n')
}

恢复流程:

// src/commands/resume.js
async function resumeSession(sessionId) {
  const messages = await readJSONL(sessionLogPath)
  const lastMessage = messages[messages.length - 1]
  
  // 重建对话状态
  return rebuildStateFromMessages(messages)
}

设计优势:

  • ✅ 追加写入(order-preserving queue)
  • ✅ JSONL 格式(易解析,易恢复)
  • ✅ 支持 --continue 和 --resume
  • ✅ 崩溃后可完全恢复状态

核心设计总结

Claude Code 的 Agent/Skills/上下文管理系统展现了生产级 AI 代理的复杂性,其核心设计理念包括:

1. 渐进式增强

从基础的"调用 API→执行工具"循环开始,逐层添加压缩、记忆、多代理、权限等生产特性

2. 分层隔离

  • 同步/Fork/远程三种代理模式
  • 不同的隔离级别和资源管理
  • 共享文件缓存 vs 独立消息历史

3. 弹性上下文管理

  • 三层压缩策略应对不同场景
  • Session Memory 提供跨会话学习
  • Memory Directory 实现结构化知识

4. 安全优先的权限系统

  • 细粒度的权限控制
  • 动态修改和继承
  • 白名单机制保护未知风险

5. 全面的持久化

  • 所有对话记录到磁盘
  • 支持崩溃恢复
  • 会话恢复机制

文档生成时间: 2026-04-01
分析版本: Claude Code v2.1.88
核心文件:

  • src/tools/AgentTool/AgentTool.tsx (1,398 行)
  • src/tools/SkillsTool/SkillsTool.ts (1,109 行)
  • src/query.ts (1,730 行)
  • src/services/compact/autoCompact.ts (352 行)
  • src/services/SessionMemory/sessionMemoryUtils.ts (208 行)
  • src/memdir/memdir.ts (508 行)