第一次意识到 context-mode 这个概念是在调试一个多商户系统的时候。页面里嵌了好几层 iframe我在控制台里怎么都拿不到内层页面的变量报错信息永远是一句冷冰冰的ReferenceError: xxx is not defined。折腾了半天才发现 DevTools 左上角有个不起眼的下拉框默认显示top切到对应的 iframe 之后所有变量瞬间就都能访问了。那个下拉框就是今天要聊的 context-mode也就是“上下文模式”。说白了它是用来决定“当前工具到底在哪个环境里执行代码、读取数据”的开关。不只是浏览器调试器有这个问题这几年大模型辅助编程流行起来之后AI 编程工具里同样存在 context-mode 的概念你喂给模型的上下文是什么它看到的就是什么选错环境结果必然跑偏。这篇文章我会从浏览器调试和 AI 编程这两个最常见的场景出发把 context-mode 的原理、实操方法、常见坑一次性讲清楚。不管你是刚接触 DevTools 的前端新手还是天天在用 AI 写代码的老手这套思路都能帮你省下很多排查问题的时间。1. context-mode 是什么先搞懂“上下文”这个概念1.1 浏览器调试里的 JavaScript 上下文在浏览器里每个独立的 JavaScript 运行环境都算是一个上下文。比如你打开一个普通页面页面的顶层全局环境是一个上下文页面里嵌了一个 iframe这个 iframe 内部的脚本又运行在另一个完全独立的上下文里Web Worker、Service Worker、浏览器扩展的后台脚本也各自拥有自己的上下文。Chrome DevTools 的 Console 面板左上角那个默认显示top的下拉菜单官方叫法就是“JavaScript context 选择器”。你选择了哪个上下文控制台里执行的代码就会运行在哪个环境里。我见过不少开发者在这个下拉菜单上踩坑明明页面里有个 iframe却在 console 里直接访问 iframe 内部的全局变量结果拿不到或者调试 Worker 的时候还在用window报错之后才开始怀疑人生。这个下拉菜单支持的环境大致如下上下文类型全局对象典型场景top顶层页面window页面主逻辑、业务脚本iframe内嵌页面iframe 内部的 window嵌套的 H5、第三方支付、编辑器等Web Worker / Service Workerself耗时计算、缓存管理、后台同步Extension Context扩展页面扩展自身的 window浏览器插件调试注意这里有一个安全边界跨域的 iframe你无法在顶层上下文中直接通过contentWindow去访问它的内部变量因为同源策略会挡住。但 DevTools 的 context 选择器不受这个限制它是调试器层面的能力相当于直接“钻进”了那个 iframe 的执行环境里。这也是为什么我强烈建议前端开发者把这个功能彻底搞明白——它比你在代码里临时加debugger或者console.log要高效得多。1.2 大模型里的上下文窗口聊完浏览器再看另一个被大量称为 context-mode 的场景就是 AI 对话和 AI 编程工具里的上下文管理。大语言模型有一个“上下文窗口”context window的概念本质上是模型一次能“看到”的 token 上限。现在的模型窗口越来越大128K、200K 都很常见但“能装下”和“装得合适”是两码事。上下文窗口里塞进去的内容决定了模型对当前任务的理解质量。你给它看什么它就只能基于什么来回答。所以很多 AI 编程助手、Agent 类工具里就出现了“自动上下文”和“手动上下文”两种模式自动模式会帮你检索相关文件、带上最近改动和对话历史手动模式则允许你明确指定哪些文件、哪些说明、哪些约束要进入模型的视野。这两种模式背后的核心和 DevTools 里的 context 选择器其实是同一个问题让工具知道现在该把哪个环境里的数据当作“当前有效信息”。2. context-mode 的核心原理与设计思路2.1 为什么不能把所有内容都塞进上下文很多人刚开始用 AI 编程工具时习惯把整个项目目录一股脑塞给模型觉得信息越全越好。实际上不是这样。我自己的经验是上下文塞得越满模型越容易“迷失在中间”。论文里有个很有意思的发现叫 lost in the middle意思是模型在处理超长上下文时对中间部分内容的记忆和关注度明显低于开头和结尾。你想想当你的关键需求被埋在几千行无关代码里模型大概率会忽略它。浏览器调试也是一样的道理。如果你在top上下文里写代码却想操作 iframe 内部的变量不是不能做但需要一层层contentWindow去取代码又长又丑还容易在黑盒场景下碰壁。与其这样不如直接切到正确的上下文让所有变量都变得“可达”。还有成本问题。对 AI 来说token 就是钱也就是延迟和费用。每次请求塞进去的 token 越多响应越慢费用越高。我通常会在项目里做一笔粗略估算中文场景下1 个汉字大概对应 1 到 1.5 个 token1 万汉字的文档光 token 就要 1 万到 1.5 万。一个 128K 窗口的模型塞满它的话大概能装 8 万到 10 万汉字听着很多但一旦有多个大文件、多轮历史、检索片段堆在一起超限是分分钟的事。超限之后系统要么直接报错要么静默截断早期内容早先那些“重要背景”可能早就被丢掉了。2.2 选择正确上下文的通用策略既然不能全塞那怎么选我把 context-mode 的选择策略总结成三步先明确任务意图再圈定相关信息范围最后设定约束和输出格式。浏览器调试里这一步对应的是先确认“我要调试的代码到底运行在哪个环境里”再选择对应的 iframe 或 Worker。AI 编程里这一步对应的是“这个需求涉及哪些文件、哪些技术栈、哪些历史决策”然后把它们有组织地放进提示词里。实操上我强烈建议使用“混合模式”让 AI 工具自动检索相关文件但你保留一个“白名单”和“黑名单”。比如我会在项目根目录维护一个说明文件把核心模块的目录结构、启动命令、测试方式、快捷键、已知坑都写进去工具每次自动加载同时把node_modules、dist、build这类目录明确排除在检索范围之外。这样一来自动模式帮我省去了手动挑选文件的体力活手动配置又保证了关键信息不会被淹没。3. 实战在浏览器调试中用好 context-mode3.1 找到并打开 context 选择器Chrome DevTools 的 context 选择器位置很固定打开 DevTools切到 Console 面板看左上角。默认它是一个写着top的下拉框旁边可能还有一个眼睛图标。点击下拉框就能看到当前页面里的所有上下文。这里有一个实用技巧如果你在 Elements 面板里选中了 iframe 内部的某个元素再到 Console 面板看这个下拉框它有时会自动切换到你正在查看的 iframe 上下文。不过这个行为取决于页面结构和 DevTools 版本不要完全依赖它手动点击下拉框永远是更稳妥的方式。3.2 场景一调试 iframe 内部的变量和函数最常见的实战场景就是调试嵌套页面。比如电商后台里嵌了一个订单详情 iframe子页面里有个全局函数refreshOrder()你在顶层控制台直接调用会报错。操作步骤打开 DevTools切到 Console 面板。点击左上角的上下文下拉框选择目标 iframe 的名称通常会显示为iframe[名字]或者about:blank之类的页面标识。此时控制台里的执行环境已经变成 iframe 内部了。直接输入window.location.href验证是否切换成功。再调用 iframe 内部的全局函数比如refreshOrder()就能生效了。如果不想切换上下文也可以在top上下文中通过 DOM 方式访问只限同源 iframe// 在顶层控制台中访问同源 iframe 内部变量 const innerWindow document.querySelector(iframe).contentWindow; innerWindow.refreshOrder();两种方式各有利弊切换 context 适合频繁调试子页面内部逻辑而contentWindow方式适合在跨环境传参、模拟外部调用时使用。但跨域 iframe 无法用第二种方式读取内部变量这时候只能靠 context 选择器。3.3 场景二调试 Web Worker 和 Service Worker调试 Worker 时最经典的错误就是在 Worker 上下文里继续写window。Worker 里根本没有window全局对象是self。在 Console 面板切换到 Worker 上下文后你可以直接访问self上的属性和方法比如self.postMessage、self.onmessage等。实际操作中我会先在下拉菜单里看有没有当前页面启动的 Worker有的话切过去然后手动执行一些检查// Worker 上下文环境验证 typeof window; // undefined typeof self; // object self.constructor.name; // DedicatedWorkerGlobalScope 或类似值Service Worker 的调试也类似但要注意 Service Worker 的生命周期是独立的它不随页面刷新而销毁所以调试完记得在 Application 面板里手动更新或停止它避免后续请求一直命中旧缓存。3.4 几个容易踩的细节坑第一let和const声明的变量不属于window对象。就算你在顶层上下文里写过let abc 1在 Console 里访问window.abc依然是undefined。这种变量挂在脚本作用域上不在全局对象上。如果你非要验证某个变量的存在直接输入变量名而不是window.变量名。第二切换上下文之后之前在当前上下文中声明的变量会丢失。因为 DevTools 的 Console 里用let、const声明的变量跟当前上下文绑定刷新页面、切换 context 都会导致这些声明失效。所以临时变量建议用window.tmp xxx这种挂在全局对象上的方式存活期更长。第三页面刷新之后iframe 的上下文列表会重建你需要重新选择一次 context。这不是 DevTools 的 bug而是页面重新加载后旧执行环境本身就已经销毁了。提示如果要在页面刚加载时就调试某个全局变量的初始化过程别用 Console 硬等建议在 Sources 面板里给对应脚本打一个断点刷新页面后在调用栈里确认当前处于哪个上下文再配合 Console 查看变量。4. 实战在 AI 编程与对话中管理上下文4.1 把项目当作一个大的上下文池AI 编程工具中的 context-mode本质上是让你从“整个仓库”这个大池子里挑选一小部分送入模型的窗口。你可以把它理解成浏览器里的top下拉菜单项目仓库是top每个文件、每段历史记录、每个规范说明都像是一个 iframe 或 Worker你得主动选择哪些要被“看到”。我最常用的做法是先不看具体代码而是把项目的“环境信息”丢给模型包括技术栈、目录结构、启动命令、测试命令、关键约定。等模型建立了基本认知再让它看具体文件。这相当于先把 context 切换到“项目顶层”把大局观建立起来再深入细节。4.2 手动模式的提示词模板手动模式不等于简单的“复制粘贴代码”。我给 AI 发任务时通常按照下面这个模板组织上下文背景这是一个 Vue 3 TypeScript 项目负责订单模块。 当前任务修复订单列表在切换状态标签后筛选条件丢失的问题。 相关文件 - src/views/order/List.vue列表页负责筛选和状态切换 - src/composables/useOrderFilter.ts筛选逻辑包含状态、时间、关键词 - src/api/order.ts接口定义 已知问题切换标签时 useOrderFilter 里的状态字段被重置了但我怀疑是 List.vue 里 tab 组件绑定值的问题。 请先说明你会按什么顺序排查再给出具体修改方案。这个模板看起来很朴素但信息组织非常讲究先说技术栈和模块让模型知道这是哪个“上下文”再说任务目标让模型知道要干什么然后列出相关文件等于给模型划定了一个“虚拟工作目录”最后说明已知问题和怀疑方向减少模型的搜索成本。我自己用下来这个模板比干巴巴一句“帮我看看这段代码为什么报错”成功率高一倍。原因不复杂context 选得越准模型越不需要瞎猜。4.3 自动模式下的 token 预算管理如果工具支持自动检索你也不能完全撒手不管。我推荐提前做一个 token 预算表心里有数地分配窗口用途建议预算说明任务描述与约束5% 左右开头和结尾的信息最容易记住相关代码片段60% 左右主体内容按依赖顺序排列项目规范与背景20% 左右技术栈、目录结构、风格约定对话历史10% 左右只保留近期关键决策旧信息压缩成摘要输出预留5% 左右防止生成中途被截断比如一个 128K 的窗口我会控制在 100K 以内留出 28K 左右的余量避免max_tokens撞墙导致回答被拦腰截断。实测下来宁可上下文中放的东西少一点也不要压着窗口上限往里塞因为模型在接近窗口上限时的推理质量会明显下降输出也可能变短、变敷衍。4.4 AI 场景下的典型翻车现场我从大量实际使用中总结出三个高频问题。第一个是“越改越乱”。原因通常是上下文里出现了矛盾信息旧版本的代码片段和新版本的代码片段混在一起模型不知道以哪个为准。解决方法是重新拉一个对话把当前最新的代码作为唯一基线旧讨论一律不放进来。第二个是“回答很空像在说套话”。这通常是上下文里缺少具体的业务约束比如接口字段、样式规范、性能要求。模型只知道大概方向只能给泛泛的建议。这时候把相关接口返回示例、UI 截图描述、性能目标加进去回答立刻会具体很多。第三个是“关键文件被忽略”。如果你给了模型 10 个文件它往往会只关注前两三个中间的会被“遗忘”。解决办法是把最重要的文件放在列表最前面或者单独用一句话强调它比如“重点看 src/constants/status.ts 里的状态映射这是本次改动的基础”。5. 常见问题排查速查表下面这张表是我在实际调试和 AI 使用过程中总结出的高频问题清单可以直接拿来当排查手册用。问题可能原因解决办法Console 报xxx is not defined选了错误的上下文切换到目标 iframe / Worker 上下文或用contentWindow访问切换 iframe 后变量突然没了页面刷新重建了全局环境刷新后重新选择上下文临时变量挂到window上Worker 里用window报错Worker 没有 DOM 环境改用self确认当前属于 Worker 上下文跨域 iframe 无法读取内部变量同源策略限制使用 DevTools 的 context 选择器直接切入AI 回答不相关上下文缺少背景和任务约束补充技术栈、模块范围、目标描述AI 中途截断或输出变短上下文过长或接近窗口上限精简内容压缩历史减少无关文件AI 重复犯同一个错旧代码和最新代码冲突新开对话只给最新基线代码工具自动检索到了无用文件缺少排除配置在配置中加入 ignore 列表比如构建目录、锁文件经验之谈排查任何和 context 相关的问题第一步永远是“确认当前在哪个环境里”。在浏览器里看下拉框在 AI 工具里看已加载的上下文清单。这一步确认完一半的问题其实已经找到根因了。6. 从工具到方法论context-mode 的通用准则6.1 上下文的最小充分集所谓最小充分集就是“能给一句话说清楚的任务绝不放十段代码”。信息越多噪音越大。调试时如果你只需要一个变量的值直接在控制台输入变量名不用在代码里加一大堆日志给 AI 提需求时能指向具体文件和函数就不要让它大海捞针。我给自己定了一条规矩每次准备给 AI 提供上下文时先问自己三个问题——这次任务依赖哪些文件哪些历史决策会影响这个改动如果我是一个刚接手的新人最少需要知道哪些背景才能动手问完这三个问题上下文质量一般都不会差。6.2 稳定上下文与瞬时上下文另一个有用的分类方式是把上下文分成稳定和瞬时两类。稳定上下文包括项目说明、技术栈、目录结构、代码规范、部署方式这些内容写得越详细越好最好写进一个固定的文档每次让 AI 自动加载。瞬时上下文包括当前报错、最近改动、本次需求的特殊约束这些只在当前对话中存在用完就该丢弃。为什么区分这两类有意义因为你如果让稳定上下文和瞬时上下文混在一起AI 就分不清哪些是长期规则、哪些是临时任务很可能把临时需求当成项目规范写进它后续的建议里导致代码风格漂移。6.3 建立团队级“上下文档案”最后我强烈建议每个项目都维护一份“上下文档案”这是 context-mode 方法论落到实处的关键。内容不需要多但要有项目一句话简介、核心目录结构、常用命令、技术决策记录、已知坑位列表。我们团队的仓库里就放了一个CONTEXT.md把上面这些内容写清楚每次接入 AI 工具时让它优先读取这个文件。效果非常明显AI 生成代码里出现瞎猜目录结构、乱用命令的情况少了很多人也一样受益——新人入职后读一遍这个文件基本能独立上手开发。这个档案和维护代码注释一样需要持续更新但收益率极高。它是整个上下文管理体系中收益最稳定的部分。最后再分享一个小技巧是我自己的习惯不一定适合所有人但你可以试试把“context-mode”当成一种调试心态遇到问题不急着改代码先在心里问一句“我现在在哪个环境里我看到的上下文完整吗”在浏览器里这句话对应的是那个下拉菜单在 AI 工具里这句话对应的是窗口里的文件列表和提示词。每次这样追问一下我都能以最快速度定位到问题的真正源头。上下文选对了事情就成了一半。