上下文管理
Claude Code 如何收集、压缩、分配和管理对话上下文
上下文收集器
Context Collectors
Claude Code 的上下文由三大收集器组成,在每次对话开始时并行收集并缓存:
上下文收集架构
📋 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 消耗,生成可视化的网格图和详细统计。
上下文分析流程
系统提示词,包含工具说明和规则
内置工具定义(FileRead, Bash 等)
外部 MCP 服务器提供的工具
CLAUDE.md 和项目记忆文件
对话历史(用户+助手消息)
用户定义的自定义 Agent
技能工具的前置元数据
斜杠命令定义
剩余可用上下文空间
// 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 预算解析流程
📊 parseTokenBudget — 三种匹配模式
/^\s*\+(\d+(?:\.\d+)?)\s*(k|m|b)\b/i/\s\+(\d+(?:\.\d+)?)\s*(k|m|b)\s*[.!?]?\s*$/i/\b(?:use|spend)\s+(\d+(?:\.\d+)?)\s*(k|m|b)\s*tokens?\b/i// 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 层级
📬 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
在 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)