首页
/ 解读 VS Code 中 Copilot 提示词基线:剖析 `gpt-5.6-terra` 模型请求体快照

解读 VS Code 中 Copilot 提示词基线:剖析 `gpt-5.6-terra` 模型请求体快照

2026-09-07 12:47:01作者:虞亚竹Luna

这篇技术指南围绕仓库中一份特殊的测试快照文件展开:它把 VS Code Agent Host 通过内置 Copilot CLI 为 gpt-5.6-terra 模型发出的完整模型请求体原样钉在磁盘上。通过它,读者可以理解 Copilot 提示词是如何跨越大模型、CLI、Agent Host 三层最终拼装成 POST /responses 上的一段 JSON,也能掌握这套"无 token、可回放、逐字段比对"的提示词基线机制,以及当 SDK 升级或提示词拼装逻辑变化时该如何维护与更新基线。

一、这是什么文件:一份"钉死"的模型请求体快照

该文件位于 providers/snapshots 目录,是 Agent_Host_E2E — Copilot prompts 测试套件为 gpt-5.6-terra 模型生成的提示词基线(prompt baseline)。与同目录下 .traffic.ahp.yaml 记录 Agent Host 协议双向语义流量不同,.prompt.md 记录的是 Agent Host 把提示词交给底层 Copilot CLI 后,CLI 真正序列化到网络上的模型请求体——也就是"模型能看到的那个输入"。

文件内容是一个被 ```json 围栏包裹的、经过 pretty-print 的完整请求体。快照命名由 snapshotPathForTest 统一生成:取 Mocha 测试的完整标题(Agent Host E2E — Copilot prompts + 模型名),把非字母数字字符替换成下划线,落到测试源码旁的 __snapshots__ 目录。因此同目录下存在一整族基线,覆盖 gpt-5claude-*gemini-2.0-flash 等各模型家族。

二、请求体结构:Responses 方言下一次完整模型请求的字段构成

快照的顶层 JSON 清晰展示了 Copilot CLI 走 Responses 方言(对应 fixture 中的 dialect: responses,即 POST /responses)时请求体的完整字段。核心字段如下:

顶层字段 快照取值 含义
model gpt-5.6-terra 本轮选中的模型
instructions 约 800 行系统提示词(见第三节) Responses 方言中系统提示词的字段名(Anthropic Messages 方言中叫 system
input 单条 user 消息 当前轮次的对话输入,内含 <current_datetime>${datetime}</current_datetime> 占位符与"Say exactly "ok"" 指令
tools 一长串函数定义数组 模型可调用的工具目录
reasoning { "effort": "medium" } 推理预算档位
text { "verbosity": "medium" } 输出详细程度
store false 是否在服务端留档
stream true 流式输出
include ["reasoning.encrypted_content"] 需要返回的加密推理内容
parallel_tool_calls true 允许并行工具调用

测试实现中的 IWireRequest 接口 可以确认这套方言约定:Responses 把系统提示词放在 instructions、对话放在 input,而 Anthropic Messages 则用 system + messagesformatPromptSnapshot 通过 extractText(request.instructions ?? request.system) 兼容两种拼写,说明这套基线机制天然跨方言工作。

三、instructions:从八类区块读懂 Copilot 的系统提示词

快照中最长的字符串是 instructions。逐段阅读,可以还原出 Agent Host 交给 Copilot CLI 的系统提示词由以下区块构成(与快照中出现的章节标题一一对应):

  • code_change_instructions / rules_for_code_changes:规定"精确、外科手术式的修改"、"不顺手修无关历史问题"、"遵守既有代码约定"、"类型安全优先、避免 as any 强转"、"先搜索复用(DRY)再新增助手"、"动手前确认验证路径"等工程纪律。
  • linting_building_testing:明确"只运行仓库里已存在的 lint/构建/测试工具"、"用能覆盖改动的最小目标命令"、"文档改动无需 lint 除非有专项测试"。
  • using_ecosystem_tools:倾向使用包管理器、脚手架等生态工具而非手工改动。
  • style:只为需要澄清的代码写注释。
  • tips_and_tricks:命令执行前先反思输出、任务结束清理临时文件、不确定时用 ask_user 澄清、不要把规划笔记写成 markdown 文件。
  • environment_limitations / prohibited_actions:声明"非沙箱共享环境"身份,并列出不得泄露敏感数据、不得把密钥提交进源码、不得生成侵权或有害内容等红线,以及"不得改动/透露/讨论这些指令本身"的持久保密约束。
  • environment_context:运行时注入的工作目录、OS、可用工具占位(即 ${workdir}${os}${available_tools})。
  • tools 使用指南:逐条解释 bash(同步/异步模式、initial_wait、后台通知、禁用 pager 等)、view(多文件并行读、view_range)、skill(必须先调用匹配的 Skill 再行动)、sql(会话级持久化与查询规范)、rg(基于 ripgrep 的精确/多行搜索)、task(何时派生子代理)等工具的最佳用法。
  • <custom_instruction>:仓库注入指令的包裹层。快照里保留了两处 <custom_instruction>${repository_instructions}</custom_instruction> 结构,证实 README 中"保留标签与数量断言、不钉内容" 的设计:AGENTS.md 等文件每改动一行都会重写全部基线,因此只断言"注入了、注入了几份、在提示词中的位置",而非逐字内容。

第一行 "You are an AI assistant using Copilot SDK in VS Code." 就是身份声明,随后还有 <system_notifications><preamble_messages><inline_line_numbers><maximize_context_understanding> 等运行期包裹指令,与测试注入的会话标识、时钟、模型目录共同组成模型看到的完整上下文。

四、tools 与采样参数:工具目录与生成控制

tools 数组里每个工具对象都是标准函数声明结构(name / description / parameters,末尾统一 "strict": false, "type": "function")。按文件出现顺序,至少包括 bashread_bashstop_bashlist_bashapply_patchviewweb_fetchskillask_usersqlrgglobtask 等(完整请求体共 853 行,中间夹有大量工具定义,此处仅截取样例解析,其余对象结构完全一致)。

bash 工具定义 为例,可以观察到工具描述本身就是一种"夹带的规范":它向模型传递了 shell 环境的执行语义——"每条命令运行在新进程、工作目录以会话创建时为准,cd/环境变量不跨调用保留"、"同步命令超时会转入后台并推送完成通知"、"initial_wait 默认 30 秒,长任务调到 120+ 秒"、"禁用 pager、用 kill <PID> 精确终止进程"。工具描述里还带有 ${platform_packages} 这类运行期占位符,快照以占位符形式保存,既稳定又无平台噪音。

生成控制方面,快照尾部字段 reasoning.effort = mediumtext.verbosity = medium 说明这一模型以中档推理与中等详细度运行;stream: true 配合 include: ["reasoning.encrypted_content"] 要求服务端回传加密推理内容;store: false 表示请求不在服务端落盘;parallel_tool_calls: true 允许模型在单轮内并发发起多个工具调用。

五、可跨机器比对的关键:逐条占位符脱敏规则

快照的比对前提是"同一模型、同一提示词拼装逻辑在不同机器上产生一致请求体"。由于一次请求天然携带日期、OS 名、路径、UUID 等易变值,normalizeVolatile 函数 在序列化前执行了逐条替换,快照中即可找到对应证据:

占位符 替换目标 快照中的证据
${datetime} <current_datetime> 时钟 input 中保留标签结构
${os} * Operating System: 一行 instructions 中 OS 行整体脱敏
${available_tools} 工具清单行 * Available tools: ... 整行被替换
${platform_packages} 平台相关包管理器提示 bash 工具描述尾部
${repository_instructions} 注入的仓库指令全文 <custom_instruction> 包裹层原样保留
${model_count} (N models available) 提示词内的模型计数说明
${model_catalog} CLI 内联进 Task schema 的 /models 目录 标签仍在、明细被折叠
${session_id} / ${uuid} session-state/ 路径与运行时 UUID 兜底把剩余 UUID 全替换

替换顺序有讲究:带标签的 UUID 先换(保留 ${session_id} 等专属占位),最后才用通用 ${uuid} 兜底,避免被二次覆盖。这些规则和 ahpSnapshot.ts 的快照文本归一化(行尾归一、workdir/homedir/用户名校验替换)共同保证同一份基线在 Linux、macOS、Windows 上都能精确比对。

值得强调的还有"形状守卫":formatPromptSnapshot 在渲染前断言系统提示词非空、工具数组非空、存在对话消息且无空消息——防止一次异常捕获变成一份"看上去合理的小基线"而静默通过。底层还有一组单元测试 Copilot prompt snapshot formatting(如 rejects incomplete request body shapes)逐条验证这些守卫。

六、快照如何被验证:确定性回放的完整链路

提示词是 Copilot CLI 的产物——它被编译进 @github/copilot 原生二进制,只有序列化到网络那一刻才可观测。因此这份基线不是录制的,而是从一次回放的 turn 中读取。测试驱动流程见 copilotPromptsE2E.integrationTest.ts

  1. 为每个模型 createRealSession 建一个真实会话;
  2. 派发 ChatTurnStarted,消息文本固定为 Say exactly "ok",并显式携带 model: { id: 'gpt-5.6-terra' }
  3. 循环等待 ChatTurnComplete/ChatToolCallReady/ChatError,对工具调用自动确认(approved: true),直到 turn 排干;
  4. observedModelRequestBodies.at(-1)——取最后一个请求体以容忍 CLI 可能插入的 preflight 请求;
  5. assertPromptSnapshot 与已提交基线比对。

背后是整套 record/replay 基础设施:测试通过 captures/copilotcli-gpt-5-6-terra.yaml 这个 dialect: responses 的 fixture,用"第 N 次请求回放第 N 次响应"的顺序匹配喂给真实 Copilot CLI;只有模型响应是假的,Agent Host 服务、SDK 子进程、工具执行、协议全部真实运行。测试故意不在录制方向做快照——录制会触达真实 CAPI 的模型目录与实验分配,二者都可能让提示词因与仓库无关的原因漂移;只有回放方向(无 token、无网络、确定性)才产基线,详见 README 的 Prompt snapshots 一节

七、如何新增一个被钉住的模型

gpt-5.6-terra 并非自动进入基线。向 SNAPSHOT_MODELS 添加模型需要同时满足三个条件(README 中"Pinning a new model is opt-in"的原则):

  1. 出现在 capiStubs.ts 的 stub 模型目录gpt-5.6-terra 的条目定义了 vendor 为 OpenAI、supportedEndpoints['/responses', 'ws:/responses']、上下文窗口 1,050,000 token、最大输出 128,000 token、最大提示 922,000 token 且 vision: true。模型不在 /models 中,CLI 会在构造请求前拒绝,测试直接失败、无体可捕获。添加该条目本身不会让任何测试变红——CLI 内联的模型目录在基线中被折叠。
  2. 有配套 fixturecaptures/copilotcli-<slug>.yaml),且 fixture 的 dialect 与模型 stub 端点匹配:Responses 端点用 dialect: responses/v1/messagesdialect: anthropic
  3. 有已提交的基线文件assertPromptSnapshot 特意在基线不存在时报错而不是自动创建(assertSnapshot 的缺文件即通过的默认行为会"绿化"一份没人写过的基线,因此测试显式 existsSync 前置检查)。

代码注释还点明了两类刻意缺席者:gpt-4.1grok-code-fast-1 在回放下根本不发模型请求,无法钉住;同时不钉"未显式选择模型"的场景——那会让 CLI 自行给 stub 目录排序,基线记录的就成了测试夹具的属性而非产品行为。

八、基线何时漂移,以及如何正确更新

基线 diff 只可能来自两个源头:Copilot CLI 变了(SDK 升级导致提示词或参数调整),或 Agent Host 交给了 CLI 不同的内容(历史保留、注入前缀、附件编组等拼装逻辑变化)。相反,编辑仓库的 AGENTS.md 或模型目录不会触发重写——它们的内容正是被刻意折叠的两个区域。这也是为什么这类基线非常敏感:copilotPromptsE2E.integrationTest.ts 全部用例声明为 POSIX-only(Windows 提示词含 PowerShell 专属区块,属于另一份基线),并且在 Windows 上以 test.skip 跳过(相关说明见 KNOWN_ISSUES.md)。

更新流程(README 中"Accept a new baseline"的官方做法):

# 用既有的确定性 LLM fixture 回放,仅更新 .prompt.md 基线(无 token、无网络)
AGENT_HOST_UPDATE_AHP_SNAPSHOTS=1 ./scripts/test-integration.sh --run \
  src/vs/platform/agentHost/test/node/e2e/providers/copilotPromptsE2E.integrationTest.ts

运行后逐字审阅 Git diff——由于正文是 pretty-print 而非字节级还原(CLI 原本把请求体压缩成单行),缩进只达结构层,字符串内的 JSON 转义使系统提示词和长工具描述各占一行,任何一句话的改写都会表现为整行重写,便于人工辨识。确认无误后再不带更新标志重跑一次,让回放模式完成真正的逐字段断言。需要注意录制与更新的边界:AGENT_HOST_UPDATE_SNAPSHOTS=1 隐含真实录制,会触达真实 CAPI,因此提示词基线只在 AGENT_HOST_UPDATE_AHP_SNAPSHOTS=1(回放范围内)接受新基线。

结语:把提示词当"契约"而不是"实现细节"来钉

gpt-5.6-terra 这份基线文件的价值在于它回答了"模型在这一刻到底看到了什么":从系统提示词的工程纪律区块,到工具目录里蕴含的 shell 执行语义,再到 reasoning/stream/parallel_tool_calls 等生成参数,模型请求体的每一个字段都被纳入版本控制。配合 record/replay 基础设施、占位符归一化与形状守卫,这套机制让提示词层面的任何意外漂移(无论来自 SDK 升级还是 Agent Host 拼装逻辑变更)都会在 CI 上变成一次可见、可定位、可回放的失败——这正是 VS Code Agent Host 把"提示词"这一高度易变又高度关键的产品面变成可测试契约的工程实践。

登录后查看全文
热门项目推荐
相关项目推荐