🧠

上下文管理

Claude Code 如何收集、压缩、分配和管理对话上下文

核心机制

上下文收集器

Context Collectors

Claude Code 的上下文由三大收集器组成,在每次对话开始时并行收集并缓存:

上下文收集架构

SystemContextGit StatusBranch InfoUserContextCLAUDE.mdCurrent DateAPI Cache Key

📋 getSystemContext()

系统级上下文,每次对话开始时收集一次并使用 memoize 缓存。

  • Git Status — 当前分支、主分支、工作区状态(截断至 2000 字符)、最近 5 条提交
  • Git User — 用户名配置
  • Cache Breaker — 调试用的系统提示注入(仅 ant 环境)

👤 getUserContext()

用户级上下文,包含项目配置和元数据,同样被 memoize 缓存。

  • CLAUDE.md — 从项目根目录向上遍历发现,合并多层 CLAUDE.md 文件
  • Memory Files — 过滤注入的记忆文件(filterInjectedMemoryFiles)
  • Current Date — ISO 格式的当前日期
  • Bare Mode--bare 模式跳过自动发现,仅加载显式目录
// context.ts — 上下文收集主入口
export const getSystemContext = memoize(async () => {
  const gitStatus = await getGitStatus();  // 分支 + status + commits
  return { gitStatus };
});

export const getUserContext = memoize(async () => {
  const claudeMd = shouldDisableClaudeMd
    ? null
    : getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles()));
  return { claudeMd, currentDate: `Today's date is ${getLocalISODate()}.` };
});

上下文使用分析

analyzeContextUsage

analyzeContextUsage() 是上下文管理的核心函数,并行计算所有上下文块的 token 消耗,生成可视化的网格图和详细统计。

上下文分析流程

Messages + ToolsSystem PromptMemory FilesTool DefinitionsMessagesMCP ToolsCustom AgentsContext GridContextData
System prompt

系统提示词,包含工具说明和规则

System tools

内置工具定义(FileRead, Bash 等)

MCP tools

外部 MCP 服务器提供的工具

Memory files

CLAUDE.md 和项目记忆文件

Messages

对话历史(用户+助手消息)

Custom agents

用户定义的自定义 Agent

Skills

技能工具的前置元数据

Slash commands

斜杠命令定义

Free space

剩余可用上下文空间

// analyzeContextUsage 返回的 ContextData 结构
interface ContextData {
  categories: ContextCategory[];     // 各上下文块的 token 分布
  totalTokens: number;               // 总 token 使用量
  maxTokens: number;                 // 上下文窗口大小
  percentage: number;                // 使用百分比
  gridRows: GridSquare[][];          // 可视化网格数据
  model: string;                     // 当前模型
  memoryFiles: MemoryFile[];         // 记忆文件详情
  mcpTools: McpTool[];               // MCP 工具详情
  agents: Agent[];                   // 自定义 Agent 列表
  messageBreakdown?: {               // 消息级别 token 分解
    toolCallTokens: number;
    toolResultTokens: number;
    userMessageTokens: number;
    assistantMessageTokens: number;
    toolCallsByType: Array<{ name: string; callTokens: number; resultTokens: number }>;
  };
}

Token 预算管理

Token Budget

Claude Code 支持用户在对话中指定 Token 预算,系统会解析自然语言中的预算声明并追踪进度。

🔄 Token 预算解析流程

用户输入
+500k / use 2M tokens
正则匹配
3 种正则模式
后缀解析
k/m/b → 数值
预算值
number

📊 parseTokenBudget — 三种匹配模式

简写前缀匹配(以 + 开头,位于行首)
/^\s*\+(\d+(?:\.\d+)?)\s*(k|m|b)\b/i
"+500k 开发这个功能""+2m 分析整个代码库"
简写后缀匹配(以 + 开头,位于句尾)
/\s\+(\d+(?:\.\d+)?)\s*(k|m|b)\s*[.!?]?\s*$/i
"预算 +500k.""请用 +2m tokens。"
详细模式匹配(全文匹配,不限制位置)
/\b(?:use|spend)\s+(\d+(?:\.\d+)?)\s*(k|m|b)\s*tokens?\b/i
"use 2M tokens""spend 500k tokens"
// utils/tokenBudget.ts
const MULTIPLIERS: Record<string, number> = {
  k: 1_000,
  m: 1_000_000,
  b: 1_000_000_000,
};

export function parseTokenBudget(text: string): number | null {
  // 1. 简写前缀: "+500k"
  const startMatch = text.match(SHORTHAND_START_RE);
  if (startMatch) return parseBudgetMatch(startMatch[1], startMatch[2]);
  // 2. 简写后缀: "预算 +500k."
  const endMatch = text.match(SHORTHAND_END_RE);
  if (endMatch) return parseBudgetMatch(endMatch[1], endMatch[2]);
  // 3. 详细模式: "use 2M tokens"
  const verboseMatch = text.match(VERBOSE_RE);
  if (verboseMatch) return parseBudgetMatch(verboseMatch[1], verboseMatch[2]);
  return null;
}

export function getBudgetContinuationMessage(
  pct: number, turnTokens: number, budget: number
): string {
  return `Stopped at ${pct}% of token target (${turnTokens} / ${budget}). Keep working.`;
}

Context Provider 体系

React Context Architecture

Claude Code 使用多个 React Context Provider 管理不同维度的运行时状态。以下是核心 Provider 的职责和设计模式。

Context Provider 层级

AppStoreMailboxStatsOverlayModalNotificationsFpsMetricsVoiceQueuedMsgPromptOverlay

📬 Mailbox — 消息队列

Mailbox 是一个全局消息队列,使用 useMemo 创建单例, 通过 Context 向下传递。所有子组件都可以向队列发送消息或消费消息。

// context/mailbox.tsx
const MailboxContext = createContext<Mailbox | undefined>(undefined);

export function MailboxProvider({ children }: Props) {
  const mailbox = useMemo(() => new Mailbox(), []);
  return (
    <MailboxContext.Provider value={mailbox}>
      {children}
    </MailboxContext.Provider>
  );
}

export function useMailbox(): Mailbox {
  const mailbox = useContext(MailboxContext);
  if (!mailbox) throw new Error("useMailbox must be used within a MailboxProvider");
  return mailbox;
}

⚡ FpsMetrics — 帧率指标

通过 getter 函数而非直接值传递帧率数据,避免不必要的重渲染。 组件只在需要时调用 useFpsMetrics() 获取当前帧率。

// context/fpsMetrics.tsx
type FpsMetricsGetter = () => FpsMetrics | undefined;
const FpsMetricsContext = createContext<FpsMetricsGetter | undefined>(undefined);

export function FpsMetricsProvider({ getFpsMetrics, children }: Props) {
  return (
    <FpsMetricsContext.Provider value={getFpsMetrics}>
      {children}
    </FpsMetricsContext.Provider>
  );
}

export function useFpsMetrics() {
  return useContext(FpsMetricsContext);
}

🪟 ModalContext — 模态窗口上下文

ModalContext 由 FullscreenLayout 设置,当内容渲染在模态插槽中时提供精确的行列数和滚动引用。 子组件使用 useModalOrTerminalSize() 替代useTerminalSize() 以获取正确的可用空间。

// context/modalContext.tsx
type ModalCtx = {
  rows: number;
  columns: number;
  scrollRef: RefObject<ScrollBoxHandle | null> | null;
};

export function useIsInsideModal(): boolean {
  return useContext(ModalContext) !== null;
}

export function useModalOrTerminalSize(fallback: { rows: number; columns: number }) {
  const ctx = useContext(ModalContext);
  return ctx ? { rows: ctx.rows, columns: ctx.columns } : fallback;
}

🔔 Notifications — 通知系统

基于优先级的队列式通知系统,支持 4 个优先级:immediate>high>medium>low。 支持 fold(合并同 key 通知)和 invalidates(自动移除过期通知)。

// context/notifications.tsx
type Priority = 'low' | 'medium' | 'high' | 'immediate';

type BaseNotification = {
  key: string;
  invalidates?: string[];    // 自动移除这些 key 的通知
  priority: Priority;
  timeoutMs?: number;        // 默认 8000ms
  fold?: (acc, incoming) => Notification;  // 合并同 key 通知
};

const PRIORITIES: Record<Priority, number> = {
  immediate: 0, high: 1, medium: 2, low: 3,
};

// immediate 优先级直接打断当前通知,其他排入队列按优先级消费

🔲 OverlayContext — 覆盖层追踪

解决 Escape 键冲突:当覆盖层(如 Select 下拉)打开时,CancelRequestHandler 不会误取消请求。 区分模态覆盖层(如 Select)和非模态覆盖层(如 autocomplete)。

// context/overlayContext.tsx
const NON_MODAL_OVERLAYS = new Set(['autocomplete']);

export function useRegisterOverlay(id: string, enabled = true): void {
  // mount 时注册,unmount 时自动注销
  useEffect(() => {
    if (!enabled) return;
    setAppState(prev => ({
      ...prev,
      activeOverlays: new Set(prev.activeOverlays).add(id),
    }));
    return () => { /* 从 Set 中删除 id */ };
  }, [id, enabled]);
}

export function useIsOverlayActive(): boolean {
  return useAppState(s => s.activeOverlays.size > 0);
}

export function useIsModalOverlayActive(): boolean {
  return useAppState(s => {
    for (const id of s.activeOverlays) {
      if (!NON_MODAL_OVERLAYS.has(id)) return true;
    }
    return false;
  });
}

📈 Stats — 统计指标存储

使用水库采样(Reservoir Sampling, Algorithm R)实现固定内存的直方图统计, 支持 counter、gauge、timer、set 四种指标类型。进程退出时自动持久化到项目配置。

// context/stats.tsx
const RESERVOIR_SIZE = 1024;

export function createStatsStore(): StatsStore {
  const histograms = new Map<string, Histogram>();
  return {
    increment(name, value = 1) { /* 计数器 */ },
    set(name, value) { /* 仪表盘 */ },
    observe(name, value) { /* 直方图 + 水库采样 */ },
    add(name, value) { /* 集合去重 */ },
    getAll() {
      // 输出: name_count, name_min, name_max, name_avg, name_p50, name_p95, name_p99
    },
  };
}

// Hooks: useCounter, useGauge, useTimer, useSet

💬 PromptOverlayContext — 提示浮层

使用数据/设置器 Context 对分离模式,写入者不会因自己的写入而重渲染。 支持两个通道:斜杠命令建议数据和任意对话框节点。

// context/promptOverlayContext.tsx
// 数据/设置器 Context 对分离 — setter 永远稳定,不触发重渲染
const DataContext = createContext<PromptOverlayData | null>(null);
const SetContext = createContext<Setter<PromptOverlayData> | null>(null);
const DialogContext = createContext<ReactNode>(null);
const SetDialogContext = createContext<Setter<ReactNode> | null>(null);

export function useSetPromptOverlay(data: PromptOverlayData | null) {
  const set = useContext(SetContext);
  useEffect(() => {
    if (!set) return;
    set(data);
    return () => set(null); // unmount 时自动清除
  }, [set, data]);
}

压缩策略

Context Compaction

Claude Code 实现了多层压缩策略来管理有限的上下文窗口:

🟢Micro Compact
🟡Auto Compact
🔴Manual Compact
🟢

Micro Compact

在 analyzeContextUsage 中自动调用,对消息进行微压缩以减少 token 估算值。 不改变消息结构,仅去除冗余信息。

🟡

Auto Compact

上下文使用率接近窗口上限时自动触发。 预留 AUTOCOMPACT_BUFFER_TOKENS 的安全缓冲区。 支持 reactive-only 模式(tengu_cobalt_raccoon 特性标志)。

🔴

Manual Compact

用户通过 /compact 命令手动触发。 预留 MANUAL_COMPACT_BUFFER_TOKENS(3k)的缓冲区。

// 压缩缓冲区计算
const AUTOCOMPACT_BUFFER_TOKENS = 33_000;  // 自动压缩缓冲区
const MANUAL_COMPACT_BUFFER_TOKENS = 3_000; // 手动压缩缓冲区

// 上下文网格计算
const GRID_WIDTH = contextWindow >= 1_000_000 ? 20 : 10;
const GRID_HEIGHT = 10;
const TOTAL_SQUARES = GRID_WIDTH * GRID_HEIGHT;

// 每个方块代表 contextWindow / TOTAL_SQUARES 个 token
// 颜色编码不同上下文类别,形成可视化热力图

工具延迟加载

Tool Search & Deferred Loading

当工具数量较多时,Claude Code 启用 Tool Search 机制:工具定义不会全部加载到上下文中, 而是通过 ToolSearchTool 按需加载。延迟工具不计入上下文使用量,但会单独显示。

📦 延迟加载的工具

  • 定义 token 已计算但不计入使用量
  • 通过 ToolSearchTool 按需加载(搜索 → 调用)
  • 已使用的工具标记为 isLoaded: true

✅ 始终加载的工具

  • 核心内置工具(FileRead, Bash, Grep 等)
  • Token 定义计入上下文使用量
  • 每工具有固定 500 token 的 API 开销(TOOL_TOKEN_COUNT_OVERHEAD