最近折腾大模型编程助手的时候我发现很多人其实不是不会写提示词而是压根没管过上下文。模型表现飘忽、改着改着忘了需求、长会话到后半段明显变傻——这些问题的根子十有八九都出在“上下文没有模式”。我按 context-mode 的思路重新梳理了工作流之后效果稳定了不少今天就把这套做法完整拆开讲讲。context-mode 说白了就是给大模型/编程助手的上下文做“模式化调配”什么时候把哪些信息放进窗口、放多少、什么时候压缩、什么时候清空都有一套明确规则。它适合三类人频繁用 AI 做跨文件重构的开发者、维护长会话项目文档的人、以及接 RAG 或者本地知识库但总觉得回答“不够聪明”的人。这个概念听起来像理论但操作起来全是实打实的参数和配置。1. context-mode 到底解决了什么问题1.1 上下文越大模型越容易“装傻”先纠正一个常见的误区上下文窗口不是越大越好。很多人看到 128k、200k 的参数就觉得把所有代码都塞进去模型一定能全局把控。实际用下来完全不是这样。大模型的注意力是会被稀释的。你塞进去的 1000 个代码片段里模型真正能稳定关注的只有头部和尾部一小段中间绝大部分信息处于“存在但没被看到”的状态。这就像把客厅当仓库所有东西都堆在眼前你反而找不到昨天随手放的那把螺丝刀。大窗口只解决“能不能放得下”的问题没有解决“放进去之后有没有用”的问题。context-mode 的核心主张就是在放进窗口之前先分级、过滤、压缩让每一段进入上下文的材料都有明确职责。放什么、不放什么不是靠模型自己临场判断而是由你提前定好的模式规则来决定。这样做能同时解决三类问题无效信息占用窗口、关键信息被淹没、模型因上下文混乱而给出错误判断。1.2 三种典型场景下的上下文崩溃我见过太多“崩溃现场”归纳一下基本就三种每种对应不同的治理思路。第一种是跨文件重构。比如要把一个订单模块从单体函数拆成 service 加 repository 的结构涉及七八个文件。很多人图省事把所有相关文件全部丢给模型。结果模型改 A 文件时引用的是 B 文件的旧逻辑改 B 文件时又用了 C 文件里已经被废弃的接口。看似上下文很全实际上没有任何一层上下文是可靠的。第二种是单文件微调。只改一个函数但你把整个仓库的 wiki、issue 记录、历史对话都留在了窗口里。模型会被那些无关内容带偏甚至在代码风格上频繁摇摆。这类问题最隐蔽因为窗口完全没满你根本意识不到上下文里全是干扰项。第三种是长会话回归。一个会话从早上聊到晚上中间切换了三四个任务。模型越往后越“健忘”不是因为它能力下降而是因为早期的关键决策被大量过程性对话挤到了窗口外面。context-mode 处理这种情况的思路是及时做“模式切换”任务 A 的上下文归档压缩任务 B 的上下文重新组装不让历史包袱拖垮新任务。2. 模式拆解把上下文切成四种类型2.1 全局模式Global常驻的“项目宪法”全局模式负责管理那些无论做什么任务都必须存在的信息。我的建议是只包含四类内容项目技术栈说明、代码规范约定、需求基线文档、关键路径文件清单。总量控制在窗口的 20% 以内。举个例子一个 128k 的窗口全局模式下放 25k 左右的 token。技术栈说明用 5k 能说清楚语言版本、框架版本、包管理器、测试工具。代码规范不用贴完整 style guide而是提炼出“用 Arrow Function 还是 function 声明”“错误处理用 try-catch 还是 top-level return”“命名后缀规则”这类模型最容易犯错的点。需求基线放的是当前迭代要交付什么不是产品 PRD 全文。全局模式的关键就是“少”。少到每一条都值得模型反复阅读。宁可牺牲一点覆盖面也要保证每一条被放进去的信息都是高优先级的。实际操作里我会把全局内容做成一个 fixed.md每次开新会话时原样注入不做任何裁剪。2.2 会话模式Session当前任务的“工作记忆”会话模式承载的是本次任务特有的上下文它是整个 context-mode 体系里最灵活的部分。包括五个要素任务目标描述、涉及文件清单、已完成步骤记录、当前阻塞问题、下一步计划。这五要素不是一直不变的。每完成一个子步骤就要更新“已完成步骤记录”遇到新问题要追加“阻塞问题”如果任务目标发生变化必须更新“任务目标描述”。整个会话模式就像一块白板你可以擦掉一部分重写但始终保持内容最新。会话模式的典型占比是 30%-40%。我见过很多人的问题在于“任务目标”写得太宽泛。比如目标是“优化订单模块性能”模型根本不知道从哪下手。正确写法是“订单列表接口 qps 低于预期定位数据库慢查询并优化目标 p95 响应时间低于 300ms只改查询逻辑不动表结构”。这就是可以直接执行的任务描述上下文的质量瞬间就上来了。2.3 文件模式File按需加载的“引用资料”文件模式处理的是任务真正要阅读和修改的源码。它的原则是“按需加载不要全量注入”。一个任务需要改 3 个文件那就只把 3 个文件放进去而不是把整个模块的 20 个文件全部塞进去。实现上文件模式需要记录两层依赖关系直接修改的文件、必须阅读的引用文件。比如你要改order_service.py它 import 了db.py和cache.py那这两个引用文件即使不改也必须放进上下文。但你不需要把db.py依赖的models.py也放进去除非要修改它。文件模式还有一个细节优先放文件的关键部分而不是全文。一个 1000 行的文件超过一半可能是样板代码对模型理解逻辑没有帮助。我通常的做法是让模型先扫描目录结构和文件头部注释再决定是否全文加载。配置里可以设置depth1、depth2来控制引入依赖的层级避免无限外溢。2.4 压缩模式Slim/Auto给历史做“动态摘要”压缩模式是长会话的救命稻草。当一个会话已经进行了很久历史对话占据了大量窗口就必须启动压缩把原始对话替换成结构化的决策摘要。压缩模式不是简单叫模型“总结一下前面聊了什么”。它要有固定的输出格式我推荐用决策日志Decision Log格式每条记录包含背景、方案选项、最终选择、原因、影响范围。这样压缩后的上下文不是一段含糊的叙述文字而是可以被后续会话直接执行的决策记录。另一个关键点是压缩的触发时机不是等窗口快满了才压缩而是每完成一个里程碑就压缩一次。比如改了 3 个文件、通过了一轮测试就可以做一次 checkpoint 摘要把前面的执行细节丢弃只保留决策日志和当前文件状态。这样整个会话的上下文始终保持在可控范围内。3. 落地实现配置、参数和接入方法3.1 一份可以直接照抄的 context-mode 配置文件我习惯用 YAML 管理所有模式因为结构清晰而且可以写注释。下面是一个实际跑过的配置骨架window: max_tokens: 128000 tokenizer: cl100k_base modes: global: enabled: true budget_ratio: 0.2 sources: - docs/tech-stack.md - docs/code-style.md - docs/release/story.md - scripts/path-map.md session: enabled: true budget_ratio: 0.35 content: goal: null files: [] completed: [] blockers: [] next_steps: [] file: enabled: true budget_ratio: 0.4 depth: 2 include: - src/**/*.py exclude: - **/tests/** - **/*.md slim: enabled: true summit_after_steps: 3 output_format: decision-log switch_rules: default: session refactor: global file debug: session file review: global slim这份配置里最重要的是budget_ratio它决定了每个模式的最大 token 占比。四个模式的预算加起来不要超过 100%实际建议留出 5%-10% 的余量给模型的回复和临时的工具输出。depth: 2的意思是只加载直接引用文件和二级引用文件更深层依赖不加载。3.2 关键参数怎么定预算和压缩阈值很多人拿到配置会直接抄但参数必须根据你的任务特征调。我给出一个可复用的计算思路。第一步确定窗口大小。如果你用的是 128k 上下文那 max_tokens 填 128000。但如果你想兼容更低配置的模型就按实际值填。第二步按任务类型分配预算。改几个独立小文件的简单任务file 模式可以只给 25%做跨模块重构file 模式要提高到 45%-50%。第三步是压缩阈值。我建议当 session 模式和 file 模式的实际 token 占到总窗口 75% 时就要做一次压缩把 session 里的 completed 记录进行提炼而不是等到 95% 才动手。这里的核心逻辑是上下文压缩需要消耗模型的额外计算如果在窗口接近满载时压缩模型一边处理压缩一边还要继续原来的任务质量必然下降。提前压缩等于给模型留了喘息空间。3.3 把 context-mode 接到 AI 编程助手里配置文件只是静态规则真正要跑起来还需要一个很小的调度器。我在实际项目里是用 Python 写了一套 CLI负责三件事读取配置、组装用户的提示词前缀、在里程碑节点触发压缩。命令设计大致是这样的context-mode new --mode refactor --goal 拆分订单service层 context-mode add --file src/order/service.py context-mode add --file src/order/repository.py --depth 2 context-mode status --mode session context-mode checkpoint --message 完成第一轮重构 context-mode switch --mode debugnew命令会启动一个新的上下文按 switch_rules 加载 global 和 file 的内容。add命令用于把文件加入 file 模式内部会解析 import 关系自动带上depth层级的依赖文件。checkpoint命令触发压缩把当前 session 的 completed 记录做成决策日志然后清空部分原始对话。如果不想写调度器也可以直接在提示词里手动执行 context-mode其实就是把配置内容拼到系统提示词里再自己控制文件粘贴的顺序。效果会差一些但比完全不管理强得多。4. 实操过程从混乱到可控的一次完整对比4.1 挑一个真实任务当测试样本我用一个很典型的场景来说明给订单模块加 Redis 缓存。涉及的核心文件有 5 个分别是order_service.py、order_repository.py、models.py、db.py以及配置文件app.yaml。任务要求是查询订单详情时优先读缓存缓存穿透时回源数据库并回填缓存过期时间 300 秒同时要保证修改不影响其他服务调用的返回结构。这个任务如果不做 context-mode多数人的做法是直接把 5 个文件全贴进对话框再补一句“帮我加缓存”。这就是典型的无模式上下文表面上信息齐全实际上模型很难判断优先级往往会在无关的函数上花掉大量输出改出来的东西要么结构乱要么遗漏回填逻辑。4.2 用 context-mode 组装上下文清单按我的配置这个任务应该切到refactor模式。第一步是注入 global 内容包括项目技术栈说明和代码规范。第二步是写 session 目标我把上面那段任务描述做了一次精炼补充了几个关键约束缓存 key 用order:{id}序列化用 JSON异常时降级为直查数据库。第三步是 add 文件。order_service.py和order_repository.py是直接修改的文件必须加载全文。models.py是引用文件只加载与 Order 模型相关的部分。db.py只需要关注get_session和事务上下文。app.yaml只把 Redis 配置相关的段落剪出来。这样组装完的上下文大概是global 25k、session 15k、file 35k总计 75k占 128k 窗口的 58%留出了充分余量。组装完之后我只把这一段上下文发给模型然后追加一句标准指令“基于以上上下文完成缓存实现先输出修改计划确认后再写代码。”这一步很重要它给了模型一次重新审视上下文的窗口能提前发现配置是否有遗漏。4.3 实验对比同样的任务两种截然不同的结果我用相同模型分别跑了一次“无模式全量塞文件”和“context-mode 组装上下文”结果差异非常明显。无模式那组输入 token 大概 110k多塞了很多无关的映射和工具函数模型前两轮都在梳理关系第三轮才开始写代码而且写出来的方案把缓存逻辑直接塞进了query方法完全没有做隔离。用 context-mode 的一组输入 token 只有 75k模型第一轮就给出了清晰的修改计划实际代码改动只涉及 service 层repository 和 db 都没动整体改动量小了 60% 左右而且一次通过编译。这里要说清楚context-mode 不是玄学它的本质是提高上下文的信息密度。同样的窗口装的信息更有用模型的产出自然更稳定。这不是模型能力变强而是你把“题目的已知条件”整理得更清楚了。5. 常见问题与排查技巧实录5.1 上下文漂移模型改着改着就偏了现象是前 20 轮模型表现正常后面逐渐开始用错接口、忘记约束而且你明明在上下文里写了“不要动 db 层”它后半段还是碰了 db 层。这不是模型不听话而是早期的高价值信息被中段的大量过程性内容挤出了注意力窗口。排查方法很简单把当前会话的输入 token 统计导出来看 global 内容是否还在窗口内覆盖范围。如果 global 的 token 占比掉到了 5% 以下基本就是漂移了。解决办法是“模式锁定”把 global 里的硬约束重复一次放在每次提问的系统提示词里同时把会话模式里已经完成的无用对话清理掉。我在 CLI 里加了一个pin参数可以把 session 里的某几条规则固定在上下文末尾因为窗口末尾也是注意力密集区这样等于给关键约束开了双重保险。5.2 压缩摘要丢关键信息回滚时找不回来压缩模式最常见的坑是摘要写得太“综述风”一条决策变成了“讨论了性能优化方案决定采用缓存方案”。这种摘要等于没记回滚的时候完全不知道当初为什么选缓存、选的是 Redis 还是本地缓存、key 规则是什么。我的对策是强制决策日志的格式背景一句话候选方案列点选择结论带编号原因必须写明被否掉的方案哪里不满足需求。宁可摘要长一点也不能牺牲可回溯性。配置里的output_format: decision-log就是用来强制这个结构的。检查压缩质量有个笨但有效的方法只凭摘要能不能重新实现这个功能。如果答案是不能说明摘要不合格需要重新压缩。5.3 切换模式成本太高每次都像重开有人试了 context-mode 之后觉得太麻烦因为从全局切到调试模式时原来的一堆上下文被清掉模型需要重新“认识”代码前几轮效率反而更低。这个问题的本质是切换太粗暴。正确的做法不是清空重来而是做层级保留切模式时保留 global 和最近的决策日志只清空 session 和 file 里的具体过程内容。这样模型还记得项目的基线也知道历史上有哪些关键决策只是把当前任务的细节置空。我在配置里把这种切换叫做“warm switch”实现上就是switch命令默认只清 session 的completed和blockers保留goal和 global。实际操作下来切换后的第一轮就能维持 80% 左右的效率而不是从头开始。5.4 token 估算不准预算很快就超了很多人用字符数估 token结果严重低估。中文字符和 token 的换算关系和英文不一样代码里符号密集也和普通文本不同。预算超标的直接后果是模型输出被截断或者某些模式内容根本没进窗口。我的经验是分类型估算中文每 1 token 约等于 0.6-0.8 个汉字英文每 1 token 约等于 4 个字符代码每 1 token 约等于 3-3.5 个字符符号多。如果不想细算可以先用tiktoken这类库对配置文件里的每个 source 文件做一次准确的 token 测量把结果缓存下来。这样每次启动 context-mode 时读取的文件 token 数就是精确值只在遇到新文件时做粗略估算。这块建议做自动校验启动时统计各模式的 token如果超出预算就拒绝加载并报告超了多少。如果不能自动做就手动跑一遍context-mode status看到超预算就直接裁剪引用文件范围不要心存侥幸。6. 最后分享两个小习惯context-mode 这套东西我开始也只当做一个配置文件在用真正让它有价值的是两个看起来很不起眼的习惯。第一个习惯是每个 checkponit 都写“当前文件状态”。压缩前把改动过的文件路径、关键函数、最近一次修改意图记下来。这样即使上下文清得很干净下一次恢复时也能快速定位到正确的文件不用重新扫描整个项目。第二个习惯是给每种模式准备一套默认指令。global 模式下模型的任务是“理解背景不写代码”session 模式下是“执行目标更新进度”file 模式下是“阅读文件输出关系”slim 模式下是“压缩记录保留决策”。模式一旦定了指令也跟着切换模型就很清楚自己当前角色是什么。很多人的提示词写得没效果其实就是角色和模式混在一起模型不知道该以什么身份干活。我个人实际用的默认配置并不是一开始就定好的而是跑了几个任务之后根据漂移问题慢慢调出来的。如果你也想试建议先选一个真正让你头疼过的跨文件重构任务在无模式下跑一遍记录下问题再切到 context-mode 跑一遍。两轮对比下来你对上下文管理的理解会比读十篇文档都深刻。