知识预览(Knowledge Priming)(读书笔记)
作者: Rahul Garg 日期: 2026年2月24日
AI编码助手默认使用其训练数据中的通用模式。我建议将项目上下文视为基础设施——在每次会话之前为模型提供预置的版本化文件——而不是依赖临时的复制粘贴。这本质上是手动RAG(检索增强生成),我相信它从根本上改变了AI生成代码的质量。
Rahul Garg
Rahul是Thoughtworks的首席工程师,位于印度古尔冈。他热衷于通过DDD和整洁架构构建可维护软件的技艺,并探索AI如何帮助团队实现工程卓越。
本文是系列文章的一部分:减少AI辅助开发中摩擦的模式
目录
- 默认行为问题
- 知识层级
- 知识预览是什么样子的
- 前后对比
- 预览文档的剖析
-
- 架构概览
-
- 技术栈和版本
-
- 精选知识来源
-
- 项目结构
-
- 命名约定
-
- 代码示例
-
- 要避免的反模式
-
- 预览作为基础设施,而非习惯
- 常见陷阱
- "太多"陷阱
- 保持预览文档的时效性
- 真实案例
- 权衡和限制
- 结论
当我入职新开发者时,我不会只是让他们看代码库然后说"去吧"。我会引导他们了解我们的约定。我会向他们展示我们认为好的代码示例。我会解释我们为什么做出某些架构选择——为什么我们使用Fastify而不是Express,为什么服务是函数式的而不是基于类的,为什么验证发生在路由级别。只有在这个上下文设置之后,我才期望他们能够贡献符合要求的代码。
AI编码助手也需要同样的入职培训。
许多开发者在使用AI助手时会经历一种可以称为"挫败循环"的体验:生成代码,发现它不适合代码库,带着修正重新生成,重复直到放弃或接受大量修改的输出。我开始相信这种摩擦不是源于AI能力,而是源于一个缺失的步骤——我们在没有首先分享AI所需上下文的情况下就要求AI做出贡献。
本文探讨了我称之为知识预览的做法——在要求AI生成代码之前,与其分享精选的项目上下文。
核心见解很简单:AI助手就像非常有能力但完全没有上下文的协作者。他们可以比任何人类工作得更快,但他们不了解特定项目的约定、约束或历史。没有上下文,他们默认使用可能适合也可能不适合的通用模式。
默认行为问题
以下是在没有预览的情况下要求AI生成代码时通常会发生的情况:
请求: "创建一个处理身份验证的UserService"
AI生成200行代码,使用:
- Express.js(项目使用Fastify)
- 存储在localStorage中的JWT(项目使用httpOnly cookies)
- utils/auth.js辅助函数(约定是lib/services/)
- 基于类的语法(代码库是函数式的)
- 过时的bcrypt API(项目使用最新版本)
代码可以工作。它在语法上是正确的。它甚至可能通过基本测试。但它对代码库来说完全错误。
为什么?因为AI默认使用其训练数据——数百万个存储库、教程和Stack Overflow答案的混合体。它生成的是"互联网的平均"解决方案,而不是特定团队的正确解决方案。
这正是如果我在没有任何入职培训的情况下要求新员工在第一天编写代码时会发生的事情。他们会利用他们之前的经验——这些经验可能符合也可能不符合我们的约定。
知识层级
我发现将AI知识按优先级分为三层是有帮助的:
- 训练数据(最低优先级): 数百万个存储库、教程、通用模式——通常已过时。这是"互联网的平均值"。
- 对话上下文(中等优先级): 当前会话中讨论的内容,AI最近看到的文件。这在长对话中会逐渐淡化。
- 预览文档(最高优先级): 明确的项目上下文——架构决策、命名约定、特定版本和模式。当提供这些时,它们会覆盖通用默认值。
层级很重要。当提供预览文档时,指令本质上是:"忽略通用互联网模式。这是这个项目的工作方式。"根据我的经验,AI确实会听从。
从技术上讲,这是手动RAG(检索增强生成)——用高价值的项目特定标记填充上下文窗口,以覆盖较低优先级的训练数据。就像新员工的先前习惯一旦被解释就会被明确的团队约定覆盖一样,AI的训练数据默认值也会让位于明确的预览。
这有一个机械原因使其有效。Transformer模型通过注意力机制处理上下文,该机制实际上作为一个有限的预算运行——上下文窗口中的每个标记都在竞争对模型输出的影响。当窗口充满通用训练数据模式时,模型会从它看到的所有内容的平均值中提取。当它充满特定的、高信号的项目上下文时,这些标记会吸引更多的注意力权重,并将生成引导到重要的模式。这就是为什么策划比数量更重要:一个专注的预览文档不仅仅是添加上下文,它改变了模型关注的内容的平衡。
知识预览是什么样子的
知识预览是在要求AI生成代码之前,与其分享精选的文档、架构模式和版本信息的做法。
把它想象成新员工的入职资料包:
- "这是技术栈和版本"
- "这是代码的结构方式"
- "这是命名约定"
- "这是这个代码库中好代码的示例"
前后对比
没有预览,对UserService的请求可能会产生Express.js、基于类的代码、错误的文件路径和过时的API——需要45分钟的修复或完全重写。
有了预览,相同的请求可能会产生Fastify、函数式模式、正确的文件路径和当前API——只需要5分钟的审查和微调。
我不能声称这是一个经过验证的发现,但推理似乎是合理的:明确的上下文应该覆盖通用默认值。我自己的实验一直令人鼓舞。
预览文档的剖析
一个好的预览文档不是大脑倾倒。它是一个精选的、结构化的指南,给AI提供它确切需要的东西——不多也不少。
我建议七个部分。每个部分都反映了我在入职人类同事时会引导的内容:
1. 架构概览
我告诉新员工: "让我先解释大局。"
大局。这是什么类型的应用程序?主要组件是什么?它们如何交互?
架构概览
这是一个基于微服务的电子商务平台。
- API网关:处理路由、身份验证、速率限制
- 用户服务:身份验证、个人资料、偏好设置
- 订单服务:购物车、结账、订单历史
- 通知服务:电子邮件、短信、推送通知
服务通过异步消息队列(RabbitMQ)通信。 每个服务拥有自己的数据库(PostgreSQL)。
2. 技术栈和版本
我告诉新员工: "这是我们的技术栈——注意版本特定的API。"
特异性很重要。版本号很重要——API在版本之间会发生变化。
技术栈
- 运行时: Node.js 20.x(LTS)
- 框架: Fastify 4.x(不是Express)
- 数据库: PostgreSQL 15,使用Prisma ORM 5.x
- 身份验证: JWT,使用httpOnly cookies(不是localStorage)
- 测试: Vitest + Testing Library(不是Jest)
- 验证: Zod schemas(不是Joi)
3. 精选知识来源
我告诉新员工: "在你搜索互联网之前,这里是我们思维方式的文档和博客。从这里开始。"
每个团队都有值得信赖的来源:他们实际阅读的官方文档,还有影响他们架构的博客文章,解释清楚事物的教程,捕获文档永远不会捕获的教训的文章。这些共同构成了团队的共享心智模型。
当AI首先咨询精选来源——而不是其庞大的、通用的训练数据——输出会更快地保持一致。团队的思维已经融入其中。
精选知识
官方文档
| 主题 | 来源 | 我们信任它的原因 |
|---|---|---|
| Fastify路由 | https://fastify.dev/docs/latest/Guides/Getting-Started | 官方,匹配我们的v4.x |
| Prisma关系 | https://www.prisma.io/docs/orm/prisma-schema/data-model/relations | 模式权威 |
我们关注的博客和文章
| 概念 | 来源 | 它如何影响我们的思维 |
|---|---|---|
| 错误处理模式 | [团队审查的博客URL] | 比官方文档更清晰,实用示例 |
| 测试策略 | [团队审查的博客URL] | 影响了我们的测试架构 |
内部参考
| 主题 | 路径 | 它捕获的内容 |
|---|---|---|
| 错误约定 | docs/error-handling.md | 我们的特定模式 |
| API设计决策 | docs/adr/003-api-versioning.md | 决策理由 |
保持精选——而非全面。5到10个真正影响团队工作方式的来源。
4. 项目结构
我告诉新员工: "这是东西所在的地方。文件放置很重要。"
东西所在的地方。文件放置很重要。
src/
├── lib/
│ ├── services/ # 业务逻辑(UserService、OrderService)
│ ├── repositories/ # 数据库访问层
│ ├── schemas/ # Zod验证schemas
│ └── utils/ # 纯工具函数
├── routes/ # Fastify路由处理程序
├── middleware/ # 身份验证、日志记录、错误处理
├── types/ # TypeScript类型定义
└── config/ # 环境特定配置
5. 命名约定
我告诉新员工: "这是命名约定。一致性比个人偏好更重要。"
明确的约定防止风格漂移。
命名约定
- 文件: kebab-case(
user-service.ts,而不是UserService.ts) - 函数: camelCase,动词优先(
createUser、`validateToken``) - 类型/接口: PascalCase,带有描述性后缀(
UserCreateInput、AuthResponse) - 常量: SCREAMING_SNAKE_CASE(
MAX_RETRY_COUNT) - 布尔变量: is/has/can前缀(
isActive、hasPermission)
6. 代码示例
我告诉新员工: "这是我们认为好代码的示例。遵循这个模式。"
展示,而不仅仅是讲述。包含2-3个代码库中"好代码"的示例。
// lib/services/user-service.ts
import { prisma } from '../db/client'
import { UserCreateInput, UserResponse } from '../types/user'
import { hashPassword } from '../utils/crypto'
export async function createUser(input: UserCreateInput): Promise<UserResponse> {
const hashedPassword = await hashPassword(input.password)
const user = await prisma.user.create({
data: {
...input,
password: hashedPassword,
},
select: {
id: true,
email: true,
createdAt: true,
// 永远不返回密码
},
})
return user
}
注意: 服务是纯函数,不是类。它们在需要时通过参数接收依赖项。
7. 要避免的反模式
我告诉新员工: "这是不要做的事情。我们通过艰难的方式学到了这些教训。"
告诉AI不要做什么。这可以防止常见错误。
反模式(不要使用)
- 基于类的服务(使用函数式方法)
- Express.js模式(此项目使用Fastify)
- 将JWT存储在localStorage中(使用httpOnly cookies)
- 使用any类型(始终定义适当的类型)
- 将业务逻辑放在路由处理程序中(使用服务)
- 原始SQL查询(使用Prisma ORM)
预览作为基础设施,而非习惯
我认为最强大的方法是将预览视为基础设施而不是习惯。
不要在每次会话开始时手动粘贴上下文(一种会消退的习惯),而是将预览文档存储在存储库中,在那里它自动应用:
# Cursor
.cursor/
├── rules # 始终开启的项目上下文(自动加载)
└── commands/
└── priming.md # 可通过@priming引用
# GitHub Copilot
.github/
└── copilot-instructions.md # 工作区级指令
# Claude Projects
将预览文档上传到项目知识库
为什么基础设施胜过复制粘贴:
- 版本控制:更改可审计和可审查
- 自动应用:每次会话无需手动复制粘贴
- 团队范围的一致性:每个人都获得相同的上下文
- 可PR审查的更改:治理内置到现有工作流中
这将预览从"个人生产力黑客"转变为"团队基础设施"。这是一种会消退的习惯和一种持续的做法之间的区别。
就像新员工的入职材料作为组织资产维护——而不是每次即兴创作——预览文档应该被视为一等公民。
常见陷阱
在我自己的实验中,我观察到了几种失败模式:
| 陷阱 | 替代方案 |
|---|---|
| 信息太多:20多页的文档让AI不知所措并稀释焦点 | 保持1-3页的基本上下文 |
| 太模糊:"现代最佳实践"告诉AI什么都没有 | 要具体:"Fastify 4.x、Prisma 5.x、函数式服务" |
| 没有示例:描述模式而不展示它们 | 包含2-3个代码库中的真实代码片段 |
| 内容过时:6个月前的预览文档 | 每月审查和更新,或在发生重大更改时 |
| 缺少反模式:告诉AI要做什么但不告诉要避免什么 | 明确列出不需要的模式 |
"太多"陷阱
一个错误是将预览文档视为综合文档。它不是。它是AI的备忘单——生成一致代码所需的最小上下文。
如果预览文档超过3页,请考虑:
- AI生成服务需要所有这些吗?
- 详细文档可以放在其他地方并只是被引用吗?
- 是否包含了很少出现的边缘情况?
AI总是可以提出后续问题。从专注开始,仅在需要时扩展。
保持预览文档的时效性
文档会腐烂。每个团队都有过时维基和陈旧README的墓地。如何防止预览文档加入它们?
将其视为代码,而不是文档:
- 存储在repo中:
docs/ai-priming.md - 更改需要PR审查(像任何代码更改一样)
- 技术负责人负责季度审查(与依赖更新一致)
引用,不要重复:
- 对于身份验证决策:"参见ADR-007"
- 对于API契约:"参见/api/schema.yaml中的OpenAPI规范"
- 对于部署模式:"参见运维手册"
更新触发器:
| 触发器 | 操作 |
|---|---|
| 新框架版本 | 更新技术栈部分 |
| 新架构模式 | 添加代码示例 |
| 重复的AI错误 | 添加反模式 |
| 重大重构 | 审查结构部分 |
过时的预览文档比没有更糟糕——它教给AI过时的模式。但是,一个存在于repo中、像代码一样被审查的预览文档,通过设计保持最新。
真实案例
以下是我参与的一个项目的精简预览文档:
# Acme API - 预览上下文
## 快速概览
用于库存管理的B2B SaaS API。多租户、事件驱动。
## 技术栈
- Node.js 20、Fastify 4、TypeScript 5
- PostgreSQL 15 + Prisma 5(通过tenantId多租户)
- 身份验证:Clerk(外部)、JWT验证中间件
- 队列:BullMQ + Redis用于异步作业
- 测试:Vitest
## 可信来源
### 文档
- Fastify:https://fastify.dev/docs/latest
- Prisma多租户:https://www.prisma.io/docs/orm/prisma-client/queries/multi-tenancy
### 我们关注的博客
- BullMQ模式:[团队审查的队列处理博客]
### 内部
- ADR:docs/adr/(架构决策)
- 错误处理:docs/error-conventions.md
## 结构
src/
├── modules/ # 功能模块(users/、products/、orders/)
│ └── [module]/
│ ├── service.ts # 业务逻辑
│ ├── routes.ts # HTTP处理程序
│ ├── schema.ts # Zod schemas
│ └── types.ts # TypeScript类型
├── shared/ # 横切关注点(db、auth、queue)
└── config/ # 环境配置
## 模式
- 函数式服务(无类)
- 所有查询包含`where: { tenantId }`(多租户)
- 使用Zod在路由级别验证
- 错误作为带有状态码的`AppError`抛出
## 反模式
- 服务不使用类
- 不使用原始SQL(使用Prisma)
- 路由中没有业务逻辑
- 没有硬编码的tenantId
## 示例服务
[包含代码库中的一个简短示例]
注意: 它不到50行。这就是目标。专注、具体、可操作。
权衡和限制
这种方法并非没有成本:
- 前期努力: 创建和维护预览文档需要时间
- 收益递减: 对于非常简单的任务,开销可能不合理
- 过时上下文风险: 过时的预览文档可能比没有更糟糕
- 不是保证: 即使有好的预览,AI有时也会产生错误的输出
我假设回报对于非平凡工作最大——特别是跨越多个会话或涉及团队协调的工作。对于快速工具函数,手动修正可能比维护上下文基础设施更快。
结论
知识预览本质上是手动RAG:在要求代码生成之前,用高价值、项目特定的信息填充AI的上下文窗口。假设很简单——明确的上下文应该覆盖通用默认值,产生适合代码库而不是"互联网平均值"的输出。
我目前的想法是,关键转变是将上下文视为基础设施(repo中的版本化文件)而不是习惯(在会话开始时复制粘贴)。基础设施持续;习惯消退。
这是其他一切的基础。当AI已经理解架构时,设计优先的对话会更有成效。当AI知道约定时,自定义命令会更好地工作。预览的投资会复合。
重大修订
2026年2月24日:首次发布
#tags #AI #AI辅助开发 #知识管理 #代码生成 #RAG #最佳实践