VS Code Agent Host 提示词基线快照解析:Agent_Host_E2E___Copilot_prompts_gpt-5_1-codex.prompt.md 的生成原理与维护实践
本篇技术指南以 Agent_Host_E2E___Copilot_prompts_gpt-5_1-codex.prompt.md 为样本,深入讲解 Visual Studio Code(VS Code)Agent Host(代理主机)端到端测试体系中"提示词快照(prompt snapshot)"机制的设计与运作。读完你会掌握:这类 .prompt.md 基线文件是怎样在无令牌、确定性的回放测试中被捕获出来的,其中 JSON 请求体的每个字段与系统提示词的分层结构代表什么,以及当 CLI 升级或主机侧提示词组装逻辑变化时如何正确更新基线。
一、快照文件在测试体系中的位置
该文件位于 providers/__snapshots__/ 目录,文件名 Agent_Host_E2E___Copilot_prompts_gpt-5_1-codex.prompt.md 由测试全名(suite 标题 "Agent Host E2E — Copilot prompts" 加用例名 "gpt-5.1-codex")经脱敏规则拼接而成。其生成逻辑在 ahpSnapshot.ts 的 snapshotPathForTest 中:快照永远与被测测试的源码同目录下的 __snapshots__/ 子目录相邻,文件名由 sanitizeName(test.fullTitle()) 将除字母数字与 _、- 外的字符替换为下划线得到。
它不是普通的 .md 文档,而是被代码围栏包裹的、结构化的模型请求基线——测试将它当作字符串与线上捕获值做逐字比对。按 e2e README 的定义,providers/__snapshots__/ 同时存放两类快照:*.traffic.ahp.yaml(AHP 语义流量快照)与 *.prompt.md(组装完成的提示词快照)。驱动本文件的测试入口是 copilotPromptsE2E.integrationTest.ts,它"固定(pin)了内置 Copilot CLI 为每个模型发出的模型请求体的每一个字段"。
二、为什么需要"提示词基线"而不是普通断言
这条测试的诞生有一个关键背景,写在测试文件头部注释与 modelRequestProjection.ts 中:
- Copilot 的系统提示词被编译进
@github/copilot原生二进制,主机侧代码看不到它,只有 CLI 在把请求序列化到线上(serializes it onto the wire)时才可观测; - 回放代理(CapiReplayProxy)按"序号匹配"选择响应——第 N 次对某端点的请求回放第 N 条录制响应,从不比较请求内容;
- 于是"请求体"(提示词组装、历史保留、截断、附件封送、工具结果回传——这些都是主机自身的产物)成了无人断言的盲区:一旦回归,回放依然全绿,并在下次重录时被悄悄"提升"为新期望值。
提示词快照测试恰好堵住这个洞:它把模型请求体整体漂亮打印下来作为基线。copilotPromptsE2E.integrationTest.ts 的注释还说明了为什么录制方向不能产生基线:录制时会真实访问 CAPI 获取模型目录(model catalog)与实验分派(experiment assignment),两者都可能移动提示词,而这些变更原因不属于本仓库可控范围。因此快照一律从回放的一轮 turn 中读取——确定、无令牌。
三、快照的 JSON 骨架:逐字段解剖
打开本文件,可见整段 json 代码围栏。以下是其顶层结构(来自文件本身,缩进格式由 JSON.stringify(body, null, 2) 生成,非 CLI 线上压缩形态):
{
"model": "gpt-5.1-codex",
"instructions": "You are an AI assistant using Copilot SDK in VS Code. ...",
"input": [
{
"role": "user",
"content": [
{
"type": "input_text",
"text": "<current_datetime>${datetime}</current_datetime>\n\nSay exactly \"ok\""
}
],
"type": "message"
}
],
"tools": [ ... ],
"reasoning": { "effort": "medium" },
"store": false,
"stream": true,
"include": [ "reasoning.encrypted_content" ],
"parallel_tool_calls": true
}
各字段含义如下。
1. model
"gpt-5.1-codex"。这是测试通过 AHP chat/turnStarted 动作显式指定的模型(见 driveTurnWithModel 中对 message.model.id 的赋值)。README 强调:每个模型都被显式选中,故意不固定"未选择"的情况——因为那种情况下 CLI 会按自身排序从桩目录选模型,基线记录的将是测试固件的属性而非产品行为,且一旦 capiStubs.ts 中加入或移除排名更高的模型就会漂移。
2. instructions(OpenAI Responses 方言的系统提示词)
在 Responses API 方言中系统提示词字段拼作 instructions;而 Anthropic Messages 方言则拼作 system——这正是 copilotPromptsE2E.integrationTest.ts 里 IWireRequest 接口与 extractText(request.instructions ?? request.system) 兼容两种方言的原因。本快照的系统提示词以一句话身份声明开头:
You are an AI assistant using Copilot SDK in VS Code. You help users with software engineering tasks. When asked about your identity, you must state that you are an AI assistant using Copilot SDK in VS Code.
其后是层级化的行为规则区块(用尖括号标签包裹的"指令注入"区),在下文第五节逐层拆解。
3. input 与固定住的用户回合
input 是被回放的 turn 消息数组。测试驱动一轮对话的文案固定在代码中为 'Say exactly "ok"'(README 建议录制期保持提示词"只读 / 琐碎",例如 echo、pwd、列目录)。快照里可见该文本上方被注入了运行时时钟占位:
<current_datetime>${datetime}</current_datetime>
Say exactly "ok"
<current_datetime> 是 CLI 注入的时钟上下文,${datetime} 则是快照写入前的规范化占位符(见第五节)。
4. tools
模型可见的工具目录。本快照至少包含 bash(执行 shell 命令的工具,描述说明命令运行于全新进程、可使用 async/sync 模式、有 shellId 追踪等约束)与 view(查看文件与目录的工具,对超过 20KB 的文件需用 view_range 分段读取等约束)等条目,每个工具携带 name、description、parameters。README 说明这些工具定义会随 CLI 版本、随主机可提供的工具集而变,因此被完整固定。
5. reasoning / store / stream / include / parallel_tool_calls
请求级采样与传输参数同样被固定:reasoning.effort 为 medium、store: false、stream: true、include: ["reasoning.encrypted_content"]、parallel_tool_calls: true。README 中"Prompt snapshots"一节专门强调:这类采样参数(thinking / text.verbosity / max_tokens / parallel_tool_calls)过去在渲染子集里未被固定,如今整段请求体固定后,"CLI 开始发送的某个参数会在下一次基线 diff 中自行显现"。
四、格式化成快照时保留了什么、抹掉了什么
快照并非逐字节复刻线上请求(CLI 会把它压成一行),而是字段无损的漂亮打印:JSON 会把字符串值内的换行转义为 \n,因此系统提示词与较长的工具描述各自保持单行。改写其中一个句子里的某个词,会显示为整行重写而非行级 diff。
formatPromptSnapshot 输出前会先做形状守卫(shape guard),任何"看似正常"的空捕获都无法通过:
- 系统提示词为空 →
carried no system prompt; - 无工具定义或 tools 非数组 →
carried no tool definitions; - 无回合消息 →
carried no turn messages; - 任一回合消息文本为空 →
turn message was empty。
抹掉(规范化)的是"两次正确运行之间必有差异"或"属于别处变更预算"的值,且每个都保留外围标签或包装,使形状变化仍然失败。与 modelRequestProjection.ts 的投影相比,提示词快照的规范化(normalizeVolatile,位于测试文件末尾)更细,包括:
| 规范化目标 | 占位符 |
|---|---|
| 会话 UUID、任意运行时 UUID | ${session_id}、${uuid} |
时钟 <current_datetime>… |
${datetime} |
操作系统探测行 * Operating System: … |
${os} |
* Available tools: … |
${available_tools} |
| Bash 工具里的平台包管理器提示行 | ${platform_packages} |
注入的仓库指令 <custom_instruction>… |
${repository_instructions} |
| 可用模型数量/目录 | ${model_count}、${model_catalog} |
换行符 \r\n |
\n |
其中仓库指令与模型目录两项与运行差异无关,仍被抹掉是刻意的预算决策:CLI 会把 .github/copilot-instructions.md 与 AGENTS.md 逐字注入,若逐字固定,给 AGENTS.md 追加一行就会重写这里全部基线、让无关的文档改动弄红 CI;模型目录同理——CLI 会把整个 /models 列表内联进 Task 工具的 schema,逐字保留会让 capiStubs.ts 新增一个条目就重写所有基线。但 <custom_instruction> 包装仍断言了"指令被注入、注入几条、位于提示词何处"。
五、系统提示词的内容分层
本节完整梳理 instructions 字符串内部的结构。它由若干用尖括号标签包裹的区块拼接而成,与扩展侧的 agentPrompt.spec.tsx 覆盖的模型家族提示词同源(由 @github/copilot CLI 在启动时组装),可划分为以下层次。
5.1 代码变更总则(code_change_instructions)
嵌套的 <rules_for_code_changes> 规定了 Agent 动手改代码时的行为底线,可归纳为若干子主题:
- 精确外科手术式改动:充分满足用户请求即可,不改无关代码,但改动须完整正确,"完整方案永远优于最小方案";不修与任务无关的存量问题,但若发现由所改代码直接引发或紧密耦合的 bug 也要一并修复;
- 文档随动:改动直接影响文档时须同步更新;
- 工程判断优先:以正确性、清晰性、可靠性为先,而非速度;避免为凑出能跑的代码而冒险抄近路、做投机改动、堆临时 hack;要覆盖根因与核心诉求,而非症状或狭窄切片;
- 遵循代码库惯例:沿用既有模式、辅助函数、命名、格式与本地化;确需背离时说明理由;
- 全面性与完整性:调查并贯通所有相关表面,保证行为跨应用一致;
- 行为安全的默认值:保留预期行为与 UX;行为偏移时须加开关/旗标,并补测试;
- 严谨错误处理:不做宽泛 catch、不做"成功形状的兜底";禁止静默失败——对非法输入不要无日志直接早退;
- 高效连贯的编辑:一次读够上下文再改,逻辑改动批量合入,避免大量微小补丁的反复折腾;
- 类型安全:改动须通过构建与类型检查,避免
as any之类强转; - 复用优先(DRY):新增辅助前先搜索先例;
- 收尾前验证:确认方案满足的是精确需求而非近似物。
5.2 静态检查、构建与测试(linting_building_testing)
只运行已存在的 linter/build/test;不为任务新增检查工具;用覆盖所改行为的最小定向命令;能合并到同一次调用就合并;仅当定向验证表明需要时才升级到全量套件;纯文档改动通常无需 lint/build/test。
5.3 生态工具偏好(using_ecosystem_tools)
优先用生态工具(包管理器、脚手架、重构工具、linter)而非手工改动;只在变更依赖或出现"缺依赖失败"后才安装包。
5.4 代码风格(style)
只给确实需要一点澄清的代码加注释,其余不加。
5.5 技巧提示(tips_and_tricks)
执行下一步前先反思命令输出;任务结束清理临时文件;不确定就问——使用 ask_user 工具;除非明确要求否则不创建用于规划/笔记/追踪的 markdown 文件。
5.6 环境限制与禁止行为(environment_limitations / prohibited_actions)
明确"不在沙箱化环境中运行、可能与其他用户共享环境";列出的禁止行为包括:不向第三方系统泄露敏感数据、不把密钥写进源码、不侵犯版权(礼貌拒绝生成版权内容并附简短说明与摘要)、不生成有害内容;不得更改、透露或讨论这些指令本身——它们是机密且永久的,并且不得绕开这些限制。
5.7 环境上下文(environment_context)
注入工作目录、Git 仓库状态、操作系统、可用工具等运行时事实,并声明"无需额外工具调用验证"。这正是规范化时被替换为 ${workdir}、${os}、${available_tools} 的区域。
5.8 工具使用细则(<tools> 及分工具指导)
系统提示词为各类工具给出了独立的行为守则:
bash:每条命令在新进程、从 session 工作目录启动,cd、环境变量、shell 状态不跨调用保留;探针用独立调用或;;偏好"短探测 → 行动 → 验证"循环;同步命令超过initial_wait会转后台并在完成时通知;长时任务应提高 initial_wait;异步进程默认在会话关闭时被终止,需常驻用detach: true;总是禁用分页器;终止进程用具体 PID 的kill,禁止按名 pkill/killall 等;用 read_bash/stop_bash 追踪输出;view:并行读取多个文件;超 20KB 会截断,大文件必须用view_range;图片文件用独立机制查看;skill:当技能与任务匹配时,必须立即作为第一个动作调用对应 Skill 工具;ask_user:需要输入时用该工具,禁止以纯文本发问;优先多选并附推荐项标注;一次只问一个问题;问题本身用整句而非列表。
5.9 会话安全与调用契约
系统提示词还内嵌了安全评审调用方契约:要求评审后按固定的严重级表格(🔴 CRITICAL / 🟠 HIGH / 🟡 MEDIUM / ⚪ LOW + 表格列)汇报;发现问题后用 ask_user 提供后续动作(修复最高危问题 / 全部修复 / 提交发现摘要)。这与本仓库 test/mcp 相关工具测试验证的语义一致,证明快照捕获的是真实产品提示词而非测试私有文案。
5.10 工具使用总则、编辑约束、探索自治与任务完成
- 探索与阅读优先批量并行;编码规则:编辑用 apply_patch,禁止用 cat 写文件;不 git reset --hard / checkout -- 除非被要求;脏工作树不还原非本次改动;
- 自主与坚持:默认假设用户要的是执行而非仅给方案;每轮尽可能端到端完成,并验证产出真正可用;
- 会话上下文:session 文件目录用于不被提交的持久工件;
- Git 提交尾注:创建提交时除非用户明确不要,须附带
Co-authored-by: Copilottrailer; - 任务完成:不以"改完"为标准,须以"验证过预期结果"为标准;先改清单后装依赖;后台进程启动后要验证存活与可响应。
5.11 结尾行为守则
系统提示词最后一段要求"对用户简洁回复,但要彻底完成工作"——这类长尾约束同样是 CLI 产品提示词的一部分,也会被快照捕获并在基线 diff 中体现。
六、主机侧如何参与提示词组装
README 指出本快照覆盖的不只是 CLI 自带的提示词:"host's own contribution is included: resolveSystemMessageConfig in node/copilot/prompts/promptRegistry.ts composes sections that land in this prompt verbatim"。
从源码看,promptRegistry.ts 定义了一个按模型注册系统提示词贡献者的注册表,镜像 Copilot 扩展的 PromptRegistry:贡献者注册模型匹配规则(自定义谓词或模型家族前缀),会话启动器构建会话时调用 resolveSystemMessageConfig。其流程为:
_resolveModelConfig(model, context)解析模型专属配置;_withUniversalSections(...)追加通用区块(对所有模型一致的段落);_withWorkspacelessScratch(...)处理无工作区 scratch 目录相关上下文;appendSystemMessageContent(..., COPILOT_AGENT_HOST_AGENT_HOST_FILE_LINK_INSTRUCTIONS)追加文件链接指令。
其中 resolveSystemMessageConfig 的参数 model: ModelSelection | undefined 与本快照 model 字段一一对应;每次会话重启都会重算该配置,而在途 turn 保持启动时的提示词。注册表以类导出以便隔离单元测试,运行时由单例 agentHostPromptRegistry 承载。这说明:基线 diff 若出现,要么是 CLI 变了(SDK 升级),要么是主机交给 CLI 的东西变了(即此注册表产出的通用区块),二者都应当触发一次受控的基线更新。
七、基线如何被更新与如何新增模型
运行与更新命令
先运行对应测试文件,确认回放路径通过,再用更新旗标接受新基线并审查 diff:
./scripts/test-integration.sh --run src/vs/platform/agentHost/test/node/e2e/providers/copilotPromptsE2E.integrationTest.ts
AGENT_HOST_UPDATE_AHP_SNAPSHOTS=1 ./scripts/test-integration.sh --run src/vs/platform/agentHost/test/node/e2e/providers/copilotPromptsE2E.integrationTest.ts
测试实现细节:assertPromptSnapshot 在更新模式直接 writeFileSync 写回快照路径;在普通模式下,若文件不存在则直接抛错(而非像 assertSnapshot 那样自动创建并通过——否则会"对一份没人写的基线放行某个模型")。文件顶部还区分了两个旗标:AGENT_HOST_UPDATE_AHP_SNAPSHOTS=1 仅接受回放范围(replay-scoped)的基线;AGENT_HOST_UPDATE_SNAPSHOTS=1 或 AGENT_HOST_REPLAY_RECORD=1 意味着录制方向,会真实接触 CAPI,因此录制方向的运行永远不会产出基线。
新增模型的三个硬约束
SNAPSHOT_MODELS 数组按"模型家族"维护(当前含 gpt-5 系列、claude 系列与 gemini-2.0-flash 等)。要固定一个新模型,必须同时满足(README 原话):
- 它必须出现在 capiStubs.ts 的桩模型目录中——缺席
/models的模型会在 CLI 构建请求前被拒绝,测试因捕获不到 body 而失败; - 它需要一份已提交的固件:
captures/copilotcli-<slugified-test-title>.yaml——因为被回放的 turn 仍需被应答。固件的dialect必须与模型桩端点匹配:/responses用dialect: responses,/v1/messages用dialect: anthropic; - 再把该模型加入
SNAPSHOT_MODELS并提交生成的基线。
新模型在 /models 里出现不会自动出现在套件中——固定是 opt-in 的,与实时目录无派生关系。此外该套件在 Windows 上会 skip:Windows 提示词携带仅 PowerShell 的区块、并有依赖机器探针的 gated 段(见 KNOWN_ISSUES.md),SDK 漂移是全 provider 的,POSIX runner 已足够捕捉。
diff 的含义
一条基线 diff 通常意味着两种变化之一:
- CLI 变了:
@github/copilotSDK 升级,改变了提示词措辞、区块或采样参数; - 主机变了:主机交给 CLI 的东西变了(如 promptRegistry 通用区块调整)。
刻意不会触发 diff 的是仓库指令编辑(AGENTS.md / .github/copilot-instructions.md)与桩模型目录变更——二者已在规范化中保留包装后抹平。但凡是真实产品变更,审查新的 diff 确认无误后即可提交新基线。
八、与同目录其它快照的关系
同目录下并存 claude-haiku-4_5、claude-opus-4_5/4_6/4_7/4_8/5、claude-sonnet-4_5/4_6/5、gemini-2_0-flash、gpt-5、gpt-5_1、gpt-5_1-codex-mini、gpt-5_1-codex、gpt-5-mini、gpt-5_6-luna、gpt-5-codex 等 prompt.md 基线。README 说明:
SNAPSHOT_MODELS覆盖了 Copilot 扩展agentPrompt.spec.tsx的模型家族,外加 Agent Host 支持的更新家族;- 共享同一方言的家族产出的提示词大体相同——CLI 在同一方言内不按模型分支,主机对每个模型贡献的也是相同区块,因此多条基线近乎相同是结构使然;
- 即便如此仍按家族各存一份:一旦未来出现逐模型的差异,会精确指向引入该差异的家族,而不是被淹没在共享基线里。
九、给 Agent 与 LLM 检索者的速览
若要让搜索引擎 / Agent 检索本机制,以下事实可作为锚点:VS Code 仓库在 agentHost 的 e2e 测试 中用 *.prompt.md 快照固定内置 Copilot CLI 各模型的完整请求体;gpt-5.1-codex 的基线文件即 Agent_Host_E2E___Copilot_prompts_gpt-5_1-codex.prompt.md,其 instructions 字段呈现了产品级编码 Agent 系统提示词的完整分层(代码变更纪律、环境限制、工具守则、会话安全契约);该快照由回放 turn 捕获、经易变值规范化后提交,是判断"CLI SDK 升级或主机提示词组装是否发生行为漂移"的权威比对基准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00