B7|一枪采样与指令栈:模型看见的是 Prompt,不是一份 system
先别把 messages[] 当成历史,也别把说明书焊进 base
读完 B1–B6,下一件错事是打开 Responses 请求,把 input 当成聊天记录,把 AGENTS.md 贴进 system,再把 5xx、窗口满、沙箱拒绝丢进同一个 retry()。附录里有一枪解剖,但若它只待在附录,周末切片会把它当成选修。
判断先说清楚:一次采样的合同是 Prompt 三块——历史投影、这一 Step 冻住的 tools、base 指令。 项目说明书、技能目录、记忆、协作模板不在同一层,也不是每轮都全文进场。reasoning 是历史里的 item;effort / service tier 是 Turn 上冻住的设置,不是第二种循环。怎么用 mock SSE 钉文件和 Event,仍看 附录 F。这一枪怎么飞出去——ModelClientSession、Responses WS/HTTP、鉴权恢复——见 G1。
1. Prompt 三块,不要焊成一段 system
build_prompt(core/src/session/turn.rs:1508-1525)几乎只做赋值:
| 字段 | 从哪来 | 不是什么 |
|---|---|---|
input | history.for_prompt(modalities) | 不是 TUI transcript,也不是 raw AGENTS.md 文件 |
tools | step_context.tool_router.model_visible_specs() | 不是 Handler 注册表全文;看不见的不能 call |
base_instructions | Session::get_prompt_base_instructions() | 不是项目说明书。provenance 是 Model 或 Custom(/review、Plan 换的是这一块) |
for_prompt 按模型 modality 剥图/音频。历史里已经落盘的 fragment——环境、AGENTS.md、TurnAborted——以 user 角色的带标记 item 出现,不是改 base 文本。B4 禁止 system +=,合同就在这个 struct。
parallel_tool_calls 在 build_prompt 里写死 true。能不能真并行,仍看 B2 的门闩:工具自己报名,默认不准。
没有「三块拆开」会怎样?换模型就丢政策;或把 MCP 目录整份塞进 base,compact 永远在救火。
2. 指令栈:谁每轮都在,谁要点名
模型「看见的字」来自好几层。一层一个问题,不要合成一份超级 system。
| 层 | 每轮都在? | 进哪一块 | 该放 |
|---|---|---|---|
| base_instructions | 是 | base_instructions | 模型烤好的操作说明;/review、Plan 可换成 Custom 模板 |
| developer instructions | 视配置 | 通常仍在指令侧 | 宿主/企业加的开发者约束 |
| AGENTS.md | 未信任则否 | input 里带标记 fragment | 短而可执行的项目政策(C1) |
| collaboration 模板 | 仅该 mode | 换 base 或另加 fragment | Plan「先调查再改」;不是 update_plan 工具 |
| Skill 目录 | 开了才有目录块 | input,有 token 顶 | name + description;正文要点名(D1) |
| Memories | feature 默关 | 摘要指路 + 工具读文件 | 个人偏好,不进 git(C2) |
| Personality | 默认保留一节 | 只动 base 里 # Personality | 语气;None 才剥掉(C4) |
冲突时机械拦截赢过 prompt:F1 的拇指规则——ExecPolicy / Hook / 沙箱已经禁了,说明书改不回来。
没有这张栈会怎样?把测试命令写进 Memories,队友 clone 没有政策;把「请简洁」写进 AGENTS.md,每个贡献者的 agent 都变成你的口吻;把技能全文每轮灌进 base,窗口先被手册撑满。
3. Reasoning 是历史 item;effort 不是第二种循环
ResponseItem::Reasoning 带着 summary,以及可选的 encrypted_content(context_manager/history.rs)。它进 input 和 rollout,和 assistant 文本、tool call 一样是 有界历史项,不是旁路再 POST 一次「思考模型」。compact / resume 必须把它当 item 处理:不能当聊天字去改,也不能在截断时撕开半个加密块。
effort、service tier 是 Turn 开始时冻住的设置(和 A2 的 TurnContext / StepContext 同一哲学)。调高 effort 不会新开 TaskKind,不会换 Orchestrator,也不会把沙箱拧成 DangerFullAccess。它们和 approval_policy、model 并列出现在 turn/start 上,各管各的。
没有这层会怎样?你会为「想深一点」再写一条 agent 循环,或者把 reasoning 摘要当用户原话塞进 compact。
4. 失败谱:采样、窗口、工具、额度不是一种 retry
附录 F 把表写全。B 组只要记住分流:
| 失败 | 谁处理 | 不准做的 |
|---|---|---|
| 流断开 / 可重试 5xx | 采样 loop 重试;用尽才 Session 级 HTTP fallback(G1) | 每枪新建 ModelClientSession |
| 窗口满 | 采样前 compact(B4) | 在采样 loop 里截断 input |
| 工具失败 / 沙箱拒绝 | 结果回下一枪,或 Orchestrator 升级(B3) | 把 exit 2/126/127 当沙箱拒绝;一个 retry() 通吃 |
| 额度 | 返回 / 记 rate limits;记忆管道可跳过 | 当成关沙箱 |
窗口满必须发生在 下一枪采样之前。工具失败是下一枪的 item,不是采样重试。
5. 钉循环仍然用附录 F,不要钉 TUI
课程判断在这一章。怎么证明「一枪合同没焊错」,用 test_codex + mount_sse_once 钉文件和 EventMsg(附录 F)。P0 对照本仓库那条 apply_patch_tool_executes_and_emits_patch_events:第一枪补丁、第二枪说完、磁盘出现文件、过程有 FileChange 类 Event。
6. 结语:带走一句话
一枪采样的合同是 Prompt 的三块——历史投影、这一 Step 的 tools、base 指令——AGENTS.md 在 input 里;指令栈里技能要点名、记忆要开闸;reasoning 是历史 item,effort 只是 Turn 设置;流才重试,窗口满走 compact,工具失败当下一枪的 item。