前阵子处理一个历史仓库差点被AI把调用关系改崩。排了半天才发现问题不在模型能力也不在提示词写得差而是我压根没给AI一个明确的上下文切换机制。今天想聊的就是这件事我自己整理的一套 context-mode。简单讲context-mode 不是某个具体工具的隐藏参数而是我在日常AI协作里维护的一套上下文管理模式。它把项目信息、角色设定、行为约束、输出格式打包成若干张“模式卡”在不同任务之间显式切换而不是让上一轮的对话残留一路带到下一轮。这篇东西适合那些经常用AI写代码、改代码、做代码审查又总抱怨“它怎么又忘了”“它怎么管这么宽”的人。读完你基本可以照着搭一套自己的。1. 一个差点翻车的重构让我决定管好上下文1.1 翻车现场的还原那个仓库是一个内部工具库scripts/目录下散落了三十多个Python脚本很多脚本之间通过sys.path互相 import还有几个被 CI 定时任务直接调用。我当时的想法很简单让AI帮我把这些脚本整理到src/tools/下面保持所有行为不变。我打开AI工具直接说了一句“帮我把 scripts 整理到 src/tools”。模型很积极立刻开始写迁移方案。问题就出在这里——它没有问我要保持哪些调用关系也不清楚哪些脚本会被外部入口依赖就按自己的“合理猜测”设计了一版新目录。它还把几个脚本里的公共函数签名改掉了理由是“更规范”。结果一跑测试三处 import 直接崩。从表面看这是AI“自作主张”的问题。但站在使用者的角度复盘根子在我我把它丢进了一个上下文不清不楚的场景。它既不知道自己是只读审计还是动手重构也不知道哪些文件是可以碰的更不知道输出应该先给计划还是直接给 diff。这种情况下模型只能从历史消息里猜猜错就是必然。1.2 context-mode 的核心理念从那以后我把所有AI协作任务按“上下文边界”重新做了切分这就是 context-mode 的来源。你可以把它理解成操作系统的运行模式内核态能做底层操作用户态受限执行不同模式拥有不同的权限和可见资源。AI协作也一样每个任务应该有一张明确的模式卡。一张模式卡至少回答四个问题当前角色是什么是资深工程师、代码审查员还是教学陪练。能看到哪些文件是只读某个目录还是允许修改全仓库。绝对不能做什么比如禁止改接口签名、禁止加依赖、禁止动无关代码。输出应该长什么样先给影响清单、再给 diff还是只解释思路不给代码。后来我在多个项目里反复验证这套东西比任何“角色扮演提示词”都稳定。因为角色扮演只是改变语气模式卡直接改变了模型的信息输入范围和输出约束它是一种结构性约束不是修辞。1.3 适用场景别只看代码context-mode 最适用的当然是AI辅助编程但它的思路完全可以迁移到别处。多项目并行你电脑里同时跑着后端服务、数据脚本、前端小工具每个项目的依赖和规范都不同。多角色切换早上写业务代码下午做代码审查晚上还要给新人讲架构。三种任务对AI的要求完全不一样。长会话维护一个会话从早上聊到晚上早期内容早被挤到窗口外面AI却仍然按旧目标干活。教学解释让AI讲清楚一段代码和让AI直接改这段代码需要的上下文完全不同前者不希望出现“我帮你改了”后者不应该输出长篇原理。我一直强调一个观点不要把AI当聊天对象把它当有临时工作台的操作员。context-mode 就是在每次任务开始前明确告诉它“这次你只需要在这张台子上工作”。2. context-mode 的核心设计分层、打包、切换2.1 五层上下文模型在搭 context-mode 之前我先把“上下文”这个概念拆成了五个层级。明确层级之后才知道模式卡应该管哪一层、项目规则文件应该放哪一层、临时指令又应该放在哪一层。层级内容生命周期典型示例系统级通用角色、价值观、回答风格整个对话“你是一位严谨的Python工程师”项目级仓库结构、命名规范、技术栈整个项目周期“本项目使用src布局测试放在tests”模式级当前任务的边界、禁忌、输出格式当前任务“本次只做只读审计不改任何文件”会话级本次对话的具体目标、临时变量单个会话“本次要梳理scripts到src的迁移顺序”消息级单条指令的补充信息单轮对话“先只看utils.py其他文件先不读”之前我所有上下文都混在同一段提示词里模型需要自己判断哪些信息是这次任务该激活的。结果就是系统级和项目级还能记住模式级经常被后面的对话覆盖会话级和消息级又经常互相冲突。2.2 模式卡的基本结构模式卡是 mode-level 上下文的载体。我用的最小结构是 YAML因为可读性好也能方便被脚本处理。下面是一张实际在用的重构模式卡id: refactor name: 重构模式 description: 用于小范围重构保持外部行为完全不变 role: 高级Python工程师 scopes: - src/**/*.py - tests/**/*.py forbidden: - 修改公开函数签名 - 新增第三方依赖 - 重排无关的import - 改动注释风格 format: - 先输出本次改动的文件列表和影响范围 - 再输出 diff - 最后输出测试建议 budget: summary这里有三个关键点值得展开。第一scopes一定要用具体目录不要写“整个仓库”。AI是严格按照字面路径理解范围的你把全仓库暴露给它它就会在全仓库里“找活干”。第二forbidden比“希望你保持接口稳定”这种正向描述有效得多。正向描述是一种意图负向描述是一种校验规则。模型对“不要改签名”的执行率远远高于“尽量保持兼容”。第三budget字段表示这次上下文预算策略。full是注入完整文件summary是只注入摘要retrieval是按需检索。预算字段控制的是“把多少资料塞进模式卡”防止模式卡本身成为新的负担。2.3 三种上下文预算策略有了模式卡紧接的问题是文件那么多全塞给AI吗当然不行即使窗口能装下信噪比也会降低。我一般按三种策略分配。第一种是完整注入。只适用于核心小文件比如单个脚本、一个类文件。完整注入的好处是模型看到的和真实情况完全一致不会出现“它以为函数长这样”的幻觉。第二种是摘要注入。适合大文件或整目录。做法是让AI先读一遍生成结构化摘要摘要里保留函数签名、关键常量、对外接口然后拿摘要作为后续工作的上下文。这个策略省token但有失真风险摘要里漏掉的细节模型会自己脑补。第三种是按需检索。模式卡只告诉AI“相关信息在 docs/ARCHITECTURE.md 和 src/utils.py 里按需打开”然后在具体执行时让AI自己判断需不需要读。这个策略需要模型具备较高的工具调用自觉性碰上强模型很好用碰上弱模型容易偷懒。选择策略的标准就一条改动的风险越高越要靠近完整注入改动越外围越可以用摘要或按需检索。比如纯排版调整用摘要就够了但改核心服务接口就必须完整注入。3. 从零落地一套 context-mode目录、命令与模板3.1 存储结构与命令脚本我建议把模式卡放在~/.context-modes/目录里按项目分子目录。整体结构如下~/.context-modes/ global.yaml legacy-tool/ audit.yaml refactor.yaml webapp/ review.yaml debug.yamlglobal.yaml放所有项目通用的约束比如“禁止编造不存在的API”“不确定的时候先提问”。各项目目录下放针对具体仓库的模式卡。然后写一个简单的命令行脚本我仍然叫它context-mode。不用太复杂把模式卡列出、查看、复制到剪贴板就够了。#!/usr/bin/env bash # context-mode查看和切换模式卡 set -euo pipefail MODE_DIR$HOME/.context-modes ACTION${1:-list} MODE${2:-} case $ACTION in list) find $MODE_DIR -name *.yaml | sed s|$MODE_DIR/|| | sed s/\.yaml$// ;; show) cat $MODE_DIR/$MODE.yaml ;; use) if [ -z $MODE ]; then echo usage: context-mode use mode 2 exit 1 fi echo 当前模式: $MODE cat $MODE_DIR/$MODE.yaml ;; *) echo unknown action: $ACTION 2 exit 2 ;; esaccm use refactor会把模式卡内容直接打印到终端然后我把它粘贴到AI会话的开头。可能有人觉得手动粘贴多此一举但实测下来粘贴这个动作会强迫我确认一次当前任务边界比直接对着聊天窗口打字更清醒。3.2 在会话里注入模式卡的正确姿势模式卡不是贴一次就完事。长对话里上下文会持续滚动模型对模式的“记忆强度”会越来越弱。我的做法是给模式做一个“会话锚点”。具体格式是这样[当前模式] refactor [会话目标] 将 scripts 目录下的工具脚本迁移到 src/tools保持所有调用关系不变 [会话锚点] 已经确认的调用关系见上方审计结果本次不允许再调整公共函数签名锚点本身是一段短文本放在每轮提问前面。尤其当我连续追问很多细节时锚点能让模型重新聚焦到当前模式。主动发锚点还有一个好处就是让你自己形成习惯每次输入前先想清楚这次是在哪个会话状态下。很多AI工具支持自定义指令或者项目规则文件比如把项目级信息放进去。我的经验是项目规则文件放系统级和项目级上下文模式卡对应的 mode-level 信息还是放在会话开头最靠谱因为模式切换的频次远高于项目规则变更。3.3 真实案例一次归档重构的完整走查回到最初那个差点翻车的仓库我用 context-mode 重新走了一遍。第一步建立legacy-tool/audit.yamlid: audit name: 只读审计 description: 摸清调用关系不修改任何文件 role: 代码考古学家 scopes: - scripts/**/*.py - src/**/*.py forbidden: - 不要给出重构后的具体代码 - 不要假设未验证的调用关系 - 不要修改任何文件 format: - 输出脚本之间的调用关系表 - 输出被外部入口依赖的高风险点 - 输出建议迁移顺序然后我把 audit.yaml 内容发给AI附上仓库目录树。它花了很少的 token 就产出了一份调用关系清单列出了 5 个被 CI 直接调用的脚本、12 个彼此 import 的脚本对以及 3 处循环 import 的高风险点。第二步AI产出审计结果后我切换到 refactor.yaml并且把审计结果作为会话锚点附在后面。refactor.yaml 里明确禁止修改函数签名这样模型在看代码时就不会再自作主张“规范化”接口。这次的迁移很顺利最重要的一行指令其实是我在切换时发的锚点“本次只允许移动文件和调整 import 路径任何函数签名改动都必须先单独提出来确认。”3.4 模式卡模板速查为了方便你直接抄我把日常常用的几类模式整理成一张模板速查表模式角色设定scopes 举例forbidden 要点输出格式audit代码考古学家全仓但只读禁止给重构代码影响清单、风险点refactor高级工程师src 与 tests禁止改签名、加依赖diff 测试建议review审查员本次 MR 涉及文件禁止直接改代码问题列表 严重级别debug排查工程师相关模块禁止大面积重写原因推断 验证步骤explain讲解老师用户指定文件禁止贴大段代码生活类比 关键行解释4. 常见问题与排查技巧实录4.1 模式串味上一轮的任务污染了新一轮对话症状是切换模式后AI仍沿用上一个目标来理解当前问题。比如刚从 audit 切到 refactor我让它“移动文件”它却还是在分析调用关系甚至输出了一堆“建议”。原因几乎总是旧上下文残留。很多AI工具不会因为你在对话里粘贴了一条新模式卡就清空历史消息前面的内容仍然占着上下文窗口权重还不低。解决办法很简单切换模式前先重开一个会话再粘贴模式卡。千万不要图省事在同一会话里切换模式。如果没法重开会话至少先发一句“忽略之前所有与本次重构无关的目标”但说实话效果不如重开会话。我在这一点上吃过好几次亏现在已经当成铁律模式切换 会话重建。4.2 模式卡本身太长把上下文预算吃光了模式卡写得越长AI越容易忽略中间的部分而且长上下文会压缩真正代码的占比。我的经验是每张模式卡控制在 30 行以内。超过 30 行就要考虑是不是这个模式覆盖了太多职责。解决办法是把一个“大杂烩模式”拆成“审计”“重构”“验证”三个阶段模式而不是让一个全能模式干完所有事。如果模式卡里确实需要放一份很重要的架构说明不要把完整说明写进模式卡写一行“完整架构说明见 docs/ARCHITECTURE.md按需阅读”就够了。4.3 摘要失真导致的代码幻觉使用 summary 预算策略时AI经常会基于一份不完整的摘要开始改代码改出来的内容是它“觉得应该有”而不是仓库里“实际存在”的。这种问题排查起来特别费劲因为表面上AI回得有理有据。我后来强制自己加一条校验规则凡是对核心文件的改动模式卡里必须写明“先引用当前文件关键代码再开始改动”。让模型先把要改的函数原文贴出来相当于要求它展示证据。它引用不出来自己就会意识到还没读文件。4.4 多项目并行时模式卡互相污染同时维护五六个项目时很容易把 webapp 的规范粘到 legacy-tool 里。我在目录命名上加了项目前缀并且每次cm use时命令脚本会打印当前模式和对应的项目路径。这样做表面上是多打几个字实际上可以避免“把A项目的规范用到了B项目”这种低级错误。检查顺序我通常是这样先cm list看全局有哪些模式再回忆当前会话所属项目最后才cm use。看起来麻烦但稳定执行两周后就会形成肌肉记忆。4.5 排查速查表现象可能原因处理方式AI仍按旧任务处理新问题同一会话切换模式重开会话再注入模式卡关键代码被“规范”改坏scopes 太宽 / forbidden 没写签名约束收窄 scopes加 forbidden输出完全跑题会话锚点缺失在问题前补充模式锚点摘要和实际代码不一致summary 策略导致失真切到 full要求先引用原文模式卡被忽略模式卡太长压缩到30行内拆模式5. 一些补充以及我自己的使用习惯5.1 负向约束永远比正向期望好用这是我在 context-mode 里收获最大的一点。同样一句话“保持和谐”不如“禁止动其他文件”执行得彻底。原因在于负向约束是可以被逐字校验的模型在生成前能快速比对是否触犯。我自己写模式卡时会专门留出三分之一的篇幅写“不要做什么”。举个例子重构模式里写“不要修改函数签名”AI在执行时看到新函数签名会立刻意识到冲突而“注意兼容性”这种话它往往一带而过。5.2 别把所有事情都塞给 context-mode也有不适合用这套机制的场景。比如只问一个API用法或者让AI帮我把一段文案改得更通顺这种一次性任务加模式卡反而累赘。context-mode 适合的是“有稳定边界、可以重复执行、风险偏高”的任务纯闲聊和一句话需求不需要。还有一个心态建议模式卡不是写得越详细越好。它应该是你和AI之间的一份“任务委托书”而不是一本操作手册。写得太细说明你自己还没想清楚边界。5.3 我的最终使用习惯现在我的日常流程已经固定成四步进入任务前先判断风险等级中低风险直接干活中高风险一律套模式卡写模式卡时先列禁止项再列输出格式切换模式一律重开会话关键任务在每轮提问前发一条会话锚点。跑了两个月最大的变化不是AI的输出质量提升了多少而是我自己的思维被训练出来了。每次准备给AI发指令我都会先问自己当前的上下文边界是什么哪些变量在这个任务里是稳定的哪些是绝对不能碰的如果以后有人问我为什么愿意多花几分钟维护这个叫 context-mode 的目录我的回答是它逼着我在每个任务开始前先把自己脑子里的上下文也理清楚。