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

173 阅读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 行)