CodeBuddy 学习(4):上下文管理

0 阅读11分钟

CodeBuddy 学习(4):上下文管理

一、概述:上下文是 AI 理解你的唯一窗口

1.1 为什么上下文管理如此重要

对话式 AI 编程的质量不取决于 AI 模型有多强——取决于你给了它什么信息。AI 不会主动"了解"你的项目,它只在上下文中看到你主动投喂的内容。

1.2 金发姑娘原则(Goldilocks Principle)

状态信息量后果
信息不足太少AI 瞎猜,生成代码与项目格格不入,不知道你用什么框架
信息过多太多AI 混乱,抓不住重点,输出质量下降
信息精准刚刚好AI 高效,代码直接可用

结论:精准投喂是关键——不太少、不太多、刚刚好。


二、上下文的四个层级

层级来源控制方式优先级说明
系统层Rules 文件编辑 .codebuddy/rules/最低全局生效,对话启动时自动加载
用户层用户偏好设置用户级 Rules 配置个人习惯,跨项目共享
项目层项目规则项目根目录配置团队约定,项目内共享
对话层@ 引用 + 直接指令你主动选择最高本章核心——你随时可控

重点:对话层优先级最高——你通过 @ 主动注入的上下文,可以覆盖任何层级设置。


三、@ 引用的五种用法

3.1 原理讲解

@ 引用是 CodeBuddy 的上下文注入指令。每次你使用 @ 引用某个实体,CodeBuddy 会:

  1. 读取该实体(文件、目录、终端输出等)的完整内容。
  2. 将内容序列化为文本。
  3. 追加到当前消息的上下文窗口中,随问题一起发送给 AI。

关键特性

  • 一次性:只在当前消息有效,下一条消息若不再次引用,AI 就不再知道文件内容。
  • 实时性:@terminal 引用的是最近一次执行的真实输出,而非缓存。
  • 手动触发:必须手动输入 @ 符号,粘贴文本中的 @ 不会生效。
引用类型写法说明典型用途
@Files@file注入文件的完整内容让 AI 分析、重构或基于特定文件生成代码
@Folders@folder注入目录结构(不阅内容)了解项目组织,规划新文件位置
@Terminal@terminal注入最近一次终端输出排错、分析运行日志、理解报错信息
@Docs@docs注入文档或外部 API 参考让 AI 参照文档风格或 API 签名
@Code@code注入选中的代码片段精准分析某段代码,避免注入整个文件

四、示例一:精确投喂——排错场景

4.1 场景描述

运行 node server.js 时报错 Cannot find module './config',需要排查原因。

4.2 完整操作流程

Step 1:在 CodeBuddy 内置终端中执行命令,获取完整报错输出。

node server.js

终端输出:

Error: Cannot find module './config'
Require stack:
- /Users/project/src/server.js:3:20
- /Users/project/index.js:1:14
    at Module._resolveFilename (node:internal/modules/cjs/loader:xxx)
    at Module._load (node:internal/modules/cjs/loader:xxx)
    ...

Step 2:在对话框中组合输入:

@file src/server.js
@terminal
请分析终端报错的原因,并给出修复方案。

4.3 预期输出

AI 会同时看到 server.js 的源代码和终端报错,给出根因分析:

原因分析:

server.js 第 3 行:
  const config = require('./config');

Node.js 在 server.js 同级目录(src/)下找不到名为 config 的模块。
可能的原因:

1. config 文件不存在 —— 最常见的情况。
   检查 src/ 下是否有 config.js / config.json / config/index.js。

2. config 文件存在但路径写错了 —— 例如文件叫 configs.js 但 require 的是 config3. 配置文件在上级目录 —— require 应该是 require('../config') 而非 require('./config')。

修复方案:
# 在终端中确认文件位置
ls src/config*

# 根据结果修改 server.js 中的 require 路径

4.4 调试过程

场景一:@terminal 引用的不是最新输出

现象:使用 @terminal 后,AI 分析的是旧的报错信息,和当前问题无关。
原因:在 CodeBuddy 外部终端(系统 Terminal)执行命令不会更新 @terminal 引用。
排查:
  1. 确认是在 CodeBuddy 内置终端(IDE 底部面板)中执行的命令。
  2. 重新在内置终端中执行命令,再引用 @terminal。
修复:在内置终端重新执行命令后,立即引用 @terminal 提问。

场景二:抱怨 AI 没看到我引用的文件内容

现象:你用了 @file,但 AI 的回复和文件内容不匹配。
原因排查:
  1. @ 符号是手动输入的吗?
     粘贴文本中的 @ 不生效——必须手动在输入框中输入。
  2. 文件名路径正确吗?文件在当前项目中吗?
  3. 文件内容是否太长,被上下文窗口截断?
排查步骤:
  1. 重新手动输入 @file,从弹出的文件列表中选择目标文件(不要手动敲路径)。
  2. 确认文件在 IDE 左侧文件树中可见。
  3. 如果文件超过 2000 行,改用 @code 只引用关键片段。
修复:确保 @ 引用是通过交互菜单选择的,而非手动输入路径。

五、示例二:分层投喂——按流水线递进

5.1 原理讲解

分层投喂的核心理念:每一步只引用上一步的产出,而不是把所有东西一股脑扔给 AI

这种方法的好处:

  • 精简上下文:每个对话只包含当前步骤所需的最小信息。
  • 减少幻觉:AI 不会因为看到太多无关代码而混淆。
  • 可追溯:出问题时,很容易定位是哪一步的上下文偏差导致的。

5.2 四步流水线

Step 1: 产品文档 → 生成类型定义
  ↓
Step 2: 类型定义 → 生成 API 接口
  ↓
Step 3: API 接口  → 生成 Hook 封装
  ↓
Step 4: Hook 封装 → 生成页面组件

5.3 完整可运行示例

Step 1:产品文档 → 类型定义

操作

根据产品需求文档,生成 TypeScript 类型定义:
- 商品:id, name, price, category, stock, imageUrl
- 订单:id, items(商品列表), totalAmount, status, createdAt
- 用户:id, name, email, avatar
请只输出类型文件内容。

预期输出src/types/models.ts):

// 商品类型
export interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  stock: number;
  imageUrl: string;
}

// 订单项
export interface OrderItem {
  productId: number;
  productName: string;
  price: number;
  quantity: number;
}

// 订单状态
export type OrderStatus = 'pending' | 'paid' | 'shipped' | 'completed' | 'cancelled';

// 订单类型
export interface Order {
  id: number;
  items: OrderItem[];
  totalAmount: number;
  status: OrderStatus;
  createdAt: string;
}

// 用户类型
export interface User {
  id: number;
  name: string;
  email: string;
  avatar: string;
}

Step 2:类型定义 → API 接口

操作(新建对话):

@file src/types/models.ts
基于 Product 类型,创建获取商品列表的 API 接口(mock 数据)。
返回分页结构,包含筛选参数(分类、搜索关键词)。
响应格式:{ code, data: { list, total, page, pageSize }, message }

Step 3:API 接口 → Hook 封装

操作(新建对话):

@file 上一步生成的 API 文件
创建 useProducts Hook:
- 封装 API 调用
- 返回 { data, loading, error, refresh }
- 支持自动请求和手动刷新

Step 4:Hook → 页面组件

操作(新建对话):

@file 上一步生成的 Hook 文件
创建 ProductList 页面组件:
- 使用 useProducts Hook
- 展示商品网格(卡片式布局)
- 加载态:骨架屏
- 空数据态:提示文案
- 错误态:重试按钮

5.4 调试过程

场景:Step 3 发现 Step 2 的 API 签名有问题

现象:写 Hook 时发现 API 返回的结构和预期不一样。
原因:Step 2 生成 API 时的上下文不足,签名理解偏差。
排查:Step 2 操作时没有 @file 引用类型文件,AI 凭描述猜测 API 签名。
修复(分层投喂的标准修复方式):
  1. 回到 Step 2 的对话。
  2. 用 @file 引用 Step 1 的类型文件,让 AI 修正 API 签名。
  3. 确认修正后重新进入 Step 3。
关键:每层只修自己的问题,不跨层修改。

六、四种上下文污染与排查

6.1 污染类型

污染类型表现后果排查信号
陈旧信息引用了已废弃的旧代码AI 生成兼容旧方案的代码生成代码用了旧 API 命名
噪声过多500 行文件全扔给 AI抓不住重点,质量急剧下降回复东拉西扯、不聚焦
矛盾信息前面说 REST 后面说 GraphQLAI 左右为难,前后不一致输出中两种方案交替出现
跨任务污染一个对话讨论 3 个功能AI 把功能搞混回复中串入了其他任务的内容

6.2 排查与修复

场景一:陈旧信息污染

现象:AI 生成的代码用了一个你三周前就改掉的函数名。
排查:
  1. 回忆你是否在早期对话中引用过那个旧函数。
  2. 检查当前对话是否从旧对话延续而来(AI 记得早期上下文)。
修复:
  1. 新建对话——切断历史上下文。
  2. 用最新的 @file 重新引用当前版本的代码。
  3. 必要时在 Rules 中维护一份"废弃列表",告诉 AI 哪些 API 已经不用了。

场景二:噪声过多污染

现象:你引用了整个 src/ 目录下的 5 个大文件,AI 的回复质量明显下降。
排查:统计当前消息中引用的文件总量(行数/字符数)。
修复(两种策略):
  策略 A(精确投喂):用 @code 只引用与当前任务相关的 50-100 行代码。
  策略 B(分层递进):只引用上一步产出(类型文件),而不是整个实现。
急救手段:立刻新建对话 + 只引用最关键的 1-2 个文件。

场景三:跨任务污染

现象:同一个对话里,你问了"创建订单页面",又问了"修复登录 Bug",
     又问了"优化数据库查询",AI 开始把登录 Bug 的修复思路用到订单页面上。
排查:回顾对话历史,是否包含 3 个以上不相关的任务。
修复:牢记法则——**一个任务一个对话**。三个任务 = 三个独立对话。

七、最小上下文原则

7.1 核心公式

输出质量 = 相关性 × (1 / 噪声量)

减噪就是提质——只给 AI 完成当前任务所需的最少信息

7.2 两条黄金法则

法则内容说明
法则一一个任务一个对话避免跨任务污染
法则二类型文件优先于实现文件接口定义优先于内部逻辑

7.3 急救手段

当 AI 输出混乱时,三步急救:

  1. 缩减上下文:只保留最关键的 1 个 @ 引用。
  2. 重开对话:新建对话,切断污染历史。
  3. 明确需求:用一句话描述当前任务目标。

八、进阶技巧:预热与锚点

8.1 预热(Warm-up)

正式提需求前,先让 AI 认识你的项目:

操作

@folder src
这是一个 Next.js 14 + TypeScript + TailwindCSS 项目。
App Router 架构,shadcn/ui 组件库。
请确认你已经理解了项目结构。

效果:后续对话中,AI 对项目结构有基本了解,不需要每次都解释。

8.2 锚点(Anchor)

对话超过 10 轮后,AI 开始遗忘早期上下文。新任务开头设置锚点:

操作

回顾一下:类型文件在 src/types/,API 路由在 src/app/api/,
Hook 在 src/hooks/,组件在 src/components/。
现在开始新任务:创建 [功能描述]

效果:用一句话帮 AI 重新定位关键路径,避免遗忘导致的质量下降。


九、负面上下文:告诉 AI 不要做什么

9.1 原理讲解

有时候,告诉 AI 不要做什么比告诉它要做什么更有效。因为 AI 的"创作欲"可能会让它主动做你不需要的事情(如引入新依赖、修改接口签名、重构无关代码)。

9.2 示例对比

未给禁止项

"帮我优化这个组件"
→ AI 可能:重构 Props、引入新库、修改 CSS、重组目录结构
→ 结果:合入风险高,需要大量审查

给出禁止项

"帮我优化这个组件,约束:
- 不修改 Props 接口
- 不引入新的第三方库
- 不修改 CSS 类名
- 不改变组件对外行为"
→ AI 只做:拆分逻辑、提取子函数、优化变量名、添加 early return
→ 结果:变更聚焦,可直接合并

9.3 调试过程

场景:给了禁止项,AI 仍然违反

现象:你说"不要改 Props 接口",AI 还是改了。
原因:禁止项描述不够明确,或者与其他需求产生冲突。
排查:
  1. 检查禁止项是用什么语气写的——"请不要..." 对 AI 的约束力弱于 "禁止..."2. 检查是否有其他正向需求与禁止项冲突。
     (如既要"重构接口设计"又要"不要改接口"——这本身就是矛盾的)。
修复:
  - 用明确的否定词:"禁止修改""不允许引入""不得改动"。
  - 检查需求之间的一致性,消除逻辑冲突。

十、小结

知识模块核心要点
@ 引用五种用法:Files / Folders / Terminal / Docs / Code
四层上下文系统 → 用户 → 项目 → 对话,对话层优先级最高
金发姑娘原则不太少、不太多、刚刚好
四种污染陈旧信息 / 噪声过多 / 矛盾信息 / 跨任务
最小上下文核心公式:输出质量 = 相关性 × (1/噪声量)
分层投喂类型 → API → Hook → 页面,每步只引用上一步产出
预热 + 锚点用最小代价换最大输出稳定性
负面上下文告诉 AI 不要做什么,限制"创作欲"