模块二:上下文管理能力
知道给 AI 什么信息、不给什么
AI 输出质量 = f(模型能力, 上下文质量)。本讲系统讲显式 / 隐式 / 对话三类上下文管理、IDE Rules 文件、git 上下文与信噪比模型。
为什么上下文管理是关键
AI 模型的行为遵循一个简单公式:
输出质量 = f(模型能力, 上下文质量)
模型能力你无法改变,但上下文质量完全由你控制。给的上下文太少,AI 胡猜;给的太多,关键信息被淹没。上下文管理就是在这两个极端之间找到最佳平衡点。
上下文的三个维度
维度一:显式上下文(你主动提供的)
你在对话中写的文字、贴的代码、引用的文件。
维度二:隐式上下文(IDE 自动提供的)
在 Trae 中:
- 你当前打开的文件(IDE 会自动注入)
- 你选中的代码片段
- 你光标所在的位置
- 项目的
.trae/rules/规则文件 - AI 通过搜索工具自行检索到的代码
维度三:对话上下文(历史对话积累的)
当前对话中前面的消息。随着对话变长,早期的信息可能被截断或权重降低。
核心技巧
技巧一:先提供"为什么",再说"做什么"
差:帮我在 render_ws_data.js 的 switch 里加一个 PAPStatusOut 的 case
好:上次 commit 删了 PAPStatusOut 的处理,导致回放泊车数据时无法自动切到泊车布局。
帮我把 PAPStatusOut 的处理加回来,跟之前的逻辑一样——
读取 data[0] 传给 layoutStore.updateDriveModeFromBack。
"为什么"提供了决策上下文,让 AI 能判断:
- 加在哪个位置合适
- 是否有其他地方也需要改
- 这个改动的影响范围
技巧二:用文件引用代替代码粘贴
差:(粘贴 200 行代码)帮我改一下这个文件
好:看一下 src/js/store/layoutStore/index.ts 中的 updateDriveModeFromBack 方法,
需要把 papStatus === 2 的硬编码改成 EDriveMode.Parking
在 Trae 中,AI 能自己读文件。你只需要指明文件路径 + 具体位置 + 改动意图。
技巧三:打开相关文件 = 无声的上下文
在提问前打开 2-3 个相关文件,这相当于无声的 Prompt。
例如你要改行泊切换逻辑,提问前打开:
render_ws_data.js(数据入口)layoutStore/index.ts(状态管理)layoutStore/types.ts(类型定义)
AI 会看到这三个文件在你的焦点中,搜索和推理时会优先考虑它们。
技巧四:用"反例"校准而不是用"描述"
差:用 MobX 的 action 装饰器,函数式写法,antd 的 message 组件,
错误处理用 try-catch
好:参考 src/js/store/layoutStore/index.ts 中 triggerDriveMode 的写法风格。
一个具体的例子比十句描述更精确——它包含了命名风格、错误处理方式、导入方式、类型声明方式等你可能说不完的细节。
技巧五:控制对话长度
当一次对话超过 10 轮之后,AI 对早期信息的记忆开始模糊。
正确做法:每完成一个完整子任务后,开新对话。在新对话开头简要交代背景:
我正在给录音功能加波形可视化。useRecorder hook 已经完成(在 src/js/hooks/useRecorder.ts)。
现在需要加一个 useWaveform hook,接收 MediaStream,用 AnalyserNode 输出波形数据。
技巧六:Rules 文件是"持久化的上下文"
.trae/rules/project_rules.md 的本质是:把你每次都要重复说的话写下来,让 AI 每次自动读取。
常见的持久化内容:
- lint / typecheck 命令
- 技术栈约束(用 MobX 不用 Redux、用 antd 不用 Material UI)
- 命名规范
- 目录结构
- 业务概念解释
- AI 行为约束(不自动 commit、不加注释)
技巧七:利用 git 作为上下文来源
看看最近3次commit改了什么 → git log -3 --oneline
看具体改了哪些代码 → git diff HEAD~1 HEAD
看某个文件的修改历史 → git log --oneline -10 -- path/to/file
让 AI 读 git diff 来理解"最近发生了什么",比你口述更准确。
上下文的"信噪比"模型
把上下文想象成无线电信号:
┌──────────────────────────────────────────────┐
│ │
│ 信号(Signal):与当前任务直接相关的信息 │
│ ────────────── │
│ • 要修改的文件和相关函数 │
│ • 类型定义和接口 │
│ • 修改的原因和背景 │
│ • 参考的代码风格样例 │
│ │
│ 噪声(Noise):不相关但占据上下文的信息 │
│ ────────────── │
│ • 不相关的大段代码 │
│ • 已经解决的历史问题 │
│ • 对话中的闲聊 │
│ • 重复的信息 │
│ │
│ 信噪比 = Signal / (Signal + Noise) │
│ │
│ 信噪比越高 → AI 输出质量越高 │
│ │
└──────────────────────────────────────────────┘
你的目标是最大化信噪比:提供尽量多的有效信息,同时排除无关干扰。
反模式 vs 正确做法
反模式一:过度依赖 AI 自行搜索
差:帮我修一下行泊切换的 bug(什么其他信息都不给)
AI 要先搜索整个代码库理解什么是"行泊切换",搜索到几十个文件,然后猜哪个是相关的。
好:行泊切换通过 render_ws_data.js 中处理 PAPStatusOut 消息触发,
会调用 layoutStore.updateDriveModeFromBack 来切换布局。
现在 PAPStatusOut 的处理被删了,帮我加回来。
反模式二:信息海啸
差:(一次性粘贴3个文件共500行代码)
这三个文件有个问题,帮我看看
好:src/js/store/layoutStore/index.ts 第240行的 updateDriveModeFromBack 方法中,
papStatus === 2 应该改成 papStatus === EDriveMode.Parking,
类型定义在 types.ts 的 EDriveMode 枚举中。
反模式三:不给验证标准
差:帮我优化一下这个组件的性能
好:这个组件渲染时间从 Chrome DevTools Performance 看是 120ms,
主要瓶颈在 canvas 重绘和 TypedArray 频繁创建。
目标是降到 30ms 以内。
实战练习
练习 1:上下文精简
找一个你之前和 AI 对话的记录(如果有的话),分析:
- 哪些信息是有效的"信号"?
- 哪些是多余的"噪声"?
- 如果重新来一次,你会怎么精简提示?
练习 2:文件打开策略
在你的项目中选一个跨 3 个以上文件的修改任务。尝试两种方式:
- 方式 A:什么文件都不打开,直接描述任务
- 方式 B:提前打开 2-3 个最相关的文件,然后描述同样的任务
对比两次 AI 输出的质量差异。
练习 3:Rules 文件建设
从零开始写一份 .trae/rules/project_rules.md。规则来源:
- 看你项目的
.eslintrc、.prettierrc、tsconfig.json,提取关键约定 - 看
package.json的scripts和dependencies,提取技术栈信息 - 回忆过去 AI 输出不符合预期的场景,把你的纠正写成规则
目标:写完后让一个新人(或新的 AI 对话)仅凭这份 rules 就能写出符合项目规范的代码。
练习 4:git 上下文
挑一个最近的 bug,尝试只通过让 AI 读 git log 和 git diff 来定位问题根因。评估:
- AI 是否能准确定位到有问题的 commit?
- 你需要额外提供多少信息才能补齐上下文?
思考题
上下文窗口与策略:假设 AI 的上下文窗口只有 4K tokens(约 3000 字),你会如何分配——多少给背景描述、多少给代码、多少给指令?如果窗口扩大到 128K,你的策略会变吗?
隐式上下文的双刃剑:IDE 自动注入当前打开的文件作为上下文。有没有"打开了错误的文件导致 AI 被误导"的情况?你能想到例子吗?
团队知识库:如果整个团队都在用 AI 辅助开发,Rules 文件应该由谁来维护?应该包含哪些内容不应该包含哪些内容?Rules 文件会不会变得越来越臃肿?
上下文管理是否可以自动化:有没有可能让 AI 自己判断需要什么上下文?比如你只说"修复行泊切换 bug",AI 能自动找到所有相关文件和 git 历史。这种模式的上限和风险是什么?
多轮对话 vs 单轮对话:有人主张"每次新开对话",有人主张"在一个长对话中持续交互"。各有什么优劣?什么场景下该用哪种?