我最近在一个老项目里做登录模块重构,AI助手帮我改了五轮,我回滚了三次。不是它写不出代码,而是每一轮都和上一轮的要求打架:第二轮改了接口签名,第三轮把错误码映射表整体替换,第四轮又把我明确说过“不能动兼容层”的约束彻底忘了。最气人的是,对话框往上翻十屏,白纸黑字写在那里。后来我把这套问题彻底梳理了一遍,发现所有失败的共同点都指向同一个词:context-mode。
Context Mode,直译是“上下文模式”。在开发圈里这个词越来越高频,但很多人理解得过于简单,以为它就是“AI能不能记住我说过的话”。我今天想把它当做一个工程问题来聊:上下文不是聊天记录,而是模型在生成代码那一刻“看得到的全部信息”。谁能主动管理这部分信息,谁就能真正掌控AI辅助开发的输出质量。这篇内容适合所有被AI工具折腾过的开发者,不管你是用IDE内联补全,还是命令行里的Agent式对话,思路都通用。
1. 同一个需求反复改错:问题出在“遗忘”,根源却在上下文管理
1.1 一个五轮对话翻车三次的真实案例
先复盘一下我那个登录模块。项目背景是这样的:这是一个维护了三年的老系统,登录接口经历过多次迭代,对外承诺了“旧客户端依然可用”。所以我对AI助手提的需求第一条就是:保持现有API签名不变,错误码体系不动,只增加一个新的防暴力破解逻辑。第一轮对话,AI规规矩矩加了限流;第二轮我让它补充验证码逻辑,它顺手把login(String, String)改成了login(LoginRequest);第三轮我发现错误码表被整个替换成了新的枚举;第四轮我忍着性子重新贴了一遍需求,结果它基于“已经改过的接口”继续演进,越走越远。
这个场景你肯定不陌生。很多人第一反应是“AI理解能力不行”,但我后来想明白了:它不是在理解层面出错,而是上下文层面的遗忘。那几轮对话里塞满了我的新要求、它的简要解释、各种报错信息、代码片段,而我最早强调的“兼容性约束”被挤到了对话流深处。对AI而言,对话历史越长,早期信息被后续内容稀释得越厉害,这是机制决定的,不是你多骂几句就能解决的。
1.2 为什么说上下文不是“无限备忘录”
我打个比方。上下文窗口就像一块白板,白板面积有限,你每次添加新内容,都可能要擦掉一些旧内容腾地方。早期的内容如果一直不被引用,很快就会被新的内容顶掉。很多AI工具为了控制成本和时间,在实现上还会主动对早期对话做摘要压缩,一压缩,细节就丢了。这时候你翻聊天记录,文字明明还在,但对模型来说,那一段已经退出了它的“可视区”。
这一点理解透了,很多现象都能解释。为什么一个任务从早聊到晚,越到后面输出越歪?为什么新开一个对话,同样贴一遍需求,效果反而更好?不是玄学,是新对话直接等于一块干净白板,你的核心约束才有机会被完整写上去。
1.3 我理解的Context Mode:可见、可控、可维护
经过几次翻车,我把context-mode重新定义为三个词:可见、可控、可维护。
- 可见:你得知道此刻AI能看见哪些信息,哪些看不见。看不见的,它绝不会主动去猜。
- 可控:你能决定把什么内容放进上下文,而不是被动让对话历史决定一切。
- 可维护:上下文里的关键信息可以持续更新,而不是每次开新会话就全部归零。
这三个词是我后面所有方法的地基。后面的章节,全部是在解释如何把这三个词落到实际操作上。
2. 上下文拆成三层看:会话、文件、项目,各管各的
2.1 会话级上下文:让每一轮对话都“独立可交付”
会话级上下文,指的就是当前这场对话里的历史内容。很多人的习惯是:一个需求开一个对话,然后一直在里面聊,直到彻底完成。这个思路在简单任务里没问题,但在复杂重构里很容易翻车。
我的做法是把长任务拆成多个短会话。每个短会话只负责一件事,比如“生成新增接口的骨架”“补充参数校验”“写单元测试”。关键点在于,每一个新会话的开头,我都要求AI先复述一遍它对我需求的理解,确认无误后才让它动手。这个“复述动作”非常管用,等于强制要求AI把最重要的约束放到它上下文的最前端,而不是让它自己去历史的海洋里打捞。
另外一个实用技巧是:不要在一个会话里同时给多个高优先级约束。你有十条要求,AI大概率只记得开头两条和结尾两条。与其让它捡芝麻,不如把十条要求拆成三个会话,每个会话只负责其中两三条。质量提升非常明显。
2.2 文件级上下文:精确控制“AI此刻能看到的代码”
文件级上下文,是IDE内联AI和命令行Agent之间的核心差异之一。IDE类工具默认会把当前打开的文件塞进上下文,有时还会附带光标附近的代码片段;命令行工具通常需要你主动指定路径,或者通过交互方式选择文件。
这里有个常见误区:很多人误以为“AI自动能读到整个项目”。其实不会,因为整个项目的代码量远超上下文容量,工具只能挑一部分喂进去。你如果不主动管理,它挑的未必是你想要的。
所以我的习惯是:在发起任务前,先想清楚“解决这个问题,AI最少需要看哪几个文件”。比如改登录模块,那核心就是LoginService.java、LoginController.java和ErrorCodes.java这三个。我会明确告诉AI:“只参考这些文件,不要碰其他文件。”这既控制了上下文体积,也防止它自己开脑洞去引用老版本模块。对于IDE内联工具,我会把这些关键文件全部打开并保持可见;对于命令行工具,我会把文件路径显式写在指令里。
2.3 项目级上下文:让AI真正“懂”你的工程
项目级上下文,是很多人完全忽略的一块。它指的是那些“不在你当前打开的代码里,但决定了代码该怎么写”的信息:项目技术栈、目录结构、编码规范、第三方库版本偏好、历史决策原因。
举个最简单例子。你让AI写一个HTTP请求的工具类,如果它不知道你们项目里已经统一用OkHttp而不是HttpClient,它大概率会写出另一套实现,看起来能用,实际却和现有代码风格冲突。解决这个问题的唯一办法,就是给AI提供项目级上下文。
我维护一个项目级上下文文件,里面就三类内容:
- 一句话项目简介和技术栈清单。
- 目录结构说明:哪个目录放接口、哪个放实现、哪个放工具类。
- 编码约束:禁用哪些写法、必须沿用哪些内部库。
每次开始大任务前,我先把这份文件贴给AI,再进入具体任务的对话。成本极低,但收益非常大。它相当于给AI一份“合作交接文档”,而不是让AI每次都靠猜。
3. 长期可用的项目上下文库:从“临时粘贴”升级成“资产沉淀”
3.1 三层抽屉模型:必读、查读、忽略
接触项目级上下文之后,我开始琢磨:能不能把零散的粘贴行为,变成一套稳定的管理机制。后来我梳理出一套“三层抽屉”模型,实战下来很好用。
必读区:所有任务开始前都必须让AI知道的全局约束。比如“后端必须用Java 17”“禁止引入新依赖”“错误码必须走ErrorCodes枚举”。这个区域的信息量要尽量少,一般控制在50行以内。为什么?因为AI是注意力机制驱动,内容越长,关键信息越容易被稀释,你写两千字规则,它真正执行的不过前几条。与其堆量,不如把最不可妥协的几条反复强调。
查读区:某些特定任务才需要的信息,比如“第三方支付回调的验签流程”。这类信息不常被用到,但如果用到而AI不知道,产出质量会明显下降。查读区的内容交给需求决定:做支付任务就贴支付说明,做登录任务就贴认证说明。
忽略区:这个区域不是给你看的,而是用来抑制AI乱翻历史的。我会在上下文里明确写“本项目的旧版代码位于/legacy目录,仅用于参考,禁止复制其实现”。文字虽然不多,但能有效防止AI在某些模型偏好下复制旧架构。
3.2 规则文件维护时的几个硬性指标
经过多次迭代,我总结出几个写规则文件的硬性指标,供你参考:
- 核心规则不超过50行。超过之后,AI对末尾内容的关注度会显著下降。
- 每条规则独立成行,不要用长篇大论解释背景。AI不需要理解你的苦衷,它只需要知道该做什么。
- 规则文件里只写索引,不写细节。比如“支付模块说明见docs/context/payment.md”,而不是把支付模块几千字全塞进主规则里。
- 负面规则比正面规则更重要。告诉AI“不能用什么”比“建议用什么”效果更稳定,因为AI对禁止项的遵守率通常比对建议项的遵守率高。
3.3 长文档压缩成“可检索索引”的具体做法
项目里那些动辄几千字的架构文档、接口规范,不可能全塞进上下文,也没必要。我的做法是给它们建立索引卡片。每张卡片包括三部分:
- 文档标题和路径。
- 一句话内容摘要:这篇文档解决什么问题。
- 关键入口点:如果AI需要了解详情,从哪里开始看。
举个例子:
支付回调文档:docs/context/payment-callback.md 摘要:解释异步回调的验签流程,包含无序重放防护策略。 关键内容:服务端使用商户私钥验签,回调地址只接受HTTPS。实际使用时,如果任务涉及支付,我会把索引卡片贴上去,再附上文档正文里和本次任务相关的三个关键段落。这样既保证了AI拿到足够的细节,又不会让整个文档淹没上下文。
4. 不同工具里Context Mode的落地差异:从“隐式”到“显式”
4.1 三类主流工具的上下文机制对照
我做了一个对照表,方便你直观对比不同场景下该用什么策略。
| 工具类型 | 典型产品形态 | 上下文获取方式 | 可控性 | 踩坑点 |
|---|---|---|---|---|
| 图形IDE内联工具 | 代码编辑器内的AI补全/问答 | 自动读取当前文件、选区、最近编辑 | 低(偏隐式) | 常引用无关文件,但用户难以干预 |
| 命令行Agent式工具 | 终端里的对话式AI | 显式指定文件路径、规则文件、交互选择 | 高(偏显式) | 需要人为规划上下文,上手成本略高 |
| 网页/API对话工具 | 纯聊天界面 | 完全依赖用户每次手动粘贴 | 中 | 上下文随粘贴内容波动大,容易前后不一致 |
我实测下来的体感是:IDE内联工具最“顺手”,但最不可控;命令行对你做“上下文管理”的要求最高,可一旦建立了合适的规则文件,长期稳定性反而最好。两者没有绝对优劣,关键看你愿不愿意投入初期规划成本。
4.2 同一任务跨工具切换时,如何交接上下文
很多人不止用一个工具。白天在IDE里写代码用内联AI,晚上用命令行Agent批量重构,或者先让网页版对话工具梳理思路,再去IDE里落地。这里最大的坑是:上下文不会自动跟着你走。
前一轮AI帮你梳理出的结论、你确认过的关键决策,在换工具时全部作废。我的经验是:切换工具前,花两分钟产出一份“会话交接卡”。交接卡里写三件事:任务背景一句话、已完成哪些步骤、下一步要做的事和关键约束。切换到新工具新会话时,把整张交接卡贴过去,让AI先确认,再继续。
你可能觉得这很麻烦。但实测下来,这两分钟能省下后面至少二十分钟的纠错时间。和同事协作还要对齐信息呢,何况是和一个没有记忆的工具。
4.3 上下文成本的现实考量:token、速度和质量的三角权衡
上下文管理不只是质量问题,还涉及成本。上下文越长,单次请求消耗越大、响应越慢。有些时候,你为了给足上下文塞进去大量文档,结果输出质量反而因为噪音而下降,同时运行时间翻倍,得不偿失。
我的原则是:上下文的长度应以“刚好覆盖任务边界”为准,而不是越全越好。一个任务的边界是什么?就是“AI为了正确输出而必须知道的信息的并集”。多一行规则文件说明,如果和本次任务无关,那就是纯噪声;多贴一个无关文件,那就可能在输出中引入“参考依据”。每一次往上下文里添加内容前,都问一句:这次任务真的需要它吗?不需要,就别贴。这个习惯养成了,你的AI输出质量和稳定性都会有质的飞跃。
5. 上下文失控的三个信号,以及我的紧急预案
5.1 信号一:答案开始“串文件”,引用了完全无关的老代码
有一次我让AI修改一个订单查询接口,它写出来的实现里却用了库存模块的仓储接口。我一看,它是在上下文里扫描文件时,把库存模块的某段代码当成了“参考示例”。这种“串文件”是上下文失控的典型信号,说明你给它的视野太大了,或者规则文件里没有写明边界。
遇到这种情况,先把视野缩小。明确告诉AI:“本次任务禁止查看和引用市场模块、库存模块的任何文件。”然后要求它重写。如果它仍然串,就开新会话,只把相关文件放进去。
5.2 信号二:同样要求重复描述两次,输出依旧跑偏
这是沟通层级的失守。很多时候我们对AI说话像对同事说话,默认它“应该理解我的意思”。但对模型而言,一句模糊的话意味着无数种可执行的落法。如果你发现重复提醒两次它还是不改,那大概率不是它没看,而是它手里的信息里就没有明确的“正确路径”。
这时候我的做法是:不继续在原会话里耗,直接开新会话,把需求完整重写一遍,并且用“验收测试”倒逼。比如明确写上:“改完后,运行以下三个测试用例,如果报错,说明你没有满足需求。”把验收标准放进上下文,比反复用自然语言抱怨有效得多。
5.3 信号三:关键约束被当耳旁风,代码里完全没体现
最让人崩溃的情况是:你说了“不要改旧错误码”,AI还是给你换了一套新错误码。问题就在于,这句关键约束只存在于会话早期某一句话里,后面大量代码内容早就把它冲掉了。靠对话维持约束是最脆弱的方式。
所以我有个很坚定的原则:重要约束要离开对话,进入代码本身。具体做法有三种:
- 在代码注释里写清楚约束,让AI扫描文件时自然读到。
- 在规则文件里单独列一条“禁止项”,每个新会话开头强制读取。
- 在Git提交信息里记录决策原因,必要时让AI查看git历史。
上面三种都属于“持久化上下文”,它们不依赖某一次对话,而是长在项目的血脉里。经历过几次翻车之后,你会明白,把上下文从“一次性聊天”升级成“持久化资产”,是质量稳定性的分水岭。
5.4 紧急预案:清空、重建、验证三步走
如果你的AI已经开始胡言乱语,上下文严重污染,最优的路径不是修复,而是重建。我给自己定了三步流程。
第一步,清空:果断结束当前会话,别心疼那堆聊天记录。你与其花时间指正一个上下文混乱的AI,不如新开一个环境。
第二步,重建:把规则文件里“必读区”的内容贴进去,再贴项目索引卡片,然后附上本次任务的描述和验收标准。让AI先用三句话概括它理解的任务,我确认后,它再动手。
第三步,验证:由AI输出一份“变更检查单”,列出所有它准备修改的文件和理由。这份检查单在动手前就必须出现。如果检查单里出现不该碰的文件,直接砍掉再让它继续。
这套流程我目前已经用了整整几个月,翻车率大幅下降。每次想偷懒跳过第二步时,我都会想起那个改了五次接口签名的登录模块。
最后再分享一点个人体会。Context Mode在工具层面千差万别,但底层逻辑始终是同一个:上下文不是鞋子里的一粒沙,而是你递给合作者的一份交接文档。你平时怎么给新同事交底一个老项目,就应该怎么给AI交底。把最重要的约束讲清楚、把无关信息收起来、把长期规范沉淀成文件,它输出的代码质量,基本就能稳定在你想要的高度上。如果你也在用AI辅助写代码,建议下次开工前,先花两分钟思考:眼前这个任务,AI真正需要的上下文到底有几条?