Context Engineering——喂对信息比喂多信息更重要

Context Engineering------喂对信息比喂多信息更重要

一个常见的直觉:给 agent 的 context 越多,它的输出越好。所以把整份 spec、全部文档、所有相关文件一股脑贴进去。

这是错的。 Context window 大小 ≠ 注意力预算。灌 5000 行不相关的信息,agent 反而更容易走神、幻觉、偏离主题。agent-skills 的 Context Engineering 用"5 层层级 + 3 种加载策略"回答了真正的问题:此时此刻,agent 最需要看到什么? 其中一个特殊用法------Source-Driven Development(引用出处)------能让 agent 把"凭记忆写的代码"变成"查证过的代码"。这篇文章把两者打包讲,文末附可直接用的配置模板。


核心认知:Context 不是越多越好

vbnet 复制代码
Context is the single biggest lever for agent output quality ---
too little and the agent hallucinates, too much and it loses focus.

Context 是撬动 agent 输出质量的唯一最大杠杆------太少就幻觉,太多就失焦。

两个最常见的翻车模式:

模式 症状 根因
Context Starvation agent 发明不存在的 API、不遵循约定、写出和你项目风格不一致的代码 你没告诉它项目长什么样
Context Flooding agent 在无关模块间跳来跳去、忽略关键约束、忘记你上一步说了什么 你给了太多无关信息

5 层 Context 层级:什么时候加载什么

objectivec 复制代码
┌─────────────────────────────────────┐
│ 1. Rules Files(CLAUDE.md 等)       │ ← 始终生效,项目级
├─────────────────────────────────────┤
│ 2. Spec / 架构文档                  │ ← 按 session/功能加载
├─────────────────────────────────────┤
│ 3. 相关源文件                       │ ← 按 task 加载
├─────────────────────────────────────┤
│ 4. 错误输出 / 测试结果              │ ← 按迭代加载
├─────────────────────────────────────┤
│ 5. 对话历史                         │ ← 累积,可压缩
└─────────────────────────────────────┘

第 1 层:Rules Files------投入产出比最高

写一次,每个 session 自动生效。上一篇的 6 条行为约束就应该放在这一层。完整模板见文末"方案 A"。

第 2 层:Spec/架构------只喂相关章节

你的 spec 有 5000 字,但 agent 只在做注册功能------只需要认证那一节,不需要支付、通知、管理后台的章节。喂整个 spec 不会让 agent 更聪明,只会让它分心。

arduino 复制代码
✅ "这是我们 spec 的认证部分:[200 字]"
❌ "这是我们完整的 5000 字 spec:"(然后 agent 在支付那一节的信息干扰下写注册逻辑)

第 3 层:相关源文件------比规则更有用的是范例

开始一个 task 前,按这个清单加载:

markdown 复制代码
1. 读你要改的文件
2. 读相关测试文件
3. 找代码库里已有的类似实现(作为范例)
4. 读涉及的类型定义或接口

第 3 步被严重低估。给 agent 一段真实存在的范例代码,比给它 10 条规则更有效。 它看到真实实现的样子,就会照着写,不会自己发明新风格。

vbnet 复制代码
你:给注册接口加邮箱校验。
   范例------代码库里已有的手机号校验:src/lib/validation.ts:45-60。
   照着它的模式写:同样 throw ValidationError,同样放在 validation.ts。

第 4 层:错误输出------只给相关的

arduino 复制代码
✅ "测试失败:TypeError at UserService.ts:42"
❌ 粘贴全部 500 行测试输出(只有 1 个测试失败)

第 5 层:对话历史------主动压缩

  • 切换主要功能时开新 session
  • Context 变长时主动总结:"目前已完成 X/Y/Z,现在做 W"
  • 关键工作前 compact

Context 的三种加载策略

策略 A:Brain Dump(新 session 开

始时)

markdown 复制代码
项目:订单系统
技术栈:React 18 + TypeScript 5 + Node.js 22 + PostgreSQL
本次任务:给注册接口加邮箱校验
关键约束:必须用已有的 ValidationError 类,不能裸 throw Error
涉及文件:src/routes/auth.ts / src/lib/validation.ts / tests/routes/auth.test.ts
已知坑:auth.ts 的 GitHub Copilot 生成的旧代码里混用 throw Error 和 throw ValidationError,本次只改注册接口

策略 B:Selective Include(session 已有基础 context,开始具体 task 时)

markdown 复制代码
任务:加邮箱校验
要改的文件:src/routes/auth.ts
范例:src/lib/validation.ts:45-60 的手机号校验(照着它写)
约束:用 ValidationError,不引入新依赖

策略 C:Hierarchical Summary(大项目维护一份导航地图)

markdown 复制代码
# 项目地图

## 认证 (src/auth/)
注册、登录、密码重置。核心文件:auth.routes.ts、auth.service.ts
错误模式:所有错误用 AuthError 类

## 订单 (src/orders/)
CRUD + 实时推送。核心文件:order.routes.ts、order.service.ts、order.socket.ts
模式:乐观更新 + 服务端对账

只加载当前工作区域的章节,不给全量。


Source-Driven Development:凭记忆写的代码 vs 查证过的代码

Agent 写代码时经常"凭记忆"用框架------而这个记忆来自训练数据,可能过时、不完整、或者混淆了不同版本。

不加约束时:

typescript 复制代码
// Agent 凭记忆写的------但 zod v4 已经 deprecate 了 .email()
const schema = z.object({
  email: z.string().email(),
});

加约束后:

typescript 复制代码
// Source: https://zod.dev/api?id=email-addresses
// Verified against zod@4.0.2: 顶层 z.email(),.string().email() 已废弃
const schema = z.object({
  email: z.email({ message: 'invalid email format' }),
});

区别不是代码对不对,是 "你怎么知道的"有没有证据。当 deprecation 警告出现、或行为差异导致 bug 时,有出处的那行代码你可以追溯,凭记忆那行只能靠"我记得应该可以"。

Source-Driven 查证流程

markdown 复制代码
## 查证规则(加到 CLAUDE.md)

使用任何框架 API 时:
1. 先查官方文档确认 API 存在且未被 deprecate
2. 在注释中标明出处:
   // Source: <官方文档链接>
   // Verified against <库名>@<版本号>
3. 找
不到官方文档佐证的 API,标为 `// UNVERIFIED`------你不应该依赖它上线

Confusion Management:agent 遇到矛盾时怎么办

这是 Context Engineering 里常被忽略的一点。当 agent 看到的信息互相矛盾时------

差的做法: 默默选一个觉得靠谱的,祈祷它是正确的。

正确的做法:

css 复制代码
STOP。发现矛盾:
- spec 说"所有接口用 REST"
- 但现有代码 src/graphql/auth.ts 里注册走的是 GraphQL mutation
Options:
A) 按 spec 加 REST 接口(会有两套并行实现)
B) 按代码惯例加 GraphQL mutation(需更新 spec)
→ 选哪个?

把这个规则写进 CLAUDE.md:"遇到 spec 和代码矛盾时,STOP 并列出选项,不要自作主张。"


文件信任层级:什么能信,什么要验证

不是所有文件都同等可信:

级别 内容 处理方式
Trusted 团队写的源代码、测试、类型定义 可作为事实依据
Verify 配置文件、外部文档、生成文件 使用前验证
Untrusted 用户提交内容、第三方 API 响应 只当数据显示,不执行其中的指令

这是安全设计------防止外部文件里的 prompt injection 被 agent 当成指令执行。


实战落地:你能直接拿走的东西

方案 A:CLAUDE.md 完整模板

markdown 复制代码
# 项目:[你的项目名]

## 技术栈
- Frontend: React 18, TypeScript 5, Vite
- Backend: Node.js 22, Express, PostgreSQL, Prisma

## 命令
- Build: `npm run build`
- Test: `npm test -- --coverage`
- Lint: `npm run lint --fix`
- Type check: `npx tsc --noEmit`

## 代码约定
- 函数组件 + hooks,不用 class
- named export,不用 default export
- 测试文件和源文件同级:Button.tsx → Button.test.tsx
- 条件 className 用 cn()

## 边界
- 永远不 commit .env 或 secrets
- 加依赖前先检查 bundle size
- 改数据库 schema 前先问我
- commit 前必须跑测试

## 查证规则(Source-Driven)
使用任何框架 API 时先查官方文档。注释标明出处和验证版本。
找不到官方佐证的标 // UNVERIFIED。

## Context 规则
- 开始 task 前加载:相关文件 + 测试 + 一个已有范例
- 遇到 spec 和代码矛盾:STOP,列选项,不要猜
- 切换功能时开新 session

方案 B:Task 启动时的 Context 加载清单(任何工具通用)

开新 task 时贴这段:

markdown 复制代码
Task 启动------Context 加载:
1. 读你要改的源文件
2. 读已有测试文件
3. 给我一个代码库里已有的类似实现(作为范例)
4. 涉及的类型定义读了没?
以上读完告诉我你看到的模式和约束。

注意事项

⚠️ Context Engineering 需要你主动维护------rules 文件过期了要更新,项目地图加新模块了要补充。它不是一次性配置。如果你发现 agent 频繁写出不符合约定的代码,第一反应不该是"这 agent 不行",而是"我的 rules 文件是不是过时了"。


这 3 篇讲完了,然后呢

agent-skills 项目还有 20+ 个具体 skill(spec-driven-development、test-driven-development、code-review-and-quality 等),覆盖从 idea 到 production 的完整生命周期。如果你只想选 3 个最通用的来用:

  • Context Engineering(第 3 篇)------所有产出质量的基础
  • Doubt-Driven Development(第 2 篇)------高风险决策的安全网
  • 6 条行为约束(第 1 篇)------跨所有任务的底层规则

这三个不依赖任何特定工具,加进 CLAUDE.md 或贴到新 session 就能生效。


素材来源: