
最开始用 AI 编程工具时我犯过一个很多人都会犯的错拼命把项目里的文件贴进对话里生怕模型没看过代码就乱给结论。结果聊到第 20 轮前面贴过的东西全被上下文窗口挤掉了模型又开始对着一个连我自己都快忘掉的旧接口提建议。后来我注意到身边同事的编辑器里有个叫 context-mode 的能力它做的是另一件事——不等你贴工具自己把当前项目的结构、关键文件、规则说明加载进来。这篇文章就聊聊这个模式到底是什么、底层在做什么、以及我在实际项目里配置和踩坑的经验。1. context-mode 到底在改什么从每次聊都要重讲一遍到它自己知道项目底细1.1 业界的通病AI 助手的失忆和反复解释的尴尬只要用过 AI 编程助手超过一星期你大概率体会过这种窒息感你在对话里跟它讲清了我们的用户表在auth.users状态字段叫status取值是 active、banned、pending它当时确实答得不错。但一旦换了新会话或者聊了几轮把前面的内容挤出了窗口它就又恢复成第一次见这个项目的白纸状态开始一本正经地告诉你建议在 user 表里新增一个 status 字段。这不是模型笨而是上下文管理的习惯问题。绝大多数 Coding Agent 产品是基于对话来工作的模型能看到的上下文就是当前会话里的历史消息、你主动贴进去的文件偶尔加上它自己调工具读回来的内容。一旦你不贴、它不读模型就只能靠猜。而猜出来的方案往往看着像模像样实际上连项目里最基本的技术栈都可能搞错比如给你的 Vue 项目提 React 方案。1.2 context-mode 能做什么、不做什么所谓 context-mode我理解成一套让工具在开始对话前就具备项目基本认知的机制。它一般做三件事自动感知当前项目是什么框架、入口文件、包管理方式、目录结构。按配置加载项目规则比如代码风格、模块划分习惯、禁用项、常用命令。把关键文件的路径和相关片段挂到本次会话的上下文中让模型不用翻找就知道该看哪里。它不做什么这事也值得说清楚它不会把整个仓库塞进模型视野也不负责记住你每一次对话的细节更不会自动理解你脑子里的业务逻辑。它解决的是开场信息太薄的问题剩下的事仍然要靠对话和工具调用来完成。1.3 一个容易被误解的点这不是CTRL C 整个项目贴进对话框很多人一听上下文模式第一反应是把整个项目文件复制进提示词——我见过有人真的这么干把一个中等仓库的源码全部粘进 Cursor 或者 Continue 的对话框里然后模型直接因为 Token 超限报错。context-mode 的机制完全不是这个思路它跟你手动贴文件看起来像实际差别很大手动贴是不分轻重全塞context-mode 是按规则挑选、按需加载、有优先级。后面我会细讲它是怎么挑的。2. 背后的大脑一次请求里到底发生了什么想用好 context-mode不能只把它当作一个开关得先理解它背后的三层结构。我把它们叫做窗口、索引、指令。2.1 上下文窗口的物理极限先说窗口。现在的编程大模型上下文窗口大多在 128K 到 200K 个 Token 之间听起来很大但换算一下一个普通的中型 TypeScript 项目光是node_modules里随便挑几个包的源文件就能轻松超过几十万 Token。更别说很多仓库还有dist、build、coverage这类生成物目录。窗口是稀缺资源它同时要装你正在编辑的文件、模型返回值、错误堆栈、历史对话能留给项目背景的空间其实是经过精心计算的。如果你把所有文件都塞进去模型并不会因此更聪明反而会因为注意力被大量无关代码稀释开始顾此失彼。这也是我后来不再迷信喂得越多越懂的原因——上下文不是硬盘它更像书桌堆满反而找不到想要的那支笔。2.2 索引与规则文件的分工索引解决的是项目里有哪些值得看的文件。绝大多数工具会用类似 ignore 规则的机制先扫一遍目录把node_modules、.git、dist、__pycache__之类的目录排除掉剩下的代码文件按扩展名和目录层级做成一个索引。规则文件解决的则是这个项目有什么约定俗成的东西。不同的工具有不同的文件名最主流的是仓库根目录下放一个没有扩展名的指令文件比如CLAUDE.md、CONTEXT.md、.cursorrules还有一些 IDE 插件用.continue/settings.json或.github/copilot-instructions.md。它们的本质都一样把项目级知识写进文件里让模型每次开始工作时先读一遍。2.3 一次请求的处理顺序当你开启 context-mode 后发起一次提问实际流程大致是工具先收集当前你在编辑的文件内容以及最近打开的几个文件路径。它读取项目根目录的规则文件把里面的指令解析成工作准则。它结合索引找出与当前文件关联度最高的几个文件比如引入它的模块、它引用的类型定义。这套组合内容被拼装成系统提示词或上下文前缀注入到模型请求里。模型基于这些信息再分析你的提问给出回答。换句话说context-mode 并不是一个什么黑魔法而是一套自动整理桌面的过程它决定什么内容该出现在书桌上、什么内容该留在一眼看不到的文件柜里。理解这一点你就能明白为什么配置规则比盲目开关更重要——规则决定了它往你的书桌上摆什么。3. 自己动手一套可以日常用的 context-mode 配置参考3.1 先从关闭自动全索引开始很多工具默认会做大范围扫描这在小项目上没问题但在 monorepo 或大型项目里会让索引特别慢甚至带着一堆不相关的包进入上下文。我的做法是第一件事就是显式设置排除项。以 Continue 这类支持 .continue 配置的插件为例排除规则一般长这样{ context: { exclude: [ node_modules, dist, build, coverage, vendor, .git ] } }如果是 Cursor 的.cursorignore或者 Claude Code 的settings.json排除逻辑大同小异。在配置完后我建议随手重开一次工具的索引很多工具并不会因为改了排除规则就立刻重新扫描不重启的话你会很困惑为什么明明排除了dist模型还是能翻到里面的旧代码3.2 规则文件要写成给新人看的项目说明而不是写作文规则文件是最容易被低估的部分。很多人一上来就写请始终使用 TypeScript尽量遵循最佳实践这种废话写了等于没写。真正有价值的规则文件应该像给刚入职的同事写 onboard 文档一样具体。我目前的模板大概是这样的以 CLAUDE.md 为例# 项目通用约定 - 本项目是前后端分离架构前端在 /web后端在 /server。 - 前端使用 Vue 3 TypeScript Pinia组件目录采用按页面划分。 - 后端使用 NestJS数据库访问统一走 Prisma禁止直接裸写 SQL。 - 所有对外接口统一挂在 /api 前缀下响应格式为 { code, data, message }。 - 环境变量集中在项目根目录的 .env.example新增配置必须同步更新示例文件。 - 脚本命令dev 启动本地服务test:unit 跑单测lint 检查代码风格。你注意看这里没有任何抽象的原则全是有人问这个项目怎么回事时你会脱口而出的东西。模型读到这些比读一百句遵循最佳实践有用得多。3.3 别忽略扩展名白名单索引的另一个重要参数是文件类型。大多数项目只需要让 AI 关注.ts、.js、.vue、.py、.go、.json这些源码和配置文件。但有些项目里会混进 Markdown 文档、Excel 导出的 CSV、图片 SVG 之类如果全部进索引上下文很快会被无关内容塞满还会导致模型在回答中引用到早已过期的说明文档。我一般会同时用排除目录和扩展名白名单两套机制。扩展名白名单看上去是个小细节但在大型仓库里的作用比想象中大它直接决定了模型看得到哪些世界。4. 实测对比同一个项目开和不开 context-mode 差别有多大4.1 我的测试场景为了不被感觉误导我专门做了一个对照实验。项目是一个中等体量的 NestJS 后端代码大概 3 万行里面有大量通过依赖注入的 Service模块划分比较清晰。我选了三个真实任务任务一解释某个 Controller 的整体链路。任务二给某个 Service 新增一个方法并接入现有模块。任务三定位一个间歇性 500 错误的可能原因。每个任务我都分别用关闭 context-mode只靠对话历史和开启 context-mode配合规则文件两种方式跑一遍模型用同一个避免模型差异带来的干扰。4.2 没开时的表现泛化、可用、但经常说不对地方关闭 context-mode 时模型的回答呈现出一种很有意思的状态它知道 NestJS 的标准写法给出的代码片段在语法上挑不出大问题但它经常猜错模块名称。比如任务三里它把数据库连接超时当作首要怀疑对象找了一通数据库配置问题而实际项目里那个 500 错误来自一个 Redis 缓存序列化的边界情况。如果不了解项目背景你很难把这归因到缓存层。任务一的表现更典型它从 Controller 开始讲一直讲到 Service 和 Repository脉络完全符合 NestJS 教科书的套路但提到的具体类名和实际项目完全不同。也就是说它回答的是一套看起来对的标准答案而不是这个项目的答案。4.3 开了之后上下文让它先找到正确的文件开启 context-mode 后明显的差异不是模型突然变聪明了而是它不再盲目猜。第一次提问时它自己列出了 CacheService 里那段序列化代码的路径并且直接告诉我这里 try 块吞掉了 JSON.parse 的异常默认值兜底导致脏数据被写回 Redis。这个结论在没有上下文的情况下要花好几轮对话才能逼近。更直观的差异体现在任务二。把新增 Service 方法接入模块时正确做法是改AppModule里的 providers 列表。没开 context-mode 的版本直接建议我把新方法写进 Controller因为它不知道这个项目里模块注册的约定开了之后它会在动手前先读一眼app.module.ts然后按现有注入风格补全代码。我把两类结果整理成一个表格方便对比对比项关闭 context-mode开启 context-mode回答与项目实际结构的匹配度低靠通用套路高能定位具体文件定位真实 bug 的效率需要多轮追问首轮就能命中代码风格一致性不稳定时好时坏稳定贴合现有风格Token 消耗起初较低但多轮追问后反超起始略高但一轮内解决更多问题坦率讲这个结果不意外。context-mode 本质上是把你需要的项目背景前置了哪怕它占了一些请求 Token它也帮你省掉了纠正错误假设的大量后置消耗。5. 三个我踩过的坑以及对应的处理方式5.1 坑一规则文件越写越长Token 悄悄膨胀刚开始用的时候我把规则文件当成百科全书写光是项目背景就写了两千字包括每个模块的历史变迁、技术选型原因、废弃代码解释。结果模型每次都要读这两千字一些简单的提问也变慢Token 成本肉眼可见地涨。后来我做了分类整理长期稳定的约定留在规则文件里会频繁变化的信息比如某个接口当前由谁负责移出规则文件放到需要时再手动提供的对话内容里。规则文件的最佳状态是三个月不用改一次如果它经常变说明你把不该放进来的信息写进来了。5.2 坑二多个工具的规则互相打架我同时用 Continue 和 Cursor两边都有各自的规则文件。最尴尬的一次是我在 Continue 里写了统一使用双引号而 Cursor 的.cursorrules里保留了某次实验用的统一使用单引号。两边同时开着做同一个仓库时模型给出的代码风格就随工具“精神分裂”。后来我规定仓库只维护一份主题规则文件其他工具都通过 include/import 机制引用它禁止各自维护独立规则。如果你团队里也有人用不同工具这点一定要提前定好不然你会发现每个人生成的代码风格都不一样review 起来火气很大。5.3 坑三索引没有刷新回答停在昨天context-mode 依赖索引但索引不是每次都无感更新的。最常见的情况是你新增了一个目录改了一个核心模块名但工具索引里还是旧的于是模型引用了一个早已不存在的路径。我都是靠重启 IDE 或者手动触发重新索引来解决但更省心的是养成习惯——结构大调整之后别急着让 AI 干活先确认索引状态。这跟重构后先等 TypeScript 编译通过再往后走是一个道理。6. 什么时候开、什么时候关我的选型经验6.1 适合常开的项目我在三类项目上会常开 context-mode大型 monorepo模块多、层级深不开的话模型找不到路。刚接手的历史项目代码风格奇异、约定散落在各个角落上下文规则能帮你迅速对齐。团队协作密集的项目规则文件本身就是团队知识的沉淀新人加入后可以让 AI 变成半个向导。6.2 适合按需开的项目小型脚本、一次性工具、还没定型的原型项目我反而建议关掉。这类项目的代码量少规则文件也还没建立开 context-mode 除了增加 Token 消耗和请求延迟并没有太多收益。等原型稳定下来、目录结构清晰了再打开也不迟。6.3 最容易被忽略的一条做代码评审时别开如果你用 AI 做 Code Reviewcontext-mode 可能会帮倒忙。因为它会自动加载规则文件和项目约定模型会倾向于认为仓库里现状都是合理的从而降低对历史包袱的敏感度。比如某个文件里有明显违背常规的写法但项目里到处都是这种写法模型可能会默认这是团队的风格而放过去。我实际把 context-mode 关掉做 review 时模型反而更容易指出这个模块过度耦合这类结构性问题。6.4 和团队协作时的落地建议如果你们团队决定推广 context-mode我强烈建议把规则文件纳入版本管理跟代码一起提交和 review。规则文件变更不应该靠某个人的当地配置完成它应该像README和.gitignore一样是仓库的一部分。这样新成员 clone 下来自动就有上下文认知老成员的本地配置漂移问题也能收敛。7. 最后分享一个让我效率提升不少的小习惯我现在每次新建项目第一步不是写代码而是花十分钟写一份极简的 CLAUDE.md内容包括项目定位于什么、技术栈是什么、常用命令是什么、目录约定是什么。等项目长大之后这份文件再同步演进。这整个过程跟 context-mode 有没有关系关系很大——因为工具只是加载器真正决定模型能看到什么的是这份文件写得够不够清晰。尝试多用几次你会慢慢找到你自己项目里那句最该写进规则文件的话等你找到之后AI 给你的回答会明显上一个大台阶。