做技术这行久了,你会发现很多问题不是“工具不够强”,而是“工作方式还没跟上工具的变化”。前阵子用 AI coding agent 做一个权限管理模块,我算是被狠狠教育了一回:需求其实不复杂,无非是角色管理、用户绑定、接口鉴权,但涉及的表有七八张,牵扯的文件二十多个。我把完整需求写进提示词,让 AI 一次性实现,结果会话进行到一半,模型开始忘掉之前定的表结构,后面甚至建议重做一套完全不同的数据模型。那一刻我意识到——不是模型笨,而是我把一个超过上下文窗口承载能力的任务,硬塞进了同一段上下文里。
在 AI Coding for Real Engineers 这个系列走到第 39 期的时间点上,我想认真聊一个真实工程里绕不开的话题:跨多个上下文窗口拆分特性。这期的核心判断是:上下文窗口不是一条可以随便突破的边界,它更像一张固定大小的“工作台面”。真正决定 AI Coding 能不能从玩具变成生产力的,不是你会多少提示词技巧,而是你能不能把一个一次装不下的任务,拆成多个彼此独立、每个都能验证、窗口之间还能无缝交接的小任务。网上经常能看到“数小时完成过去数周工作”的说法,这个说法不算夸张,但它通常藏着一个没被说出来的前提:使用者已经知道怎么拆需求、做交接、分窗口。没有这个前提,AI 只是帮你更快地写出不可维护的混乱代码。
1. 真实功能天生就超过单次上下文窗口
1.1 一个“简单功能”的信息量,远超你的估算
很多人对上下文窗口的理解,停留在“模型一次能读多少 token”。但落到真实项目里,问题要具体得多。
一个看起来简单的“角色管理”功能,背后是这些信息:
- 数据库表结构和迁移脚本;
- 后端服务里角色的增删改查逻辑;
- 与用户表的多对多关联关系;
- 接口路径、参数、权限注解;
- 前端列表页、编辑弹窗、表单校验;
- 单元测试和联调用的测试数据;
- 部署时的环境变量和初始化脚本。
这些内容加在一起,轻松超过几千行代码,换算成 token 就是几十万。主流的 AI 编码模型虽然宣传上下文窗口很大,但真实编码任务里,模型需要同时理解项目结构、依赖关系、已有代码风格、本次需求、约束边界,再加上对话历史里来回修改的内容,一次会话能装下的“有效工作集”远比你想象的小。
更麻烦的是,你很难预判某个细节会被模型记住还是被忽略。可能你觉得已经说清楚了的表名,在二十分钟后就被模型“创造”了一个新版本。这不是模型故意犯错,而是它工作台面上的东西太多了,注意力被稀释了。
1.2 把上下文窗口当作“工作台面”,而不是“硬盘”
我以前总觉得,上下文窗口越大越好,最好能把整个项目都塞进去。实际用过几轮之后才发现这个理解是错的。
上下文窗口更像一张物理工作台:你只能把当前要用的工具和材料放在手边。台面大小固定,东西放多了,要么把之前放上去的东西挤下去——对应到模型就是“忘记”之前的信息;要么所有东西都挤在一起,拿什么都费劲——对应到模型就是输出质量下降、前后矛盾。
工程上解决“工作台面放不下”的标准做法,是使用外部存储:把不常用的零件放回货架,把当前需要的放在台面上。代码放在文件系统,设计写进文档,步骤记在待办清单里,需要时再取出来。AI 编码的跨上下文窗口拆分,本质上是同一套思路:上下文窗口装不下的部分,应该放在“外部”——文件、文档、交接说明——需要用的时候再通过一个新窗口读取进来。这不是逃避模型的上下文限制,而是适应这个限制的工程选择。
2. 跨窗口拆分拆的不是文件,而是“可独立验收的交付块”
2.1 每个交付块都要能回答三个问题
跨窗口拆分最难的不是“怎么拆”,而是“按什么标准拆”。
很多人习惯按文件拆:这个窗口改 service,那个窗口改 controller。这种拆法看起来清楚,但一个窗口做完之后,你几乎无法验证它是不是“真的完成了”,因为功能要等所有文件都改完才能联调跑通。于是问题就积压到了最后,联调变成一场灾难。
更合理的拆法,是围绕“可独立验收的交付块”来拆。每个交付块做完之后,不用等别的窗口,单独就能验证。判断一个交付块是否合格,你可以问三个问题:
- 它的输入是什么?——需要读取哪些文件、依赖哪些已有接口。
- 它的输出是什么?——应该产生哪些代码改动、新增哪些文件。
- 怎么证明它做完了?——能否编译通过、调通一个接口、看到一个页面,或者跑过一组测试。
如果一个窗口做完后还是“半成品”状态,说明拆得还不够细。举例来说,“角色管理”可以拆成这样:
| 交付块 | 交付内容 | 验收方式 |
|---|---|---|
| 1 | 角色表 + 迁移脚本 | 迁移能执行,表结构正确 |
| 2 | 后端角色 CRUD 接口 + 权限校验 | 接口调用返回符合预期 |
| 3 | 前端列表页 + 编辑弹窗 | 页面能渲染,交互能走通 |
| 4 | 用户与角色绑定逻辑 + 测试 | 测试通过,边界场景覆盖 |
每个交付块单独开一个上下文窗口,彼此之间通过交接文档连接。窗口内不需要知道其他交付块的完整实现,只需要满足前置依赖即可。
2.2 验收成本控制在五分钟以内,循环才能转起来
这里有一条很实际的经验:每个交付块的验收成本,最好控制在五分钟左右。
如果验证一个窗口的产出要半小时甚至一小时,整个流程就会被拖垮。你会在潜意识里开始偷懒——“先不验证了,继续下一个吧”——然后问题就会在你没注意的地方悄悄堆积,最后在联调时一次性爆出来。
五分钟能验证什么?跑一个迁移、调一个接口、打开一个页面、执行一组单测。这些快速验证足以证明“这个交付块是健康的”。至于更完整的端到端联调,应该放在单独的窗口里做,而不是塞进每个交付块的验收环节。
这条规则的本质是:跨窗口拆分要照顾到人的工作循环。快速验收、及时反馈、进入下一个窗口,这个循环一旦建立,AI Coding 的产出才会稳定。验收如果太慢,循环就会断,流程就会退化成“先写完再说”的旧习惯。
注意:每个窗口的验收标准必须在开工前写清楚。没有验收标准的窗口,很容易变成 AI 自由发挥的施工现场。
3. 窗口与窗口之间,靠交接文档而不是聊天记忆
3.1 为什么“继续对话”不是好方案
很多人跨窗口的方式,是在同一个产品里继续对话,或者把上一次的聊天记录直接粘贴给新会话。理论上可行,但实际效果很差。原因有三个。
第一,对话历史本身就是上下文负载。你把前面几轮长对话原样带进新窗口,等于还没开始干活,台面的一半已经被旧东西占了。第二,对话的信息密度太低。中间有大量试错、走弯路的过程,真正重要的决策被淹没在冗长的历史里。第三,聊天记录无法被结构化使用。你需要的不是“当时聊了什么”,而是“现在代码在什么状态、下一步改什么、哪些决定不能动”。这些信息只能通过一份整理过的文档提供。
所以正确的做法是:每个新窗口都从一个干净上下文开始,把必要信息通过一份交接文档带进去。AI 不需要知道昨天你们争论过什么,只需要知道今天它该干什么。
3.2 一份交接文档至少写清五类信息
我在实际项目中使用的交接文档,通常放在项目里的固定位置,比如docs/handoff-001.md,并且保持固定结构:
- 当前目标:这个窗口要完成哪个交付块,验收标准是什么。
- 已有状态:项目目前已经实现了哪些部分,哪些文件是本次的核心文件。
- 关键决策:已经定下的表结构、命名规范、接口约定、禁止改动的内容。
- 待办事项:下一个窗口要做什么。
- 风险提醒:之前在什么地方差点出错,下一个窗口要注意什么。
这里最关键的是“关键决策”和“禁止做的事”。比如写一句“用户与角色采用users、roles、user_roles三张表关联,不要改成 JSON 字段存储”,就能阻止下一个窗口的 AI 设计出完全不符合预期的结构。
不要把交接文档写成聊天记录的压缩版。它应该像项目交接时给下一个工程师的备忘录——只保留能帮助对方正确工作的信息,其余全部去掉。
3.3 交接文档要持续更新,而不是一次写死
交接文档不是写一次就完了。每完成一个交付块,就要把“已有状态”和“关键决策”更新一遍,把悬而未决的问题补进“风险提醒”。
你可以让 AI 在完成每个窗口后自动生成一份窗口总结,你花两分钟检查一下,作为下一份交接文档的输入。这样整个流程就变成了:窗口 1 产出代码 + 交接文档,窗口 2 读取交接文档 + 产出代码 + 更新交接文档,窗口 3 继续。每一份文档都比上一份更接近最终系统的真实状态。
如果工具支持把文件作为上下文引用,也可以直接把交接文档路径告诉新窗口的 AI,让它先读文档再开工。这一步能省掉大量重复解释,也让新窗口的启动变得非常快。
4. 单个窗口内的信息负载控制
4.1 一个窗口只做一种动作
跨窗口拆分解决了“任务太大装不下”的问题,但窗口内部还有一个常见错误:在一个窗口里让 AI 同时做实现、重构、修 bug、写测试。
这个问题的根源在于,不同动作类型的上下文需求完全不同。实现新功能需要的是需求、相关文件、接口契约;重构需要的是现有代码结构、调用关系、风险点;写测试需要的是被测逻辑、输入输出样例、边界条件。把这几件事混在一起,AI 的注意力会被反复切换,上下文里也塞满了相互矛盾的信息。
更稳妥的用法是:一个窗口对应一个明确动作类型。要么实现,要么修复,要么重构,要么写测试。如果中途发现 AI 已经偏离了当前动作,不要试图在同一个窗口里把它拉回正轨,而是停下来,重新开一个窗口,只描述当前问题。
4.2 用“文件引用 + 关键片段”代替整文件粘贴
另一个常见问题,是把项目里的文件整段复制进提示词,以为信息越全越好。
实际使用中,很多 AI coding agent 已经具备读取项目文件的能力。你可以直接告诉它:“你的任务基于app/services/role_service.py、app/api/role_routes.py和前端src/pages/roles目录,先读取这三个文件再开始。”让工具按需读文件,比自己手动粘贴所有代码省大量上下文。
如果工具不支持自动读文件,就采用“关键摘录 + 路径引用”:只贴函数签名、数据结构、核心逻辑片段,同时把完整文件路径写在提示词里,让 AI 知道去哪里查看上下文。这里有个容易踩的坑:你以为贴得越全越好,实际上贴得越全,真正重要的需求描述越容易被淹没。上下文里全是代码,需求指令反而成了少数派。
4.3 让 AI 只输出改动,而不是重写整个文件
还有一点很多人忽略:AI 在实现功能时,默认倾向把整个文件重写一遍。这在单人小项目里问题不大,但到了真实项目里,整文件重写会导致大量无关改动,代码评审变成一场逐行比对事故。
我在让 AI 做修改时会明确要求:“只输出需要修改的函数、新增的代码和对应位置,不要重写整个文件。”如果工具支持 diff 模式,就尽量使用——AI 生成改动,你审查后再应用。
这个习惯有两个直接好处:一是上下文消耗大幅降低,因为改动集中、差异清晰;二是评审成本低了许多,你能快速判断每个改动是不是本窗口该做的事。如果 AI 给出的大段重写里包含无关重构,你可以直接拒绝,而不是花时间甄别。
5. 从需求到多个窗口:一套可以直接抄的实操流程
5.1 第一步:把需求倒推成验收点清单
拿到需求后,不要急着让 AI 开工。先在文档里把需求拆成验收点,每个验收点对应一个上下文窗口。
可以用一个简单模板记录:验收点编号、交付内容、涉及文件、验证方式、前置依赖。
举例,需求是“给订单模块加一个导出功能”:
| 验收点 | 交付内容 | 验证方式 | 前置依赖 |
|---|---|---|---|
| 1 | 订单查询接口支持导出参数 | curl 调用接口返回 CSV | 已有订单表 |
| 2 | 导出任务异步化,大订单不阻塞 | 接口返回任务 ID,轮询能拿到结果 | 已有异步任务组件 |
| 3 | 前端导出按钮 + 下载链接 | 页面点击后能下载文件 | 接口完成 |
| 4 | 权限校验:非管理员不允许导出 | 普通账户调用返回 403 | 已有权限体系 |
每个验收点都是一个独立窗口。窗口之间不需要知道对方的完整实现,只需要满足自己的前置依赖。
5.2 第二步:为每个窗口写一份“启动说明”
打开新窗口之前,用几分钟写一份窗口启动说明。它不是完整需求书,而是给 AI 的上下文入口:
- 你的任务是:完成验收点 X。
- 涉及文件:列出具体路径。
- 前置约定:已经定好的接口格式、数据库结构、命名风格。
- 验收标准:这次做完怎么算完成。
- 禁止事项:不要动哪些文件、不要改哪些设计。
这份说明可以手工写,也可以基于上一份交接文档让 AI 生成初稿,你再补充。关键是让新窗口在很短时间内进入状态,而不是花十分钟向 AI 解释背景。
这里有一个建议:把“禁止事项”写得越具体越好。泛泛的“不要改无关代码”没用,要写成“不要修改order.py中已存在的查询逻辑”“不要重命名export_task表”这样可检查的指令。
5.3 第三步:逐窗口执行,每个窗口结束都强制验证
执行顺序上,建议先做依赖最深的部分,再做上层展示。比如先数据表、再接口、再前端、最后联调。
每个窗口结束,用验收标准做一次快速验证:编译、跑测试、调接口、看页面。验证通过,更新交接文档;验证不通过,先在当前窗口修复,不要带着已知问题进入下一个窗口。这条规则要强制,没有例外。
实际经验是:只要有一次带着未验证的问题进入下一窗口,后面至少会多花一倍时间来找问题根源。因为到那时,你已经无法确定问题是出在这个窗口还是上一个窗口。
5.4 第四步:联调单独开一个窗口
联调是一个独立动作。所有交付块都完成之后,专门开一个窗口做集成联调。这个窗口的目标不是写新代码,而是把各窗口的产物串起来验证。
联调窗口的输入,应该包括所有交付块的改动清单、交接文档和完整验收标准。它不需要读取每个窗口的全部对话历史,只需要这些结构化产物。如果联调中发现两个交付块之间存在接口契约不一致,那就回去更新对应交付块的交接文档,再开修复窗口处理,而不是在联调窗口里顺手改掉,那样会让上下文再次失控。
6. 四种典型失败模式与排查链路
6.1 失败模式一:AI 改了不该改的文件
跨窗口拆分后,新窗口的 AI 拿到需求,为了“实现得更完整”,顺手改掉了不属于本次范围的代码。
出现这种情况,先别急着怪 AI。检查窗口启动说明里的“禁止事项”是否写清楚了。如果文档已经明确“只允许修改这三个文件”,AI 仍然乱改,再考虑是不是工具需要限制文件访问范围。多数情况下,问题出在文档不够具体。
排查顺序是:先看启动说明,再看工具配置,最后看 AI 的具体改动内容。不要一上来就断言“这个 AI 工具不行”。
6.2 失败模式二:前后设计不一致
窗口 1 定好了表结构,窗口 2 实现了另一套结构,最后两个窗口的代码互相冲突。这是跨上下文拆分里最典型的风险。
排查方向优先看交接文档里的“关键决策”是否写清楚。如果文档没写,或者写得含糊,比如只写了“用户和角色是多对多关系”,却没说明关联表名和字段类型,那么窗口 2 的 AI 有充分的自由发挥空间,前后不一致几乎是必然的。
修复方式不是让 AI 去猜,而是回到交接文档,把决策写死,然后重新开一个窗口改掉不一致的部分。靠对话提醒是没用的,因为下一个窗口未必能读到这次对话。
6.3 失败模式三:单窗口信息过载导致输出退化
有时候任务已经拆小了,但窗口里塞了太多文件内容、测试代码和历史对话,导致 AI 输出到后面开始重复、遗漏或者质量下滑。
排查链路建议按这个顺序走:
- 先看输入:启动说明之外,你是否手动粘贴了大量完整代码?如果是,改成文件引用。
- 再看对话轮次:过去几轮里有没有大量来回修改?如果有,考虑重新开窗口。
- 最后看文件范围:涉及文件是否远超交付块所需?如果是,缩小范围。
正常情况下,一个窗口只应该有两到三次有效交互:读取上下文、产出实现、根据反馈做小幅修正。如果对话轮次超过十次,大概率说明任务拆分或者输入组织出了问题。
6.4 失败模式四:验收缺失导致问题积压
如果每个窗口都不做快速验收,问题不会消失,只会延后到联调窗口集中爆发。
统一的排查思路可以这样写:先定位现象,再检查输入,然后看环境与依赖,接着确认参数与范围,最后才考虑工具边界。对应到跨窗口场景:
- 现象:哪个验收点失败了?是编译、逻辑还是数据问题?
- 输入:交接文档和启动说明是否准确反映了当前状态?
- 依赖:这个交付块的前置依赖是否真的完成了?
- 范围:AI 是否被允许做了超出窗口的事?
- 边界:如果单独跑交付块没问题、集成才出问题,说明两个窗口之间的接口契约不一致。
按照这个顺序排查,大多数跨窗口问题都能定位到具体环节,而不是在“AI 不好用”这个层面反复打转。
7. 团队协作时,这套方法还要补三件事
7.1 统一交接文档格式
团队多人使用 AI coding agent 时,最容易出现的问题是每个人拆分方式不同、交接文档格式不同,最后互相看不明白。
团队至少要约定:交接文档放在哪里、叫什么名字、包含哪些固定章节、验收点如何编号、每个交接文档由谁负责更新。这些约定不是文档洁癖,而是让团队成员之间可以互相接手未完成的工作。否则一个人写“已完成角色 CRUD”,另一个人写“角色接口好了”,上下文信息就对不上。
7.2 按交付块做代码评审
跨窗口拆分之后,代码评审也应该按交付块进行。每次评审只看一个窗口的改动范围,验收点和改动内容一一对应。
如果评审时发现改动范围里混了其他内容,要么拒绝,要么单独开一个修复窗口。别在评审现场让 AI 顺手改掉——那会让评审记录和实际改动脱节。按交付块做评审的好处是,评审记录本身也变成了下一份交接文档的素材,整个流程形成闭环。
7.3 选工具时先看上下文可控性
目前市面上的 AI coding 工具很多,包括常见的编辑器内助手、独立 Agent、命令行工具,也有像是 GLM Coding Plan 这类面向开发者的方案套餐。各家对上下文的管理方式差异很大。
我的建议是:不要先纠结哪个工具“代码写得好”,而是先看它是否支持文件级引用、是否允许你控制 AI 的读取范围、是否方便把交接文档作为启动上下文。如果一个工具连“限制 AI 只读某些目录”都做不到,那很难支撑稳定的跨窗口拆分流程。
工具能力会不断更新,具体参数以你实际使用时的官方文档为准。但“上下文可控性”这个判断标准,短期不会变。
8. 适用边界:不是所有场景都值得拆
8.1 适合拆的场景
这套“跨上下文窗口拆分特性”的方法,适合以下场景:
- 功能涉及多个文件、多张表、多个阶段;
- 项目已经有一定代码基础,不是从零开始的白板;
- 需要多人协作,或者任务跨越多个工作日;
- 对代码质量有要求,不能接受“能跑就行”。
在这些场景里,拆分带来的收益非常明显:每个窗口的错误可控、每个交付块可验证、每个交接点都有文档可追溯。
8.2 不需要拆的场景
对应的,下面这些场景就不用折腾:
- 一次性脚本,几十行代码,一个窗口轻松完成;
- 探索性原型,目标只是快速验证想法,不追求架构稳定;
- 临时调试,直接在原有窗口里追加对话更快;
- 从零到一的极简 Demo,单窗口完全够用。
对于这些场景,强行拆分会浪费大量时间在文档和流程上,反而拖慢进度。这正好说明了方法论的价值有边界:任务越简单,越不需要复杂流程。判断要不要拆,看的是“一个窗口能不能同时装下需求、代码和验证”,而不是“任务听起来大不大”。
8.3 要长期使用,还得补上工程化能力
如果打算把跨窗口拆分作为团队的长期工作方式,光有文档和流程还不够。还需要补上几块基础能力:
- 版本控制:每个交付块单独提交,commit message 关联验收点编号;
- 自动化验证:CI 能把窗口内做的快速验证扩展到整个项目;
- 结构化交接:交接文档可以被 AI 读取,甚至参与生成下一个窗口的启动说明;
- 回滚机制:当某个窗口的产出不合格,能快速回退到上一个验收点,而不是手动修补。
这些能力不是 AI Coding 特有的,但它们是让 AI Coding 从“单次演示”变成“生产流程”的前提。缺少这些,跨窗口拆分只能在个人小项目里自嗨,无法支撑真正的工程协作。
跨多个上下文窗口拆分特性,真正改变的其实是人管理复杂任务的方式。窗口大小是模型定的,但任务怎么拆、交接怎么写、验证怎么做,完全由你决定。下次准备把一个复杂功能交给 AI 时,可以先别急着打开编辑器写提示词。花二十分钟把需求拆成验收点清单,写一份交接文档,然后只开第一个窗口。看起来多花了一点时间,但你跨过的,是很多人始终没有跨过去的那道坎。