缘起
用 GitHub Copilot (Agent Mode) 写了一整天代码后,我突然好奇:这个 128K 的 Context Window,到底被谁瓜分了?
VS Code 提供了一个隐藏的 Context Window 使用面板,展示了当前会话中每一类内容的 token 占比。我截取了一张,看完之后觉得这个话题值得深入拆解——因为这直接关系到你的 AI 编程助手到底在多大程度上理解你的代码。

VS Code 中的 Context Window 使用面板(Settings → "context window")
下面我们逐项拆解截图中的每一行,追溯到磁盘上的具体文件。
全景数据
我的这次会话快照:
还没聊几轮就用掉了将近一半。每一项占比如下:
下面逐项拆解,追溯到磁盘上的具体文件路径。
1. System Instructions(9.0% ≈ 11,520 tokens)
系统指令是每次 API 调用都会携带的"底色"——你还没说话,它已经在了。
它由 三层 叠加而成:
| 层级 | 来源文件 | 内容 | ≈ tokens |
|---|---|---|---|
| ① Copilot 内置 | ~/.vscode/extensions/github.copilot-chat-0.37.8/dist/extension.js | 身份提示 "You are a highly sophisticated automated coding agent..."、输出格式规则、KaTeX 指令、Markdown Linkification 规则、Notebook 指令 | ~4,000 |
| ② 项目指令 | .github/copilot-instructions.md → 符号链接 → CLAUDE.md | 项目导航地图、命令手册、架构图、Content Conventions、Communication Style | ~3,000 |
| ③ Skills 描述列表 | .claude/skills/*/SKILL.md (30 个)~/.claude/skills/*/SKILL.md (20 个) | 每个 Skill 的 name + description + file 路径,打包成列表注入 system prompt | ~4,000 |
层级 ①:Copilot 硬编码提示
藏在一个 17MB 的压缩 JS 文件里:
~/.vscode/extensions/github.copilot-chat-0.37.8/dist/extension.js
用 grep 能挖出多条系统提示模板,分别对应不同场景:
$ grep -oE '"You are [^"]{20,80}"' extension.js | head -4
"You are a helpful code reviewer who..."
"You are a highly sophisticated automated coding agent with expert-level knowledge."
"You are a strictly grounded assistant limited to the"
"You are a coding agent running in VS Code. You are expected to be precise, safe, and helpful."
不同的 Chat Participant(github.copilot.default、github.copilot.editsAgent、github.copilot.notebook...)会选用不同的系统提示模板。在 Agent Mode 下,用的是那条最长的 "highly sophisticated automated coding agent"。
层级 ②:项目指令(你自己写的)
这是最有意思的发现——我的仓库里有个符号链接:
$ ls -la .github/copilot-instructions.md
lrwxr-xr-x 1 polly staff 12 1月 30 23:49
.github/copilot-instructions.md -> ../CLAUDE.md
一个文件,两个入口:Claude Code 读 CLAUDE.md,VS Code Copilot 读 .github/copilot-instructions.md,实际是同一个 293 行的项目指令文件。这是我当初有意为之的设计——维护一份文档,两个 AI 编程助手都能读到。
层级 ③:Skills 描述列表
这部分跟我在 Skill Pipeline 深度拆解 中分析的完全对应。Copilot 会扫描两个层级的 Skills:
Workspace 级(30 个): .claude/skills/*/SKILL.md
User 级(20 个): ~/.claude/skills/*/SKILL.md
每个 Skill 只抽取 name 和 description 字段(约 100-150 tokens),打包成一个列表注入 system prompt。30 + 20 = 50 个 Skill 描述 × ~80 tokens ≈ 4,000 tokens。
2. Tool Definitions(10.9% ≈ 13,952 tokens)
工具定义比系统提示还大——它是最沉默的 token 大户。
| 类型 | 来源 | 内容 | ≈ tokens |
|---|---|---|---|
| 内置工具 (Active) | extension.js 硬编码 | read_file、grep_search、replace_string_in_file、run_in_terminal、semantic_search、create_file、list_dir、manage_todo_list 等 ~15 个工具的完整 JSON Schema | ~8,000 |
| Deferred 工具列表 | extension.js 硬编码 | fetch_webpage、run_notebook_cell、get_changed_files 等 ~50 个工具的名称 + 简述 | ~3,000 |
| MCP 外部工具 | .claude/settings.json + MCP 服务器动态注册 | mcp_master-transl_*、mcp_tavily-remote_*、mcp_pylance_* 等 | ~3,000 |
每个工具定义长什么样?大概是这样的 JSON Schema:
{
"name": "read_file",
"description": "Read the contents of a file.\n\nYou must specify the line range...",
"parameters": {
"properties": {
"filePath": { "description": "The absolute path of the file to read.", "type": "string" },
"startLine": { "description": "The line number to start reading from, 1-based.", "type": "number" },
"endLine": { "description": "The inclusive line number to end reading at, 1-based.", "type": "number" }
},
"required": ["filePath", "startLine", "endLine"]
}
}
read_file 算简单的,大约 300 tokens。而 run_in_terminal 带了一堆使用指南(Directory Management、Background Processes、Output Management...),轻松到 800 tokens。
用 grep 统计各工具在 extension.js 中的引用次数:
$ grep -oE 'replace_string_in_file|semantic_search|read_file|run_in_terminal' extension.js \
| sort | uniq -c | sort -rn
195 replace_string_in_file # 引用最多——因为使用指南长
84 semantic_search
74 read_file
67 run_in_terminal
39 manage_todo_list
36 grep_search
12 create_file
6 list_dir
Deferred Tools:按需加载的优化
Copilot 并不是把所有 ~60 个工具的完整 Schema 都塞进去(那要 30,000+ tokens)。它用了一个聪明的分层策略:
- Active Tools(~15 个):完整 JSON Schema 直接注入,每次调用都带
- Deferred Tools(~50 个):只放名称 + 一句话描述,需要时通过
tool_search_tool_regex动态加载完整定义
Active: read_file, grep_search, run_in_terminal, create_file... → 完整 Schema
Deferred: fetch_webpage, run_notebook_cell, install_extension... → 名称 + 简述
这就是为什么你有时在对话中看到 Copilot 先调 tool_search_tool_regex 再调目标工具——它在"按需展开"一个 Deferred Tool 的完整 Schema。
3. Messages(13.8% ≈ 17,664 tokens)
这是唯一没有独立磁盘文件源头的部分——它就是你和 AI 聊的内容本身。
| 组成 | 来源 | 说明 |
|---|---|---|
| 对话历史 | VS Code 内存 + workspaceStorage/state.vscdb | 你的每条消息 + AI 的每条回复,按时间顺序累积 |
| Conversation Summary | Copilot 动态生成 | 对话变长时,早期内容被压缩为 <conversation-summary> XML 块 |
持久化位置:
~/Library/Application Support/Code/User/workspaceStorage/<hash>/
└── state.vscdb ← SQLite 数据库,存储 chat 会话历史
Messages 是 Context Window 中增长最快的部分。每多一轮对话,你的可用空间就少一些。当接近窗口上限时,Copilot 会开始压缩早期对话——这就是长会话后期"失忆"的根本原因。
4. Files(5.7% ≈ 7,296 tokens)
这部分来自你主动提供或编辑器自动携带的文件上下文:
| 类型 | 来源 | 注入方式 |
|---|---|---|
| 用户附加文件 | 你在编辑器中选中的内容(如 CLAUDE.md 293 行) | <attachment> XML 标签包裹,完整内容注入 |
| 编辑器上下文 | 当前打开的文件路径 + 光标位置 | <editorContext> 标签,路径 + 选区信息 |
| Workspace 结构 | 工作目录的目录树摘要 | <workspace_info> 标签,自动生成 |
这里的关键优化点:不要无脑附加大文件。把一个 500 行文件选中拖进聊天 = 白白吃掉 ~3000 tokens。只在需要时选中相关代码段。
5. Tool Results(7.6% ≈ 9,728 tokens)
每次 AI 调用工具后,工具的返回结果也要放回 Context Window——因为 LLM 需要看到结果才能继续推理。
| 工具 | 返回内容 | Token 消耗 |
|---|---|---|
read_file | 文件内容 | ~2000/300行 |
grep_search | 搜索结果列表 | ~500/次 |
run_in_terminal | 命令输出 | 变化大 |
get_errors | 编译/lint 错误 | ~100/次 |
runSubagent | 子代理报告 | ~2000/次 |
Tool Results 是"隐形消费"大户。你让 AI 读一个文件 → ~2000 tokens,再读一个 → +2000,跑个 git push → +500...不知不觉就累积了将近 10,000 tokens。
6. Other(0.5% ≈ 640 tokens)
最小的一块,但也值得知道它是什么:
<environment_info>macOS</environment_info>
<context>
Terminals: zola, node, zsh...
Last Command: git push
Cwd: /Users/polly/.../www.polly.com
Exit Code: 0
</context>
来自 VS Code 运行时环境采集:操作系统类型、已开的终端、最近执行的命令、当前工作目录。这些帮助 AI 理解你的开发环境上下文。
全景磁盘地图
把所有来源汇总到一张文件树上:
~/.vscode/extensions/github.copilot-chat-0.37.8/
├── dist/extension.js # 17MB,包含:
│ ├── System Prompt 模板 # "You are a highly sophisticated..."
│ ├── Tool JSON Schemas # read_file, grep_search, ...
│ ├── Deferred Tools 列表 # ~50 个工具名称+简述
│ ├── Skill 加载逻辑 # .claude/skills 目录扫描
│ └── Context 组装器 # 拼接所有来源
└── package.json # 12 个 chatParticipant 注册
<workspace>/
├── CLAUDE.md # 项目指令 (293 行)
├── .github/
│ ├── copilot-instructions.md→../CLAUDE.md # 符号链接!
│ └── prompts/ # 16 个 prompt 模板 (按需)
├── .claude/
│ ├── settings.json # MCP 服务器配置
│ └── skills/ # 30 个 workspace skills
│ ├── blog-writer/SKILL.md
│ ├── paper-writer/SKILL.md
│ ├── memory-keeper/SKILL.md
│ └── ... (27 more)
~/.claude/
└── skills/ # 20 个 user-level skills
├── academic-paper-writer/SKILL.md
├── frontend-design/SKILL.md
└── ... (18 more)
~/Library/Application Support/Code/
└── User/workspaceStorage/<hash>/
└── state.vscdb # 对话历史 (SQLite)
最核心的一个文件就是那个 17MB 的 extension.js——System Prompt、Tool Definitions、Skill 加载器、Context 组装器全在里面。其余都是配置文件和内容文件,被它在运行时读取并拼装。
成本结构:固定 vs 累积
这张图是我最想表达的核心观点:
┌─────────────────────────────────────────────────┐
│ 每次 API 调用的 token 构成 │
├─────────────────────────────────────────────────┤
│ │
│ 🔒 固定成本(每次都付) ≈ 20% │
│ System Instructions 9.0% │
│ Tool Definitions 10.9% │
│ │
│ 📈 累积成本(越聊越多) ≈ 27% │
│ Messages 13.8% │
│ Files 5.7% │
│ Tool Results 7.6% │
│ │
│ 📦 杂项 ≈ 1% │
│ Other 0.5% │
│ │
│ 💨 剩余空间 ≈ 52% │
│ 可用于继续对话 │
│ │
└─────────────────────────────────────────────────┘
优化指南
知道了每一寸 token 的出处,优化就有方向了:
| 优化策略 | 针对部分 | 效果 |
|---|---|---|
| 清理不常用的 Skills | System Instructions | 50 个减到 20 个 → 省 ~2,400 tokens |
| 减少 MCP 工具数量 | Tool Definitions | 每少一个 MCP 工具 → 省 ~300 tokens |
| 及时开新会话 | Messages | 归零,回收 ~15-20% |
| 精确选中代码段,别全文拖入 | Files | 300 行→50 行 → 省 ~1,600 tokens |
| 少让 AI 读大文件 | Tool Results | 每次 read_file 控制行数 |
| 精简 CLAUDE.md | System Instructions | 293 行→150 行 → 省 ~1,500 tokens |
跟 Skill Pipeline 的关系
如果你读过我的 Skill Pipeline 深度拆解,现在可以把两篇文章串起来:
- Skill 描述列表常驻 System Instructions(~4,000 tokens)——这就是 Skill Pipeline 的"唯一固定代价"
- 触发 Skill 后,SKILL.md 全文作为 Tool Result 注入——从 Tool Results 的 7.6% 那块扣
- 工具调用(read_file 等)的结果也进 Tool Results——Skill 触发后续的工具调用链,每一步都在累加
整个 Skill Pipeline 的 token 足迹:
描述列表 (常驻) → ~80 tokens/skill → System Instructions
SKILL.md (按需) → ~500-2000 tokens → Tool Results
后续工具调用 → 每次 ~500-2000 → Tool Results (累积)
结语
Context Window 就是 AI Agent 的"工作内存"。跟你用 htop 看进程内存一样,这个面板告诉你每一寸 token 被谁占了、从哪来的。
下次你觉得 AI "不够聪明"或"忘了之前说的"时,先看看 Context Window 使用率——很可能不是模型的问题,而是它的"内存"快满了。
这篇拆的是 VS Code Copilot 的 Context Window。Claude Code 呢?它的上下文组装策略完全不同——没有 Deferred Tools,有 System Prompt Caching,还有一套独特的 conversation compaction 机制。那是另一个故事了。
本文与 拆解 Skill Pipeline 为同日姊妹篇,建议对照阅读。

