Agent Prompt Atlas提示词源代码图谱
证据模式
← 返回 提示词基础
F03 · FOUNDATIONS

上下文窗口、消息序列化与可见边界

正文完成章节 3/13

学习目标

本章结束时,你应能从一个 Agent 的源码追到它的 HTTP 请求,并回答模型在这一轮究竟看见了什么。你会区分字符、UTF-8 字节和 token,理解 role、content block、tool call ID、图片和文件输入为什么不能被无损压成一个字符串。你还会分析项目指令发现、历史链、缓存和压缩如何改变可见边界,并设计一个只改变单一上下文变量的捕获实验。

上下文不是“所有已知信息”的同义词。模型只看到请求实际携带的内容,以及 Provider 按协议恢复的状态。磁盘上的文件、数据库中的 memory、终端环境变量和运行器内部 state,只有经过发现、筛选、序列化并发送,才进入模型上下文。反过来,一段内容只要进入请求,即使用户界面没有显示,也可能影响生成。研究上下文的任务,就是把这条可见性边界画清楚。

IMAGEGEN
图像资产待生成
图 01:上下文是有序结构

图 01 说明:请求由 instructions、message items、tool definitions 和多种 content blocks 组成;它们有顺序和类型,不是一块无结构文本。

1. 从字符到 token 的三次转换

源码通常按字符或字节限制文件,模型 API 则按 token 计算上下文。中文字符在 UTF-8 中通常占多个字节,tokenizer 又可能把一个词、一个汉字或标点组合成不同 token。20,000 characters20,000 bytes20,000 tokens 是三个完全不同的门槛。Agent 配置若用字节截断项目文件,却用 token 判断压缩阈值,就需要在两处记录单位。

字符是语言层单位,适合教程字数、UI 文本和简单长度检查。字节是文件和网络层单位,适合 project_doc_max_bytes、HTTP body 大小和哈希。Token 是模型层容量与计费单位,取决于 tokenizer 和模型。一个 prompt 文件的 SHA-256 对字节稳定,但不能直接告诉你消耗多少 token。

IMAGEGEN
图像资产待生成
图 02:字符、字节和 token

图 02 说明:同一段中英文在三种单位下得到不同计数;任何容量限制都必须标明单位与计算时点。

运行器常在多个阶段转换内容:读取 UTF-8 文件,去除 frontmatter,截断字符或字节,拼接分隔符,序列化 JSON,再由 SDK 和 tokenizer 估算 token。每次转换都可能改变边界。教程里的 source hash 应对原文件计算,runtime hash 应对实际消息文本计算,不能把二者混为一个值。

2. Content block 保留多模态边界

一条消息的 content 不一定是字符串。它可以包含文本、图片、文件引用、音频、tool use 或 tool result。把这些块转换成 '[image]' 文本会丢失媒体、顺序和元数据;把所有文本块 join,也会丢失哪些段落是用户输入、哪些是工具返回。

多模态 Agent 需要记录每个 block 的 type、位置、MIME、尺寸或引用 ID。图片可能由模型原生读取,也可能先经 vision tool 转成文本。两条路径给模型的上下文不同:原生图片保留视觉细节,工具摘要只保留提取结果。研究网页应把 transformation 标出来。

文件输入也可能采用上传 ID,而不是在消息中内联全文。模型是否能访问文件取决于 Provider 工具、检索或 sandbox,不是看到路径字符串就能读取。提示词写“请查看 /tmp/a.pdf”只提供一个名字;运行器必须附加文件、暴露 read_file,或把内容加入 context。

3. Responses 的 item 模型

Responses API 把输入和输出表示为 item。Input 可以包含 message、function call output 等类型,顶层 instructions 提供当前请求的高层指令。Output 数组可能同时出现 assistant message、tool call 和其他条目,因此客户端不能假设第一个 output 就是文本。OpenAI 官方 Prompt engineering 文档明确提醒 output 可能包含多种 item,并提供聚合文本的 SDK helper[^src-openai-prompt]。

Item 模型的好处是保留结构。Function call output 与 call ID 关联,文本与图片是不同 content type,role 也属于 message item。代价是捕获器和网页必须理解 schema,不能只搜索 JSON 中所有 content 字段。一个通用 textFromContent() 适合生成阅读副本,但原始 capture 仍要保留。

使用 previous_response_id 时,Provider 可以关联前一响应,但应用仍需理解什么被继承。上一章已经说明 instructions 不自动继承。工具定义、动态 policy 和项目规则是否重发,也由应用框架决定。连续请求 capture 能验证这一点。

4. Chat Completions 的消息数组

Chat Completions 使用有序 messages。System/developer/user/assistant/tool 的顺序形成对话上下文。Assistant 发出 tool_calls,tool message 通过 ID 返回结果。多个并行调用时,调用与结果不能仅靠位置配对;ID 是结构化关联。

IMAGEGEN
图像资产待生成
图 03:三种线协议对照

图 03 说明:Responses 以 item 为中心,Chat Completions 以 messages 为中心,Anthropic Messages 以 system 和 content blocks 为中心;图只比较边界,不暗示功能完全等价。

兼容服务可能只实现一部分 OpenAI schema。它们可能拒绝 developer、忽略 reasoning 参数、不支持并行 tools,或把图片格式限制为 URL。成功返回 HTTP 200 也不证明所有字段被使用。Provider adapter 应声明 capabilities,测试应检查最终请求和行为。

本项目的 Hermes、Pi 和 Grok capture 采用 Chat Completions 形状,三者的 system 文本长度和内部层次不同。相同协议便于统一捕获,却不能证明它们对 history、tool results 或缓存使用相同策略。

5. Anthropic Messages 的内容块

Anthropic Messages 通常把 system 与 messages 分开,并在 content 数组中使用 text、tool_use、tool_result 等块。工具调用由 block ID 关联,cache control 可能附着在 system 或工具等特定块上。严格的角色交替和 block 顺序会影响请求是否合法。

将 Anthropic 请求适配成 OpenAI messages 时,需要映射 tool blocks、system blocks 和 assistant content。某些信息没有完全同构表示。统一 Agent SDK 应在内部保持丰富结构,最后按 Provider 降级;不能先压成最低公共字符串,再期待恢复原语义。

Prompt caching 也依赖块边界。一个缓存标记若被放错 block,可能降低命中或改变成本。研究时应记录 cache_control 等协议字段,但不能把它们当自然语言 prompt 展示。

6. Tool call ID 是上下文的一部分

两个工具并行运行时,结果可能以不同顺序返回。Call ID 让模型知道每个结果属于哪个动作。若执行器丢失 ID,只按完成顺序追加,模型可能把搜索 A 的结果当成搜索 B。这个错误不是提示词措辞能修复的。

IMAGEGEN
图像资产待生成
图 04:并行工具结果通过 ID 绑定

图 04 说明:call_A 和 call_B 并行,结果顺序可以颠倒,但下一次请求通过 ID 正确关联。箭头标注 create、execute、return、bind。

工具结果还可能非常长。运行器可以截断、摘要或保存到文件再返回引用。每种策略都改变模型可见内容。若 tool schema 说返回完整日志,而运行器只保留末尾 4 KiB,模型会基于错误 contract 决策。返回 metadata 应说明 truncated、original size 和 artifact path。

错误结果也应关联原调用。重试时使用新 ID 还是同一 ID,取决于协议和运行器。日志必须区分模型重发、执行器自动重试和网络 transport 重试,否则会把重复副作用误判为多次模型决策。

7. 消息顺序承载因果关系

对话历史不是可以任意排序的文档集合。User request 先于 assistant tool call,tool result 先于 assistant final answer。改变顺序会改变因果解释,甚至使请求无效。Context builder 应维护 turn 与 call graph,而不是把所有文本按“重要性”重新排序。

项目规则、memory 和 retrieved context 可以放在高权限前缀或当前 user message 周围,但顺序必须有明确语义。OpenAI 文档建议 developer message 通常按 identity、instructions、examples、context 组织,并把变化的 context 放在后部[^src-openai-prompt]。这是一种常见结构,不是所有模型的绝对最佳顺序;需要通过 eval 验证。

Few-shot examples 中的 user/assistant 对话也有顺序,但属于 example,不是实际历史。网页和 trace 应标记 origin。否则调试人员可能以为模型之前真的回答过示例内容。

8. 项目指令的发现和合并

OpenAI 官方 AGENTS.md 文档说明,Codex 每次运行构建一次 instruction chain。全局层先检查 Codex home 中的 AGENTS.override.md,不存在时读取 AGENTS.md;项目层从项目根走到当前目录,每个目录依次检查 override、AGENTS 和 fallback names,每目录最多一个;最后按根到当前目录连接,较近规则出现在后面并覆盖较远指导[^src-openai-agents-md]。

IMAGEGEN
图像资产待生成
图 05:Codex 项目指令发现链

图 05 说明:全局、项目根、services、payments 按顺序合并;同目录 override 取代普通 AGENTS,较近目录规则后出现。

默认 combined size 受 project_doc_max_bytes 限制,官方文档当前写明 32 KiB。空文件跳过,到上限停止添加。这里有两个可见边界:搜索边界只走到当前目录,容量边界可能截断后续文件。若关键规则超过上限,模型根本看不到,不能靠“它在仓库里”证明生效。

Codex 发现策略与本次捕获的旧版基础 prompt 描述存在差异:旧 prompt 的 AGENTS.md spec 更概括,当前官方文档给出 override、fallback 和 byte limit 细节。网站应把运行版本 prompt 和当前产品文档并列,避免用新文档偷偷改写旧 capture。

9. 不同 Agent 的项目上下文策略

Hermes 项目上下文使用优先链:.hermes.md/HERMES.md、AGENTS.md、CLAUDE.md、cursorrules,第一种匹配类型生效。它还扫描潜在 prompt injection、去除 frontmatter,并按配置或上下文窗口截断。SOUL.md 是独立身份来源,避免重复加载。

Pi 的 resource loader 发现 AGENTS.md 与 CLAUDE.md,并把预加载的 contextFiles 包裹成 <project_context>。它允许关闭 context files,也允许 SDK 调用者直接提供预加载数组。研究时要区分发现器输出和 system prompt builder 输入。

Grok Build 的 prompt 说明项目指令文件可以在仓库各处出现,更深目录优先。具体发现、信任和远程配置又由 shell config 层负责。只读模板不能完全回答 loader 行为,需要 source 与 runtime capture 配合。

10. 截断是一项语义决策

上下文过长时最简单的办法是切掉尾部,但尾部可能是离当前目录最近、优先级最高的项目规则。只切头部又可能丢掉身份、安全 policy 和任务起点。头尾保留能保住两端,却会失去中间定义。任何截断策略都隐含“什么更重要”的判断。

IMAGEGEN
图像资产待生成
图 06:三种截断策略

图 06 说明:头部保留、尾部保留和 70/20 头尾保留会让不同事实不可见。被截断内容不是“权重较低”,而是完全不进入请求。

Hermes 使用带 marker 的头尾分割,让模型知道内容被截断。Codex 按 combined byte limit 停止添加项目文件。工具结果可以返回 artifact path,让模型按需继续读取。好的策略应让截断可观察,并提供恢复路径,而不是静默删除。

截断测试要把关键规则分别放在开头、中间和结尾,记录 capture。还要测试多字节中文是否在字节边界被截断成无效 UTF-8。读取函数应在文本边界安全截断,哈希和 UI 应标明原大小与保留范围。

11. 长上下文并不保证稳定使用

Lost in the Middle 研究发现,相关信息位于长上下文中间时,模型在问答和键值检索任务上的表现可能显著下降;开头或结尾通常更好[^src-lost-middle]。结果随模型和任务变化,但足以反驳“窗口够大就把所有东西塞进去”的假设。

IMAGEGEN
图像资产待生成
图 07:相关信息位置影响使用

图 07 说明:同一相关事实分别位于开头、中间和结尾,模型使用表现不是平坦直线。图标注这是研究现象,不写成所有模型的绝对规律。

Agent prompt 设计应减少竞争:稳定规则简洁、工具描述可检索、项目上下文按作用域选择、长日志按需读取。把所有 skills 全文、整个仓库文档和完整历史一次送入,不仅贵,还可能降低关键信息可见性。

检索也不是万能。向量搜索可能漏掉精确标识符、否定条件或最新变更。Retrieved context 应带来源、分数或检索理由,并允许 Agent 使用 file search/rg 验证。重要 policy 不应只依赖语义检索偶然命中。

12. 缓存前缀与动态尾部

Prompt caching 通常要求请求前缀字节稳定。身份、长期 policy 和不变工具 schema 放在前部,当前 user、tool results 和动态 metadata 放在后部,可以提高复用。OpenAI 官方文档建议把重复内容放在 prompt 和请求体前部,以节省成本和延迟[^src-openai-prompt]。

IMAGEGEN
图像资产待生成
图 08:稳定缓存前缀与动态尾部

图 08 说明:稳定前缀在多个回合保持相同 hash,动态尾部随 user 和 tool result 改变。时间戳若插在前缀会使缓存失效。

缓存布局不能覆盖权限语义。User data 不能为命中缓存搬进 developer。动态组织 policy 必须更新,即使导致 miss。先保证正确和隔离,再优化稳定字节。

Hermes 明确把缓存稳定作为设计原则,冻结会话 system prompt;Codex 也维护 cache key 与 context fragments;Grok、Pi 的 prompt 会随工具和 cwd 变化。研究网页可以显示“cache-affecting fields”,帮助读者知道哪个配置改变前缀。

13. 压缩是有损序列化

当历史接近窗口上限,Agent 可以摘要旧消息、删除低价值工具输出、保存 artifact,再用压缩结果继续。MemGPT 将有限上下文类比为分层内存管理,通过在快慢存储之间移动信息扩展可用历史[^src-memgpt]。这是一种架构启发,不表示摘要无损。

IMAGEGEN
图像资产待生成
图 09:压缩摘要的有损转换

图 09 说明:原始历史先按来源分区,再选择、摘要、校验,形成 compact context。红色标记显示被丢弃内容,绿色标记保留审批与边界。

压缩器应保护不可恢复信息:当前目标、用户纠正、未完成工具调用、审批状态、文件路径与验证结果。可以丢弃重复日志、已读取的大块内容,但需保留 artifact reference。项目规则最好重新发现,而不是由模型摘要复制。

多次摘要会累积漂移。回归测试应保存原历史和每代摘要,检查否定、数字、ID、未完成状态和来源限制。模型生成的“已完成”不能替代环境验证;压缩后仍要保留测试输出或可重新检查路径。

14. Builder snapshot 与 HTTP capture

Builder snapshot 是调用 SDK 前的内部消息结构,HTTP capture 是 SDK/adapter 后的真实请求。两者之间可能发生 role mapping、content block 转换、header 添加、工具 schema 正规化和默认参数注入。只保存其中一个无法定位转换错误。

IMAGEGEN
图像资产待生成
图 10:上下文序列化实验

图 10 说明:固定输入经过 discovery、builder、adapter、HTTP gateway 四站;每站记录结构 hash,最终做 role-aware diff。

最小实验固定 Agent 版本、Provider、模型、cwd、tools 和规则文件。第一次无项目上下文,第二次只加入一份 AGENTS.md,第三次只改变当前目录。分别保存 discovered files、builder fragments 和 request segments。差异应能指向单一变量。

敏感 header 在 capture 时脱敏,但 header 名、请求路径和 content type 保留。Prompt hash 对规范化消息文本计算,原始 JSON 另存。若 SDK 调整空白,source mapping 应说明规范化,而不是宣称字节完全一致。

15. 常见错误

错误一:把整个请求 flatten 成一段字符串。这样会丢失 role、block type、call ID 和多模态。错误二:用字符数估算 token,却不标模型 tokenizer。错误三:认为磁盘文件存在就等于模型已看到。修正是检查 discovery 与 capture。

错误四:静默截断。修正是 marker、原大小和恢复路径。错误五:把 previous_response_id 当作 instructions 永久继承。修正是连续捕获。错误六:为了缓存把动态数据塞进稳定高权限前缀。修正是按权限和生命周期共同分层。

错误七:压缩摘要宣称完成,却丢失真实工具结果。修正是保留 artifact 与验证状态。错误八:把长窗口当成无限记忆。修正是检索、按需读取和位置 eval。错误九:只测 builder,不测 adapter。修正是 builder snapshot 加 HTTP capture。

16. 练习

练习一:给同一句中英文计算字符与 UTF-8 字节,解释为什么不同。练习二:画一个含 text、image、tool use 的 content block 列表,不把它压成字符串。练习三:模拟两个并行 tool call 逆序返回,用 ID 恢复对应关系。

练习四:创建全局、根目录和子目录 AGENTS.md,预测 Codex 合并顺序。练习五:把关键规则放到超过 byte limit 的尾部,验证 capture 是否包含。练习六:为头尾截断设计 UTF-8 安全测试。

练习七:连续两个 Responses 请求只在第一轮发送 instructions,观察第二轮。练习八:把时间戳移入缓存前缀,比较 hash。练习九:压缩含审批拒绝的历史,检查摘要是否保留拒绝。练习十:对 builder snapshot 与 HTTP capture 做 role-aware diff。

17. 先建立上下文预算表

一个 Agent 拥有 128k 或 1M token 窗口,不表示应用应把它全部填满。窗口还要为模型输出、工具调用和下一轮观察留空间。预算表应至少有高权限指令、工具 schema、项目上下文、会话历史、检索资料、当前用户输入、媒体和输出 reserve。每项有上限、缩减策略和不可截断字段。

高权限 policy 通常短而稳定,但工具 schema 可能随工具数量迅速增长。项目文件长度由仓库决定,history 随回合增长,tool result 可能突然产生数万行日志。没有预算表,最先出现的大内容会占满窗口,后续更重要信息只能被临时删除。

预算不是固定比例。代码审查任务可能需要更多项目上下文,图像分析需要媒体 token,简单写作不需要大量工具 schema。运行器可以根据任务类型和工具集合选择 profile,但选择逻辑也要可测试。网页展示 capture 时,应显示各区段字符或 token 占比,不以“总长度”替代结构。

输出 reserve 必须在发送前扣除。若输入已经占满模型总窗口,Provider 可能拒绝请求,或迫使输出极短。压缩阈值应早于硬上限触发,并为工具结果回注留余量。Hermes、Pi 等 Agent 都有 context length 和 max output token 的独立概念,教程应避免把两者都翻成“最大 token”。

18. 工具 Schema 也消耗上下文

每个工具的名称、描述、JSON Schema、枚举和参数说明都会随请求发送。几十个复杂工具可能比 system prompt 更长。Hermes 的 narrow waist 原则正是因为核心工具 schema 每次 API call 都要付出成本;能力优先通过 skills、插件或按需 toolset 暴露。

工具检索是一种解决方案:初始只给 tool_search,模型根据任务查找具体工具,再在后续回合暴露或调用。它降低固定 schema 成本,却增加一次选择和潜在漏检。评测要衡量检索准确率、额外延迟和无法发现工具时的恢复。

另一种方案是按 session surface 决定工具集合。Desktop UI、CLI、gateway 和 headless worker 具有不同可达能力,工具应由会话来源控制,不由进程环境粗略猜测。否则同一后端为多个客户端服务时,会把 GUI 工具错误暴露给 CLI,或让远程 GUI 缺工具。

工具描述压缩也有风险。把参数边界删成一句短描述,可能省 token 却增加无效调用。最优 schema 不是最短,而是用最少歧义表达动作、参数、边界和错误。后续工具章节会用 eval 比较不同描述。

19. 检索内容应该靠近问题,但保留来源

RAG 从外部索引选择与当前问题相关的片段,再加入 prompt。它能让 Agent 访问训练后或专有信息,并避免发送整个知识库。检索质量由 query、chunking、embedding、过滤、reranking 和 top-k 共同决定。模型只看到被选中的片段,没被检索到的事实等同于不可见。

Retrieved chunk 应带 document ID、路径、更新时间和片段范围。模型需要区分来源事实与应用指令。若知识库文档包含命令,它仍是数据,除非高权限规则明确授权将某种配置解析为动作。引用输出也依赖来源元数据;只有片段文本而无 path,模型无法生成可复核引用。

相关片段放在 user message 末尾、developer context 区或 file search tool 结果中,会产生不同角色和缓存行为。不要只比较回答质量,还要比较 prompt injection 风险和缓存 miss。动态检索通常属于请求尾部,不适合进入稳定前缀。

检索失败应显式可见:没有结果、索引过期、权限过滤、query 太宽。Prompt 应要求模型说明缺失信息,不应把空结果当作“事实不存在”。工具结果 schema 可以提供 matched, filtered, index_versionquery

20. Memory 注入是一种检索与重写

长期 memory 不会自动进入模型。运行器可能在会话开始读取固定 snapshot,也可能每回合根据 query 检索。固定 snapshot 稳定、容易缓存,但可能过期;动态检索新鲜、相关,却使请求变化。Hermes 本地 memory 与 user profile 在系统 prompt volatile tier 中形成 snapshot,中途写入不一定立即改变当前缓存。

Memory 写入常由模型把对话总结成事实,这已经是一次有损转换;下次读取再加入 prompt,是第二次转换。记录 original conversation reference、memory text、createdAt 和 lastUpdated 能帮助纠错。只保存一句事实而无来源,会让错误难以追踪。

用户当前明确要求应覆盖旧偏好。Memory 注入区应写明它是背景事实,不是命令。命令式条目如“Always use English”会被模型误读为 policy;陈述“User usually prefers English”更容易被当前中文请求覆盖。

删除同样重要。用户要求忘记某条信息时,要删除存储、索引和缓存副本,并在新会话验证不再注入。网页教程不应把“memory 已删除”只建立在 UI 消失上,需要 capture 或检索结果证据。

21. Skills 的按需加载边界

Skill index 通常只列名称和简短描述,完整 SKILL.md 在匹配任务时读取。这是一种上下文分层:目录小且稳定,正文大且动态。Codex developer 消息给出 skill roots、可用列表和读取规则;Hermes skills prompt 也要求先查看 index,再用 skill_view 加载。

按需加载会产生一次新的工具结果或 developer fragment。运行器应记录 skill name、resolved path、source、version 和正文 hash。两个同名 skill 在用户与项目目录冲突时,需要明确优先级。短 alias 必须先解析成绝对路径,避免模型读取错误位置。

Skill 引用 references、scripts 和 assets 时,主 Agent可能继续读取多个文件。每个文件都占上下文;instruction 要求完整阅读某些文件,是为了避免模型只读第一页。资源加载器可以在工具层提供分页,但关键流程规则应保证读完。

压缩后 skill 正文可能从 history 消失。Hermes 用 [SKILL_PRUNED] marker 要求重新加载。Codex skill 规则也强调选定的 instruction file 要完整读取。重载应使用可信 path,而不是根据摘要中残留内容行动。

22. 超长工具结果的四种处理

第一种是截断。适合只关心末尾错误的日志,但必须保留 truncated flag、原长度和保留区间。第二种是分页。适合模型能按需浏览的数据,但提示词必须要求继续读取关键 instructional content,避免第一页偏差。第三种是摘要。适合重复输出,但会丢失精确行和标识符。第四种是 artifact reference,把完整结果写文件,返回路径与短摘要。

工具应按语义选择处理,而不是全局统一 4 KiB。git diff 可能需要文件分段,测试日志可能优先错误上下文,JSON 数据应保持合法结构,二进制不能按 UTF-8 截断。Result serializer 应由工具拥有,Agent loop 只处理统一 metadata。

当模型需要继续读取 artifact 时,read_file 工具要允许 offset 或 section。但某些 skill instruction 禁止对必须完整阅读的 playbook 分页,因为模型可能偷懒。不同内容类别有不同 lazy-reading 风险,不能使用同一分页 policy。

测试应生成刚超过阈值、远超阈值、含多字节字符和关键错误在中间的结果。Capture 验证模型看到的 marker、范围和 artifact path。行为 eval 检查模型是否会继续读取需要的部分。

23. 多模态序列化与视觉可见性

图片可以作为 URL、base64、file ID 或 provider-specific block 发送。URL 可能在模型读取时过期或被网络策略阻止;base64 增大请求;file ID 依赖上传生命周期。Capture 应避免把巨大 base64 直接展示,但保留 MIME、尺寸、hash 和引用方式。

图片顺序会影响 “Image 1”“Image 2” 的引用。多图编辑 prompt 必须按输入顺序标角色,例如 reference、edit target、supporting insert。Adapter 若重排文件,模型会编辑错误对象。测试应断言 block 顺序和文件 hash。

视觉工具还可能先在本地 OCR、缩放或压缩。每次转换改变模型可见像素。过大图片被缩小可能丢失小字,EXIF 旋转未处理可能方向错误。记录原尺寸、最终尺寸、压缩格式和转换工具,才能解释结果。

文本替代不能替换真实图片生成验收。本项目的 imagegen comp 和知识卡要求真实位图;HTML 截图即使视觉相似,也不是用户指定的生成路径,因此已被删除。内容审计直接检查文件存在,防止 spec 冒充资产。

24. 流式传输不改变已发送上下文

Streaming 让客户端边生成边接收 event,但请求发送完成后,本轮输入上下文通常已经固定。用户中途 steer 需要运行器的专门机制:取消当前请求、追加到当前 turn 的后续请求,或排队下一 turn。不能把用户在 UI 输入的新文字神奇地插入已经在服务端推理的 context。

不同产品对 steer 与 queue 定义不同。OpenAI Codex prompting 文档说明 Codex 工作时可把消息 steer 到当前 run,或 queue 到下一 run。实现可能在工具边界或模型调用间读取新事件。研究时应捕获后续请求,观察 steer 实际出现在何处。

流式工具调用参数可能分多个 delta 到达。执行器必须等参数完整并通过 JSON/schema 校验后再运行,不能看到命令前缀就执行。取消时要清理未完成调用,防止一半参数导致副作用。

捕获网关返回占位 stream 时,也需符合 event 语法。否则客户端可能重试并生成多个 capture。验证 prompt 不需要真实模型语义,但需要协议正确结束,才能证明 Agent 走完请求路径。

25. Retry、幂等和上下文重复

Transport 层遇到 429 或 500 可能自动重试相同请求。Agent loop 也可能在模型错误后重新调用。工具执行器又可能重试命令或 API。三类重试必须区分,否则一个外部写操作可能执行多次。

模型请求重试通常可复用 request ID 或 idempotency key;工具写操作应由业务 API 提供幂等键。Prompt 可以要求执行后读回验证,但不能自己保证网络幂等。日志记录 attempt、request fingerprint、turn ID 和 tool action ID。

上下文重复也会发生:恢复会话时重复加入 system prompt,tool result 被 append 两次,用户消息同时来自 history 和 current input。结构测试应按 ID 和 hash 检查重复,而不是只看总 token 异常。

捕获网关的 latest 文件适合单次验证,但完整研究应保存带时间戳的每次请求,区分自动 retry。网页默认展示 canonical capture,并提供其他 attempts,不能静默选择最符合预期的一次。

26. Context builder 的不变量

第一,角色顺序合法。第二,每个 tool result 有匹配的 call。第三,system/developer 不包含未授权远程数据。第四,动态值不会误入稳定缓存前缀。第五,截断不产生无效编码或无提示丢失。第六,输出 reserve 始终大于零。

第七,项目文件 discovery 与当前 cwd 一致。第八,memory 和 skills 的 source 可追踪。第九,恢复或压缩后不可变 policy 仍存在。第十,敏感 headers 和 secrets 不进入 prompt debug。每个不变量都应有单元或集成测试。

Builder 可以返回 {messages, tools, metadata},metadata 含 fragment list、token estimate、truncations、cache key parts 和 source map。Provider adapter 消费 messages/tools,debug UI 消费 metadata。不要把调试 marker 插进模型 prompt 只为观察;模型不需要知道的记录应留在外部。

Snapshot tests 能发现字节变化,但也容易把动态时间戳冻结成噪音。行为 contract tests 应断言相对顺序、包含条件和映射关系。两者结合:snapshot 审查文案,contract 审查机制。

27. Hermes 的上下文路径

Hermes 从默认或 SOUL.md 身份开始,加入工具/模型指导、完成规则、环境和平台提示形成 stable。Context 包含 caller system message、项目上下文和 coding workspace。Volatile 包含 skills index、memory、user profile、插件分区和时间戳。最终按 stable、context、volatile 连接[^src-hermes-assembly]。

此处“volatile”仍在缓存 system prompt 中,只是相对更易变化,并非每回合动态注入。会话开始构建后,普通回合复用;压缩等重建路径才重新读取。API-call-time ephemeral prompt、prefill 或某些 plugin context 可以走另一条不持久路径。

研究时应分别 capture 新会话、memory 写入后的同会话、压缩后和新会话。预期磁盘 memory 写入不会立刻改变旧缓存,压缩或新会话才可见。若只比较两个新会话,会漏掉核心缓存不变量。

Hermes 还会根据模型 family 加工具强制、执行指导或 Google 特定规则。工具集合影响 skills、memory 和平台能力。一个 capture profile 必须保存 model、provider、platform、tool names、cwd、profile 和 ignore rules 设置。

28. Codex 的上下文路径

Codex 为具体模型选择 base instructions,再用多个 contextual fragments 构造 developer 内容。Permissions、user instructions、apps、environments、plugins、multi-agent role、personality 等可以按配置出现。AGENTS.md discovery 每次 run 构建链,当前官方文档给出 global override、project traversal、fallback names 和 byte limit[^src-openai-agents-md]。

本次 0.151.0 capture 中 instructions 与 developer 分开,developer 主要是 skills/permissions。当前 main 的 template 与旧 capture 不同。研究网页必须允许同 Agent 多版本、多模型 prompt pages,而不是用“最新”覆盖历史。

Codex 的 Responses request 还携带 tools、sandbox metadata、thread IDs 和 headers。Prompt text 只是请求一部分。Debug 页面可以把 header 值脱敏后用于识别 originator 和版本,但不应把 installation ID 当教材核心事实。

验证 AGENTS.md 时,建立临时 CODEX_HOME 和仓库树,分别从根与子目录运行,capture developer fragment。测试 override 选择、fallback、空文件、32 KiB 上限和新 session 重建。不要修改用户真实 Codex 配置。

29. Grok Build 的上下文路径

Grok Agent PromptContext 收集 prompt template、audience、tools、project instructions、user info、memory、role 和 persona。ToolBridge 用 MiniJinja 渲染。不同 prompt profile 可选择 base、apply-patch 或 subagent template。条件 block 按工具 kind 出现。

模板源码被 XOR 混淆进二进制,运行时按需解密并 zeroize。这个机制改变二进制 strings 可见性,不改变模型上下文语义。Source test 证明明文与数组一致,HTTP capture 证明具体版本的渲染结果。

Grok shell 还有 goal planner、verifier、summarizer 和 compaction prompts,它们可能属于辅助模型调用,而不是主 Agent system prompt。网站应按 request purpose 分页:foreground turn、subagent、goal planning、compaction。把所有模板串联会制造不存在的“完整请求”。

官方临时二进制运行时,/v1/models 返回的 model metadata 决定 agent type、backend 和能力。研究 gateway 需要提供最小 models/settings/user endpoints,才能让二进制走真实启动路径。Model list 本身也是上下文配置证据。

30. Pi 的上下文路径

Pi 的 buildSystemPrompt 输入直接展示可变层:customPrompt、selectedTools、tool snippets、prompt guidelines、appendSystemPrompt、cwd、contextFiles 和 skills。默认主体之后追加 project context、skills 和 cwd。Custom prompt 替换默认主体,但这些追加层仍可存在。

Resource loader 负责发现 AGENTS.md、CLAUDE.md、skills 和 prompt templates;builder 不直接扫描磁盘。分层使 SDK 能提供预加载输入,也使测试可以不依赖文件系统。研究时同时检查 loader 和 builder。

Pi 的 prompt templates 是用户命令资源,通过参数替换生成 user prompt,不是 system builder 的同义词。$1$@ 和默认值替换改变用户输入内容。网站应将“系统提示词”和“命令模板”分开导航。

本次 capture 禁用所有资源,得到最小 system prompt。下一步对照实验应逐个开启 read tool、一个 AGENTS.md、一项 skill 和 appendSystemPrompt,构造四个可解释 diff。Pi 是学习单变量上下文实验的理想起点。

31. 设计一个角色感知 diff

普通文本 diff 把消息移动、空白变化和动态字段混在一起。Role-aware diff 先按 segment ID 或 role/type 对齐,再比较正文。Tool schema 按 tool name 对齐,content blocks 按 type 和 index 对齐,动态 cwd/time 可以单独标记。

Diff 输出至少分四类:source text change、assembly order change、runtime dynamic value、protocol transformation。Source change 需要 commit review;order change 可能影响优先级和缓存;dynamic value 是预期;protocol transformation 需要 adapter 说明。

Translation diff 不能直接对中文和英文做行匹配。译文绑定原文 segment hash;原文变化时状态回到 needs-review。译者查看 source diff,更新对应段,保留工具名、路径、标签和版本。

网页双栏可用 paragraph/heading boundary 对齐,而不是强行逐行,因为中英文行宽不同。Source line numbers属于英文,中文显示 segment anchor。切换语言不改变 evidence ledger 和阅读位置。

32. 上下文调试 UI 应显示什么

第一层是摘要:总 token 估算、消息数、工具数、截断数、cache key 和 capture 状态。第二层按 role/type 展开 segments,显示字符、hash、origin、scope 和 source link。第三层显示原始 JSON,默认折叠并脱敏。

UI 要区分“未发送”和“被截断”。未发送的 project file 可以列在 discovery report;被截断 fragment 显示保留范围。模型外 state 如 approval、cwd、sandbox 在独立面板,不伪装成 prompt text。

敏感内容默认隐藏,复制按钮只复制当前 segment。原文/译文/双栏是阅读模式,不改变 raw capture。版本选择器要显示 run version 与 source commit,避免把 current docs 和历史 capture混合。

性能上,不要一次渲染数十万行 raw JSON。使用折叠、虚拟列表或按 segment 页面。静态 Astro 可以为每段生成独立页面,客户端 JS 只处理语言切换和复制。

33. 端到端上下文实验

准备临时仓库:根 AGENTS.md、services/AGENTS.mdservices/payments/AGENTS.override.md,每个文件包含唯一 marker。准备一个 tool 返回长日志,关键 marker 位于中间。固定 Agent 版本和 Provider,分别从根、services 和 payments 运行。

记录 discovery files、builder fragment order、HTTP messages、tool schemas 和 token estimate。验证 payments 运行包含 global、root、services、payments override,且同目录普通 AGENTS 被忽略。将 combined size 调小,观察哪个 marker消失并显示 truncation。

再触发并行 tools,让结果逆序返回,验证 call IDs。将日志超过阈值,确认 artifact path 和 truncation marker。加入 image block,记录转换尺寸。连续两回合测试 instructions 重发,接近上限触发 compaction,检查审批与否定规则。

最后运行 role-aware diff 和行为任务。若模型失败,先确定是 discovery、assembly、adapter、context position 还是 decision。整个实验只使用临时 HOME 和本地 capture gateway,不读取用户真实 secrets。

34. 发布检查清单

  • 每个高权限 fragment 有 role、origin、scope、hash 和 owner。
  • Project discovery 有根目录、当前目录、override 和 byte limit 测试。
  • Tools 有稳定 ID,tool results 能处理逆序、错误和截断。
  • 多模态 blocks 保留顺序、MIME、hash 和转换记录。
  • Token budget 包含输出 reserve 和下一轮工具余量。
  • Cache prefix 不含无必要的时间戳或用户数据。
  • Compaction 保留目标、否定、审批、ID、文件路径和验证事实。
  • Builder snapshot 与 HTTP capture 有结构 diff。
  • Retry 有 request fingerprint 和外部写入幂等策略。
  • Prompt debug 默认脱敏,并有访问与保留边界。

如果任何项只能回答“模型应该会处理”,就还缺 model-external contract 或测试。上下文工程的目标不是让请求尽可能长,而是让每个必要事实以正确角色、正确时机和可复核来源可见。

35. 扩展练习与答案线索

练习十一:为 128k 窗口写预算表,至少留 16k 输出 reserve。答案线索:工具 schema 和动态结果单独预算。练习十二:比较一个 tool schema 全量注入与 tool search 策略。答案线索:测 token、延迟、选择正确率和恢复。

练习十三:把同一 RAG 片段分别放进 developer context 和 tool result,分析权限与缓存。练习十四:设计 memory 删除验证,确保新会话 capture 不再出现。练习十五:让两个同名 skill 位于用户和项目目录,记录 resolver。

练习十六:构造 100k 行测试日志,关键错误在中间,比较截断、摘要和 artifact。练习十七:流式 tool arguments 在半个 JSON 时取消,断言执行器未运行。练习十八:Transport 自动重试相同 POST,识别重复 capture。

练习十九:对 Hermes 同会话 memory 写入前后 capture,验证缓存。练习二十:对 Codex root 与 nested cwd capture AGENTS chain。练习二十一:对 Grok main/subagent prompt 做条件 diff。练习二十二:对 Pi 逐个开启四种资源。

36. 小结

上下文工程最后要落到可操作的预算,而不是停在“窗口很大”这句描述。先为每轮请求列出固定前缀、当前任务、历史、工具定义、工具结果和输出 reserve,再为每一项写出计算单位、来源、是否可截断以及超限后的恢复路径。这样的表比一个总 token 数更能解释回归:总数没有变,工具 schema 变长或输出 reserve 被挤掉,同样会让行为改变。预算表还应记录最小安全余量,例如下一次工具调用至少需要多少输入空间;否则本轮看似成功,下一轮却因为没有空间发送结果而失败。

37. 把预算变成可测试的契约

可以把 builder 的预算输出固定为一个 JSON 契约:fragmentIdroleoriginunitoriginalSizekeptSizetruncatedsourceRef。单元测试检查每个片段是否声明单位,集成测试检查合计是否留下输出 reserve,捕获测试检查最终消息顺序与契约一致。测试数据要包含中文、emoji、长路径和多块图片,因为这些输入会让字符数、UTF-8 字节数和 token 估算出现不同边界。只断言总长度的测试很容易放过“删掉了高优先级片段但数字刚好合格”的错误。

预算还应有优先级而非只有排序。不可丢失的安全 policy、当前用户目标和未完成调用属于 hard requirements;可重新获取的检索段、重复日志和旧的闲聊属于 soft requirements。超限时先删可恢复数据,再压缩可验证的历史,最后才考虑缩短工具描述。每一次动作都写入 budgetDecision,这样审阅者能回答“为什么这段消失”,而不是把差异归因于模型随机性。

38. 工具 schema 的隐藏成本

工具定义本身也是上下文。一个包含几十个可选字段、长描述和重复示例的 schema,可能比一次短用户请求更占空间。设计工具时把字段描述写成可验证的约束,把示例放在开发文档或按需 skill,而不是默认塞进每轮请求。enum 的长字符串、嵌套对象和重复的错误说明都应纳入 token 预算。工具数量变化时,必须重新生成 prompt snapshot 与 cache key,不能只比较自然语言 system 文本。

工具可见性最好由任务能力决定。列出一个工具不等于模型一定会调用它,但模型会为它分配注意力并承担选择成本。可以用三组实验比较全部工具、按阶段工具和单工具提示:固定用户目标、固定历史,只改变 tools[],然后对比调用率、错误参数和请求大小。结果应该记录在 evidence ledger 中;“工具越多越灵活”不是无需验证的原则。

39. 失败回注与幂等边界

工具失败返回时,结果应包含稳定的 call_id、错误类别、是否可重试和下一步建议。网络超时与参数校验失败不能共用同一自然语言句子,因为前者可能重试,后者通常需要模型修正参数。执行器若自动重试,下一轮模型消息中应标记这是 transport attempt 还是新的 decision。外部写操作还需要业务幂等键,防止模型重发与网络重试叠加造成重复副作用。

一个实用的 capture 记录包含 turn_idattemptrequest_fingerprinttool_action_idside_effect_status。调试 UI 按这些字段聚合,读者才能区分“同一请求发了两次”和“模型决定了两次”。如果重试后结果与第一次不同,也要保留两份原始返回及其时间,而不是只保留最后一份。上下文的可见性和系统的实际副作用必须在同一条证据链里对齐。

40. 四个 Agent 的对照实验

跨 Agent 比较时,先固定问题、文件树、工具名称和模型,再分别保存四个 builder snapshot。Hermes 可以展示稳定、上下文、易变三层;Codex 展示 instructions、developer fragments 与权限元数据;Grok 展示模板 profile 和动态插槽;Pi 展示最小主体、工具片段和项目上下文。比较的对象应是相同语义字段,例如“项目规则从哪里来”“工具结果如何回注”,而不是简单比较哪份英文更长。

对照表还要写清不可比较的部分。不同 Provider 的 role、content block 和缓存字段可能没有一一对应,缺失字段不能被解释成“该 Agent 没有这项能力”。先标记 not representednot capturednot supported 三种状态,再讨论行为差异。这样既能利用统一表格,又不会把适配器的降级行为误写成产品设计。

41. 发布前的上下文回归

每次更新 builder,至少运行四类回归:结构回归检查 role、block 和 call ID;预算回归检查 hard requirement 与输出余量;来源回归检查 source hash、版本和动态字段;行为回归检查工具选择、拒绝危险操作和继续读取 artifact。快照只冻结经过规范化的稳定字段,时间戳、随机 ID 和请求追踪号用占位符。这样既能捕捉真实文案变化,也不会因为每次运行都不同而让测试失去信号。

回归报告应把变更分为 expected、review-required 和 breaking。新增一个明确的动态字段通常是 expected;改变 developer 与 user 的相对位置需要 review;丢失 tool result 的 call ID 或把用户数据放入缓存前缀则属于 breaking。报告链接到对应源码、capture 和实验参数,审阅者可以在不运行真实模型的情况下复现序列化结果。

42. 练习:画出你的可见边界

选择一个最小 Agent,准备一份全局规则、一份项目规则、一个包含唯一标记的工具结果和一条当前任务。分别从根目录与子目录运行,记录发现文件、builder 片段、HTTP 消息与哈希。然后把项目上限调到足以截断其中一份规则,检查报告是否明确显示保留范围。最后把工具结果改成逆序返回,验证 call ID 仍能把结果绑定到正确动作。

答案不在“模型答对了”这一项。你应能指出每个标记在哪个阶段首次出现、在哪个阶段可能消失、哪个字段负责把它重新关联,以及哪条限制来自 Provider 而不是自然语言。若无法回答,继续缩小实验变量,直到一次只改变一个文件、一个工具字段或一个消息位置。这个过程本身就是上下文序列化的工程方法。

43. 结语:可见性比长度更重要

上下文窗口是有限带宽,序列化是有语义的编译,捕获是可复核的产物。把磁盘、内存、工具和历史都称为“上下文”会掩盖真正的边界;只有被发现、被选择、以正确 role 和 block 编码并发送的内容,才属于模型本轮可见世界。工程上的目标不是让 prompt 变长,而是让必要事实在正确位置、正确版本和正确权限下出现,并在超限、重试、压缩和 Provider 适配时仍然可解释。

上下文是由协议类型、消息顺序和运行时筛选共同决定的可见集合。字符、字节和 token 控制不同阶段;content block、role 和 tool call ID 保存不能由纯文本替代的结构;项目发现、截断、长上下文位置、缓存和压缩决定哪些事实最终可用。可信研究必须同时观察 discovery、builder、adapter 和 HTTP request。

下一章将聚焦工具 schema、调用和结果回注,把这里的结构边界转化为具体 Agent-computer interface。继续阅读时,请始终问:这段信息存在哪里、何时被选择、以什么类型进入请求、是否被截断或摘要、模型外还能否重新验证。

[^src-openai-prompt]: OpenAI, “Prompt engineering”, https://developers.openai.com/api/docs/guides/prompt-engineering(访问于 2026-08-30)。 [^src-openai-agents-md]: OpenAI, “Custom instructions with AGENTS.md”, https://learn.chatgpt.com/docs/agent-configuration/agents-md(访问于 2026-08-31)。 [^src-lost-middle]: Liu et al., “Lost in the Middle: How Language Models Use Long Contexts”, https://arxiv.org/abs/2307.03172(访问于 2026-08-30)。 [^src-memgpt]: Packer et al., “MemGPT: Towards LLMs as Operating Systems”, https://arxiv.org/abs/2310.08560(访问于 2026-08-30)。 [^src-hermes-assembly]: Hermes Agent, “Prompt Assembly”, fixed at commit 5cc1369f(访问于 2026-08-30)。

图稿与资产状态

每张图先有独立 claim、alt 和 imagegen spec;当前环境允许文件暂缺,但不会把 spec 当成已生成图片。

f03-01 · 01-context-structure.png模型上下文由有序消息和内容块组成,不是一个无结构字符串

请求中 instructions、messages、tools 和内容块的有序结构

IMAGEGEN SPEC 已登记 · 位图待生成
f03-02 · 02-char-byte-token.png字符、字节和 token 是不同的容量单位

中英文文本在字符、UTF-8 字节和 token 三种单位下的对照

IMAGEGEN SPEC 已登记 · 位图待生成
f03-03 · 03-wire-protocols.png三种 API 线协议保留不同的消息和工具边界

Responses、Chat Completions 与 Anthropic Messages 结构对照

IMAGEGEN SPEC 已登记 · 位图待生成
f03-04 · 04-tool-call-id.png工具调用 ID 把异步结果绑定回正确动作

两个并行工具调用通过 call ID 返回并进入下一次请求

IMAGEGEN SPEC 已登记 · 位图待生成
f03-05 · 05-agents-discovery.png项目指令发现链从全局到当前目录按顺序合并

Codex 全局、项目根和子目录 AGENTS.md 发现与覆盖链

IMAGEGEN SPEC 已登记 · 位图待生成
f03-06 · 06-truncation-strategies.png截断策略决定哪些上下文事实永久不可见

头部截断、尾部截断和头尾保留三种策略的可见内容对照

IMAGEGEN SPEC 已登记 · 位图待生成
f03-07 · 07-lost-middle.png长上下文中的相关信息位置会影响模型使用效果

相关信息位于开头、中间和结尾时的注意表现示意

IMAGEGEN SPEC 已登记 · 位图待生成
f03-08 · 08-cache-prefix.png缓存前缀稳定与动态尾部更新需要分层设计

稳定缓存前缀和每轮动态内容的请求层叠图

IMAGEGEN SPEC 已登记 · 位图待生成
f03-09 · 09-compaction.png压缩摘要是有损转换并需要保留来源和关键边界

历史消息经过选择、摘要和校验后形成压缩上下文

IMAGEGEN SPEC 已登记 · 位图待生成
f03-10 · 10-serialization-lab.png上下文实验必须同时记录 builder 输出和 HTTP capture

固定输入、builder snapshot、请求捕获和 role-aware diff 实验面板

IMAGEGEN SPEC 已登记 · 位图待生成