Microsoft 优化 VS Code 中 Copilot 的 token 使用效率,降低运营成本和响应延迟。直接改善开发体验和代码生成速度。
2026 年 6 月 17 日,Ryan Caldwell、Bhavya U
随着 GitHub Copilot 最近转向按使用量计费,Agent 会话中的每一个 token 都至关重要。它们会影响你的额度、延迟,以及 Agent 为完成任务所剩余的上下文窗口。正如我们从自己的数据中观察到的那样,每一代新模型在单个任务上消耗的 token 往往都比上一代更多。这意味着,为了抵消这一趋势,harness 层面的效率变得越来越重要。随着 Agent 开始承担持续时间更长、自主性更强的工作,低效 harness 带来的成本会迅速累积。
持续提升 VS Code 中 GitHub Copilot Agent harness 的 token 效率,是抵消这一趋势的最佳方式。对于大多数改动,我们都会在生产环境中运行 A/B 实验,并针对任务套件进行离线评估,以确认任务成功率能够维持或提升,同时降低 token 用量。这种优化很少来自某一次巨大的突破,通常是一连串稳定的小幅改进。下面,我们将依次介绍近期针对 OpenAI 模型和 Anthropic 模型取得的成果。
每个 Agent 请求的核心都包含两类成本,而我们可以通过两个思路来降低它们。虽然 OpenAI 和 Anthropic 两家提供商以不同方式提供这些能力,但这些思路都适用于双方的模型。
突出展示 prompt 各个组成部分的 prompt signature 图形概览。
Prompt 前缀与缓存。 在 Agent 编程会话中,每次请求都有很大一部分内容会在多个轮次之间重复,包括系统指令、工具定义、代码仓库上下文和对话历史。这段重复出现的开头就是 prompt 前缀。当多个请求拥有完全相同的前缀时,推理服务提供商可以复用已经缓存的模型状态,而不必在每次请求时从头计算。尽管它被称为“缓存”,但被缓存的产物并不是一份人类可读的 prompt 副本,而是模型处理该前缀时计算出的状态,在内部以 key/value tensor 的形式表示。复用前缀既能降低成本(缓存 token 的价格最多可以低至原来的十分之一),也能减少延迟,因此我们一直致力于维持较高的 prompt 缓存命中率。
工具定义开销。 Agent 可以引入大量工具,包括 MCP server 暴露的工具、内置工具,以及扩展提供的工具。每个工具都会连同完整定义一起发送给模型,其中包括名称、描述和完整的 JSON 参数 schema。过去,每次请求都会把所有这些工具加载到上下文中。即使这些数据已经缓存,每一轮仍然要承担固定的上下文窗口开销,而且工具集越大,开销也越高。
工具搜索。 工具搜索允许模型按需加载工具定义,而不是一次性全部加载,从而减少这部分开销。在请求开始时,模型只能看到轻量级元数据,也就是各个延迟加载工具的名称和描述;体积更大的参数 schema 则不会进入上下文,直到模型搜索某个工具并将其加载。由于延迟加载的工具会被添加到上下文窗口末尾,而不是 prompt 前缀中,因此已缓存的 prompt 前缀仍然可以复用,缓存带来的收益也能在多个轮次之间持续生效。最终得到的是一个更精简的上下文窗口:模型不再把 token 浪费在从未使用的工具上,从而为实际任务留出更多空间和预算。
对于 OpenAI 模型,我们近期的工作重点是通过提升 token 效率,降低 Copilot 用户的使用成本和延迟。我们从三个方面推进这项工作:延长已缓存模型状态的保留时间、减少工具定义开销,以及使用持久化 WebSocket 连接替代重复的 HTTP 请求。
OpenAI 模型会自动缓存 prompt 前缀:服务提供商会推断哪些前缀可以复用,并在多个请求之间复用相应的模型状态。这种复用会直接带来成本收益。对于大多数支持缓存输入定价的 OpenAI 模型,未缓存输入 token 的价格是缓存输入 token 的 10 倍。
前缀缓存本身会自动完成,但缓存能够存活多久则可以由我们配置。经过仔细评估,我们通过 prompt_cache_retention 请求体参数,为受支持的模型启用了延长 prompt 缓存功能。默认情况下,缓存位于高速 GPU 显存中。如果大约 5 到 10 分钟没有活动(某些情况下最长可达一小时),缓存就会被清除,以便为其他工作腾出空间。设置 "prompt_cache_retention": "24h" 后,缓存会被转移到速度较慢但空间更充裕的 GPU 本地存储中,并保留最长 24 小时。
它的好处很直接。使用默认缓存时,只要暂停几分钟以上,缓存就可能被丢弃,因此下一次请求必须以完整的未缓存价格重新处理整个前缀。延长保留时间可以让缓存持续保持可用,所以即使中断很长时间,再回来继续工作时依然又快又便宜。
在 VS Code 中为受支持的 OpenAI 模型启用延长 prompt 缓存后,我们测得缓存命中率出现了如下相对增幅。这里指的是相对变化,而不是百分点增幅:增长 919% 意味着缓存命中率变成了此前的 10.19 倍。
当两次请求的间隔较长时,增幅最为明显,因为那些原本已经过期的缓存模型状态仍然可供复用。在实际使用中,这意味着 prompt 中会有更大比例的内容按照较低的缓存输入费率处理,即使中间暂停了较长时间,也能降低请求成本。
为了避免在每次请求中发送所有工具定义,工具搜索将这项工作变成了按需执行。OpenAI 的原生工具搜索适用于 GPT-5.4 及更新模型,它通过 defer_loading flag 实现这种延迟加载机制。
在请求开始时,模型只能看到轻量级元数据:每个延迟加载 function 的名称和描述;如果延迟加载的 function 被归入 namespace,模型则只能看到该 namespace 的名称和描述。
在一项为期四天、使用 GPT-5.4 和 GPT-5.5 的 VS Code 实验中,工具搜索降低了每轮 token 使用量、首 token 延迟和完成耗时:
汇总整个会话的数据后,Copilot 用户中位数的总 token 用量在 GPT-5.4 上下降了 8.97%,在 GPT-5.5 上下降了 10.92%。
Agent 编程中的一轮交互可能涉及对推理服务提供商发起许多连续请求;模型每调用一次工具并朝解决方案推进一步,就会产生一次请求。即使底层 HTTP 连接能够复用,每一步仍然是一个独立的 API 请求。
Responses API 的 WebSocket 模式会保持持久连接,并为这些连续请求提供延迟更低的续接路径。在连接处于活跃状态时,OpenAI 还可以从连接本地的内存缓存中复用最近一次响应的状态,从而减少长链工具调用中的续接开销。
几个月前,OpenAI 宣布 Responses API 支持 WebSocket。最初的文档展示了显著的延迟改善,因此我们很早就开始进行实验,并在自己的 A/B 测试中观察到了稳定的延迟下降。这是一个事后看来理所当然的思路:Agent 编程会话会在一次长时间持续的交互中反复发送请求,而这正是 WebSocket 擅长处理的场景。
在最初向 VS Code Stable 推出 WebSocket 的过程中,A/B 实验中的延迟收益也在生产环境中得到了保持。下表展示了该轮发布期间 WebSocket 相对于 HTTP 带来的延迟改善。此后,技术栈中其他部分的优化,包括更完善的 prompt 缓存,又进一步降低了延迟和使用成本。对于每项指标,数值越低越好:
我们还观察到了具有统计显著性的用户参与度相对增长。对于 GPT-5.3-Codex 和 GPT-5.4,活跃用户数分别增长了 1.27% 和 2.17%,两日参与度则分别增长了 1.90% 和 3.14%。
这些收益促使我们在包括 VS Code、Copilot CLI、GitHub app 等 Copilot 产品中,将 WebSocket 设为 OpenAI GPT-5.2 及更新模型的默认传输方式。
对于 Anthropic 模型,我们近期的工作针对的是同样两类重复成本:需要在缓存中保持可用的 prompt 前缀,以及每一轮都要发送的工具 payload。我们通过两项改动来解决这些问题:更审慎地分配 prompt 缓存断点,以及通过工具搜索延迟加载工具定义。
Anthropic 的 prompt 缓存机制与 OpenAI 模型所使用的自动前缀缓存有所不同。服务提供商不会自行推断哪些前缀可以复用,而是由调用方显式放置 cache_control 断点,API 会缓存每个标记之前的所有内容。
每次请求可使用的断点数量很少且固定,因此断点放在哪里,与是否使用断点同样重要。我们重新设计了 Messages API 的缓存方式,有意识地分配最多四个断点,并将它们固定在 prompt 中最稳定的边界上:
工具定义末尾和 system prompt 末尾,也就是多个轮次之间变化最少的部分。
位于最近两条可缓存消息上的一对滚动锚点。
其中第二个较旧的锚点是一道安全网。如果最新的锚点未命中——例如某次缓慢的工具调用导致其缓存过期,或内容出现轻微变化——较旧的锚点仍然可以命中,并覆盖它之前的所有内容。通常情况下,我们只需要放弃一次交互的缓存,而不必对整个对话缓存进行冷启动。
这些改动让缓存命中率稳定提升了几个百分点。对于 prompt 很长、各轮请求间隔又很短的 Agent 工作负载,缓存命中率现在大约为 94%。这意味着每次请求只有很小一部分输入需要重新计算,其余内容都可以直接从缓存中提供,从而同时降低使用成本和首 token 延迟。
Anthropic 的工具搜索工具采用了同样的延迟加载思路。工具会被标记为 defer_loading: true。与此同时,除了延迟加载的工具目录,我们还会预先加载一小组精心挑选的核心工具,包括读取和编辑文件、运行终端命令以及搜索 workspace,因此最常见的操作不需要额外步骤。
我们最初使用 Anthropic 的服务端工具搜索来推出这项功能:模型在 Anthropic 一侧搜索延迟加载的工具目录,API 再将匹配结果以内联 tool_reference block 的形式展开。在一项为期七天的 VS Code 实验中,延迟加载工具定义不仅减少了 prompt token 和总 token 用量,也缩短了首个数据块的返回时间:
对于 Copilot 用户中位数,在整个会话范围内,prompt token 和总 token 用量均下降了约 18%。
在验证这套方案有效后,我们将搜索本身迁移到了客户端,并使用为 VS Code 精简工具集构建的同一套工具分组系统作为支撑。模型仍然会调用 tool_search 工具,但不再由 Anthropic 在延迟加载的工具目录中进行匹配,而是由我们在本地执行搜索,并返回最匹配工具的 tool_reference block。
本地搜索也更加智能。我们不再基于工具名称和描述进行词法匹配,而是使用内部的 Copilot embedding 模型,将查询与每个可用工具的向量表示进行比较。这也是为 embedding 引导的工具路由提供支持的同一个模型。由于它匹配的是意图,而不是字面上的关键词,因此即使某个请求(例如“查找这个符号的所有引用”)与目标工具的名称和描述没有任何相同词汇,也能找到正确的工具。
如需深入了解这套工具分组和 embedding 引导的路由机制,请参阅《我们如何用更少的工具让 GitHub Copilot 变得更智能》。
将搜索迁移到客户端后,除了原本的 token 节省,我们还获得了一些额外收益:
响应速度: 搜索会在本地针对已缓存的 embedding 运行,因此发现工具不再依赖服务端搜索的往返请求。
响应速度: 搜索会在本地针对已缓存的 embedding 运行,因此发现工具不再依赖服务端搜索的往返请求。
动态发现 MCP 工具: 由于候选工具集合由我们掌控,因此连接的 MCP server 在会话过程中新增或移除的工具会立刻反映出来,无需等待固定的服务端工具目录更新。
动态发现 MCP 工具: 由于候选工具集合由我们掌控,因此连接的 MCP server 在会话过程中新增或移除的工具会立刻反映出来,无需等待固定的服务端工具目录更新。
更高质量: embedding 引导的搜索更有可能针对给定查询找到正确的工具,从而减少用户错误并提高任务成功率,具体可见下方指标。
更高质量: embedding 引导的搜索更有可能针对给定查询找到正确的工具,从而减少用户错误并提高任务成功率,具体可见下方指标。
这种响应速度直接体现在了数据中。在为期两周的 VS Code Stable 发布过程中,客户端工具搜索在此前通过延迟加载实现 token 节省的基础上,进一步降低了延迟。
在两种实现中,延迟加载的工具都位于已缓存的 prompt 前缀之外,因此前缀永远不需要重写,上述缓存收益也能在多个轮次之间持续生效。而且,一旦发现某个工具,它就会在对话的剩余过程中始终可用,模型无须再次付出搜索它的成本。
上述工作让我们的 Agent harness 变得更加精简:缓存命中率更高、每次请求包含的工具定义更少、传输开销也更低。下一步,是将若干完整类别的工作从主 Agent 中彻底剥离。我们正在构建专用 subagent,也在探索针对特定用途进行定制训练的 subagent,用于处理搜索 workspace、运行命令和总结结果等范围明确的任务。每个 subagent 都会使用能够完成相应工作的最小、最便宜模型,而不再由主模型在自己的上下文中承担这些工作。最终结果是降低每项任务的总体成本。
此外,我们还在努力提升产品内 token 用量和缓存状态的透明度。其中包括对那些会悄然推高成本的操作发出提示,例如在长时间暂停、缓存已经过期后恢复会话,或者在会话进行过程中更改 reasoning effort。这样,你就能在为缓存冷启动付费之前作出知情选择。
提升 Agent harness 的 token 效率是一项持续进行的工作,我们会继续投入,一次积累一个小小的成果。