同一个 AI,有时像资深工程师,有时像刚进项目第一天的新人。
很多人会把这种差异归因于模型状态、提示词写得好不好,或者当天选到的模型版本。但在真实项目里,更常见的原因其实是:AI 每次拿到的上下文不同。
如果只给它一句“帮我改一下分类筛选”,它需要自己猜项目结构、业务规则、验收标准和测试方法。它猜对了,结果看起来就很惊艳;猜错了,改动就会迅速偏离目标。
所以 AI 编程进入真实项目以后,真正需要解决的不是一句提示词怎么写得更长,而是如何稳定地把正确的信息交给它。这件事可以叫作上下文工程。
提示词解决一次沟通,上下文工程解决持续协作
Prompt Engineering 当然有价值。它可以让一次任务的目标更清楚,让输出格式更稳定,也可以提醒 AI 先分析、再修改、最后验证。
但提示词很难长期承载一个项目的全部背景。项目规则、目录结构、历史决策、测试命令和风险边界,不应该在每次对话中重新解释一遍。
如果这些信息只存在聊天记录里,就会出现几个问题:
- 换一个任务后,背景信息容易漏掉
- 换一个会话后,AI 又要重新认识项目
- 不同人给出的约束不一致
- 重要决策散落在很长的对话里,无法复用
上下文工程关注的则是另一组问题:AI 做这个任务需要知道什么?哪些信息是项目级固定规则?哪些信息只属于当前任务?哪些信息应该来自测试结果?哪些信息需要随着项目变化而更新?
它不是把提示词写得更复杂,而是把信息放到正确的位置。
AI 编程需要五层上下文
我会把一个真实项目里的上下文分成五层。
1. 项目级上下文
这一层回答“这个项目是什么”。内容包括技术栈、目录职责、启动命令、测试命令、代码风格、不能随便修改的文件,以及生成文件和源文件的区别。
它适合放在AGENTS.md、项目 README 或repo-map.md中。
2. 任务级上下文
这一层回答“这次要解决什么问题”。至少应包含目标、范围、不做什么、验收标准和已知风险。
一句“增加筛选功能”通常不够。更明确的任务应该说明筛选对象、支持的条件、默认行为、空结果如何展示,以及哪些旧行为不能改变。
3. 文件级上下文
这一层回答“具体从哪里改”。它包括相关文件、调用关系、数据流、已有抽象和修改边界。
不要一开始就把整个仓库都塞给 AI。先让它根据项目地图定位相关模块,再给它足够完成当前任务的代码,结果通常更容易控制。
4. 验证级上下文
这一层回答“怎么证明改对了”。内容可以是单元测试、接口测试、构建命令、截图检查、人工验收点和最近一次失败日志。
没有验证上下文,AI 很容易把“代码写完”误当成“任务完成”。
5. 历史级上下文
这一层回答“为什么要这样做”。例如某个接口为什么保留旧字段,某个模块为什么没有抽象,某个兼容逻辑为什么不能删除。
这类信息如果不记录,AI 很容易把历史约束当成坏味道,顺手重构出新的问题。
一套够用的最小组合
不需要一开始就建设很重的知识库。一个小项目先准备下面几类文件,已经能解决大部分重复解释问题:
AGENTS.md或 Skill:固定协作规则和安全边界repo-map.md:入口、模块、测试和常见修改路径- issue 模板:目标、范围和验收标准
- 测试矩阵:场景、输入、预期和优先级
- decision log:重要决策和不能违反的历史约束
- 发布检查清单:上线前必须验证的事项
它们不必写得很长,但必须容易找到、容易更新、能被任务流程实际使用。
一个具体的任务上下文模板
## 目标 ## 不做什么 ## 相关文件 ## 已有规则 ## 验收标准 ## 必须运行的验证命令 ## 已知风险把这份模板放进 issue 或任务卡里,AI 的工作起点就会稳定很多。执行前,可以要求 AI 先复述目标、列出影响范围和验证方法;执行后,再要求它对照验收标准逐项检查。
这比不断追加“注意一点”“不要改坏别的地方”更有效,因为约束已经变成了任务的一部分,而不是临时提醒。
上下文也需要维护
上下文工程不是一次性写完文档就结束了。项目结构会变,测试命令会变,旧的决策也可能被新方案替代。
每次 AI 踩到一个重复出现的坑,都应该判断它是否值得写回项目规则。每次发现常见任务都有固定修改路径,也可以补进仓库地图。过时的文档则要删除或标记失效,否则上下文越多,噪声也越大。
好的上下文不是“信息最多”,而是“当前任务拿到的信息足够、可信、可验证”。
我在记账 App 里怎么落地
以“给交易列表增加分类筛选”为例,我不会直接把需求扔给 AI,而是先准备一张任务卡:
## 目标 在交易列表中支持按分类筛选,默认显示全部交易。 ## 不做什么 - 本次不修改统计页的统计口径 - 本次不新增自定义分类 - 本次不改动数据库表结构 ## 相关文件 - frontend/src/pages/BillsPage.vue - frontend/src/components/TransactionList.vue - backend/app/api/transactions.py - backend/app/services/transaction_service.py ## 验收标准 - 选择分类后列表只显示对应账单 - 清除分类后恢复全部账单 - 无结果时显示空状态 - 原有分页和日期筛选不受影响 ## 验证命令 - pytest backend/tests/test_api_integration.py - npm run build --prefix frontend然后让 AI 按固定顺序工作:先读repo-map.md,再检查相关文件,接着列出影响范围和实现计划,等我确认后才改代码。修改结束后,它必须把每一条验收标准对应到具体测试或人工检查。
这个过程比“帮我增加分类筛选”多了几分钟准备时间,却省掉了大量来回纠错。更重要的是,任务完成以后,这张任务卡还可以直接变成 PR 描述和测试记录。
怎么判断上下文是不是过量
上下文也不是越多越好。如果把整个仓库、所有历史聊天和所有日志一起交给 AI,真正重要的信息反而会被淹没。
我会用三个问题做筛选:
- 这条信息是否会改变实现方案?
- 这条信息是否能帮助判断边界或风险?
- 这条信息是否能被测试或文件引用验证?
三个问题都答不上来的内容,通常可以先不放进当前任务。把固定规则、当前需求、相关代码和真实验证结果分开存放,比做一个不断增长的“超级上下文”更可靠。
最后
AI 编程从玩具走向真实项目以后,提示词只是入口,上下文才是工程能力。
可以把结果粗略理解为:
AI 编程质量 = 模型能力 × 上下文质量 × 验证反馈模型能力决定它能做什么,上下文质量决定它是否知道该做什么,验证反馈决定它能不能发现自己做错了什么。
Prompt 决定 AI 这一次怎么回答,上下文工程决定 AI 能不能在一个真实项目里持续稳定地工作。