运行时提示词叠加层:动态注入会话上下文到 Agent 系统提示
运行时提示词叠加层:动态注入会话上下文到 Agent 系统提示
学习目标
读完本章后,你将能够:
- 设计运行时提示词叠加层(Runtime Overlay),在 Agent 系统提示中动态注入会话上下文
- 使用 HTML 注释标记实现叠加层的幂等应用与剥离
- 实现会话作用域模型指令文件的三层合并
- 理解代码地图生成与缓存策略
- 设计压缩协议(Compaction Protocol)防止上下文压缩时丢失关键状态
前置知识
核心概念
1. 为什么需要运行时叠加层
Agent 的系统提示(如 AGENTS.md)通常是静态文件,存储在用户目录或项目目录中。但在每次会话启动时,需要注入会话作用域的上下文:
| 需要注入的信息 | 为什么不能写入静态文件 |
|---|---|
| 会话 ID 和时间戳 | 每次会话不同 |
| 当前活跃的模式状态 | 模式状态随工作流变化 |
| 代码地图(项目目录结构) | 代码库会演进 |
| 项目记忆摘要 | 从运行状态中动态提取 |
| 团队编排器指令 | 仅团队模式需要 |
运行时叠加层的方案是:在会话启动时读取静态文件,注入运行时上下文,将合并后的内容写入会话作用域的文件。会话结束时剥离叠加层,不修改源文件。
2. HTML 注释标记与幂等应用
叠加层使用 HTML 注释标记界定注入范围:
AGENTS.md 源文件:# Project Agent Guidelines...(用户编写的内容)...
会话启动时的叠加层注入后:# Project Agent Guidelines...(用户编写的内容)...
<!-- OMX:RUNTIME:START -->## Session MetadataSession ID: omx-1717567890-abc123Timestamp: 2026-06-05T02:10:00Z## Native Subagent Routing...<!-- OMX:RUNTIME:END -->幂等性保证:
伪代码:function applyOverlay(agentsMdContent, overlay): // 先剥离已有的叠加层 content = stripOverlay(agentsMdContent) // 再注入新的叠加层 return content + "\n\n" + wrapWithMarkers(overlay)
function stripOverlay(content): return content.replace( /<!-- OMX:RUNTIME:START -->.*?<!-- OMX:RUNTIME:END -->/gs, "" )为什么需要幂等:如果叠加层已经被部分应用(如上一次会话未正常清理),重新应用不应产生重复内容。
多标记类型:
| 标记 | 用途 |
|---|---|
<!-- OMX:RUNTIME:START/END --> | 主叠加层 |
<!-- OMX:TEAM:WORKER:START/END --> | 团队 worker 叠加层 |
<!-- OMX:MODELS:START/END --> | 模型路由叠加层 |
<!-- omx:generated:agents-md --> | 生成的 AGENTS.md 标记 |
3. 叠加层注入内容(优先级排序)
叠加层内容按优先级排序,溢出时截断:
溢出保护:总上限 3500 字符,优先保留 Required 部分。Optional 部分按优先级依次注入,直到达到上限。
4. 代码地图生成与缓存
代码地图是项目目录结构的轻量级快照:
伪代码:function generateCodebaseMap(): mtime = getGitIndexMtime() if cache.mtime == mtime and cache.map exists: return cache.map
files = run("git ls-files --cached") dirs = groupByTopLevelDirectory(files)
map = "" for dir, count in dirs (max 14 directories): map += formatDirectory(dir, files[dir] (max 10 files))
cache.mtime = mtime cache.map = truncate(map, 1000) // 上限 1000 字符 return cache.map缓存策略:基于 git 索引的 mtime 判断是否需要重新生成。git 索引未变更时直接返回缓存。
5. 会话作用域模型指令文件
会话启动时,系统创建一个会话作用域的合并文件,合并三个来源:
阴影技能过滤:如果项目级 AGENTS.md 引用了与用户级 AGENTS.md 相同的技能,则删除项目级的阴影引用(避免技能定义冲突)。
6. 压缩协议(Compaction Protocol)
当 Codex 的上下文窗口接近上限时,会自动进行上下文压缩(compaction)。压缩协议确保关键状态不被丢失:
叠加层中的压缩协议指令:"Before context compaction occurs, checkpoint all active states:1. Write current mode state via `omx state write`2. Record skill active state3. Save progress ledger entries4. Then proceed with compaction"为什么需要压缩协议:上下文压缩会丢弃早期对话历史。如果关键状态(如当前技能阶段、迭代计数)只存在于对话历史中,压缩后 Agent 会”忘记”当前进度。
7. 文件锁与并发安全
叠加层的写入使用目录级文件锁:
伪代码:function withOverlayLock(operation): lockDir = mkdir(".omx/locks/overlay") // 原子操作 try: return await operation() finally: rmdir(".omx/locks/overlay") // 如果 PID 不存在,说明锁持有者已崩溃,直接删除死 PID 回收:如果锁目录的 PID 对应的进程不再存在,直接删除锁目录,允许后续操作继续。
8. Ralph 规划门控
Ralph 规划门控是叠加层的动态部分,根据规划工件的存在性显示状态:
当 .omx/plans/ 中存在 PRD 和 test-spec 时:## Ralph Planning GateStatus: UNLOCKED — PRD and test-spec artifacts exist.
否则:## Ralph Planning GateStatus: BLOCKED — No PRD found. Run $ralplan first.门控的目的:防止 Ralph 在没有批准方案的情况下直接实现代码。
陷阱与对策
| 陷阱 | 后果 | 对策 |
|---|---|---|
| 叠加层标记不匹配 | 源文件被污染 | 严格使用 HTML 注释标记,正则剥离时 s 模式匹配跨行 |
| 代码地图超过字符上限 | 叠加层被截断 | 代码地图单独限制 1000 字符,溢出时丢弃低优先级内容 |
| 并发写入竞争 | AGENTS.md 损坏 | 目录级文件锁 + 死 PID 回收 |
| 压缩丢失状态 | Agent 忘记当前进度 | 压缩协议强制先持久化状态 |
| 会话作用域文件残留 | 新会话使用旧叠加层 | 会话启动时先 strip 再 apply |
| 阴影技能冲突 | Agent 使用错误的技能定义 | 合并时检测并删除项目级的阴影引用 |
参考来源
- OpenAI Codex CLI — AGENTS.md runtime overlay and session-scoped model instructions
- HTML comment parsing patterns — Standard HTML comment syntax