上下文核心模型设计
最后更新:2026-06-06
设计背景
March 的核心卖点是“上下文不会腐烂”。传统 Agent 把对话历史线性累积——读到旧版本文件、忘记前面做了什么、上下文膨胀后丢失关键信息。March 的当前做法是在 Agent Run 开始时从当前事实组装初始上下文;Agent Run 过程中如果模型调用工具,后续 Model Call 由 pi-agent 基于持续追加的 transcript 推进,而不是 March 重新组装 context layers。
系统结构
稳定层在上(一次注入、长期有效),高频层在下(Agent-run-start Context Assembly 刷新、按需注入)。排序的第一原则是 provider prefix cache:高频变化的小层不能放在大块内容前面,否则会让后面的大块 token 缓存失效。
层名 | 稳定性 | 写入方 | 读取方 | 职责
[system_core] ← 几乎不变 | 写入:系统初始化 | AI 只读 | March base prompt、角色定义、安全约束、模型专属追加提示
[injections] ← session 级 | 写入:MCP/扩展启动时 | AI 只读 | 外部系统明确要求注入给模型看的指令
[session_identity] ← session 级 | 写入:March 运行时 | AI 只读 | cwd、workspace root、memory root、平台、shell
[recent_chat] ← Agent Run 级刷新 | 写入:March 运行时 | AI 只读 | 最近 Agent Runs + recall hints排序原因:稳定前缀更容易命中 provider prefix cache;大块且相对稳定的内容尽量放在高频小层之前。文件正文不再作为常驻层注入,AI 需要时通过 read 读取;记忆召回结果不作为独立层注入,而是跟随消息附加在尾部的 [recent_chat] 中。技能系统不再作为独立上下文层存在,原技能类方法论迁移为 memory 文档,由 recall hint 提示线索,再通过 memory_open 主动读取正文。
Shell 输出不作为默认上下文层常驻注入。用户消息尾部只附加极短 [shell_hints],列出可检查的 shell id/name/status/command/cwd/line count;AI 需要内容时通过 terminal_read 或 terminal_snapshot 按需读取。
组件详述
system_core
- 稳定性:几乎不变
- 写入方:系统初始化(模型 base prompt、March 角色定义)
- 读取方:AI 模型(只读)
- 职责:定义 March 的基本行为和身份——遵循什么规则、有什么能力边界
- 内容:稳定的 March 核心行为指令、安全约束,加上按
modelId选择的 model-specific 追加提示 - 边界:
provider、model、thinking是请求元数据,不默认写进上下文文本。modelId只用于 March 内部选择模型专属追加提示,不允许替换 March 基础系统介绍;provider只负责请求路由、鉴权和 transport;thinking只作为 provider request option 传递
injections
- 稳定性:session 级(session 启动时确定,不再变)
- 写入方:MCP server 连接时、扩展加载时
- 读取方:AI 模型(只读)
- 职责:外部系统通过标准协议注入的额外指令,且这些指令必须是明确要给模型阅读的文本
- 内容:MCP server instructions、外部扩展注入的 policy / behavior snippets
- 边界:MCP tools 进入 runtime tool registry;MCP resources 不自动进入上下文;
provider、model、thinking不进入该层
session_identity
- 稳定性:session 级(session 启动后不变)
- 写入方:March 运行时
- 读取方:AI 模型(只读)
- 职责:告诉 AI "你在哪里、环境是什么"
- 内容:当前工作目录、workspace 根路径、memory root、操作系统、平台、shell 类型
- 边界:不包含目录结构、git 状态、最近变更文件或 memory 文件列表;需要工作区事实时由 AI 通过
glob/grep/git status按需查询,需要 memory 正文时通过 memory 工具读取
recent_chat
- 稳定性:Agent Run 级刷新;Agent Run 开始时进入初始上下文
- 写入方:March 运行时(Agent Run finalize 时记录用户/助手最终内容与 recall 输入)
- 读取方:AI 模型(只读)
- 职责:最近对话的压缩视图;同时承载由对话激发的记忆线索,不注入记忆原文
- 内容:最近 10 个 Agent Runs;每个 Agent Run 含用户消息、用户 recall hints、March 最终回复,以及 assistant recall 输入记录
- 被动召回:用户 recall 在 Agent Run 开始前计算并注入;assistant recall 在有工具的中间 assistant 轮结束后以隐藏 steer message 注入,最终 finalize 时只记录不再注入模型
- 召回格式:每条 hint 只包含
id、name、short_description。AI 需要记忆原文时,必须通过主动 memory 工具打开 - 去重规则:用户消息触发的 recall 使用与 recent_chat 对齐的滚动抑制窗口,默认覆盖最近 10 个 Agent Runs;assistant 输出触发的 recall 在当前 Agent Run 内去重,避免 user recall 和 assistant recall 重复提示同一条记忆
- 主动回忆:被动召回只提供线索;AI 可以通过 memory search/open/read 工具主动检索和读取记忆原文
关键流程
流程:Agent Run 开始上下文组装
- [system_core] + [injections] — 稳定层,作为初始 system prompt 的一部分进入 pi-agent
- [session_identity] — March 写入稳定环境身份
- [recent_chat] — 注入最近 10 个 Agent Runs 摘要,以及记录在消息上的 recall hints
- 组装完成 → 作为 Agent Run 的初始上下文交给 pi-agent;后续 Model Call 使用 pi transcript append,不重新组装 March context layers
流程:被动记忆召回
- 用户消息进入 Agent Run 前,March 用用户消息检索 memory store,选出最多 3 条未被滚动抑制窗口过滤的 recall hints,作为隐藏 recall message 注入
- 有工具调用/工具结果的中间 assistant 输出结束后,March 用 assistant 输出检索 memory store,选出当前 Agent Run 内未出现过的 recall hints,作为隐藏 steer message 注入给后续 Model Call
- 最终 Agent Run finalize 时,assistant recall 只写入记录,不再触发新的 Model Call
- 每条 recall hint 只包含
id、name、short_description,不包含记忆原文 - 用户消息召回另有 rolling suppression window,默认覆盖最近 10 个 Agent Runs,避免同一段连续对话里反复提示同一条记忆
- AI 如果需要读取记忆原文,必须调用主动 memory 工具
流程:Shell 线索
- 用户消息进入 Agent Run 时,March 检查当前 shell runtime 是否有非 killed shell
- 如果有,只在 Agent Run 初始上下文里附加
[shell_hints]短摘要,不附加 shell 输出 - AI 需要 shell 内容时调用
terminal_read;需要视觉/ANSI 证据时调用terminal_snapshot
流程:文件被外部修改
- 用户在终端里手动改了
src/auth.ts - 下一次 context assembly 不常驻注入文件正文或工作区摘要
- AI 需要文件内容时调用
read,直接读取当前磁盘内容和行号 - AI 修改文件时调用
edit_file,工具执行时从磁盘读取原文再应用 patch - 诊断功能由 LSP 服务和工具链保留,但不作为默认上下文层注入
流程:编译器产生错误
- 用户或 AI 修改
packages/opencode/src/auth.ts - March 的 LSP client 收到 TypeScript server 推送的 diagnostics,或 typecheck runner 完成一次
bun typecheck - March 将原始错误归一化为
{ source, severity, path, range, message, code } - 下一次 context assembly 不注入 diagnostics;AI 需要时通过工具、命令或 UI 反馈获取错误事实
- AI 修复代码后,diagnostics 随 LSP/checker 下一轮结果刷新,但不作为默认上下文层常驻