Prompt Engineering for Next.js
同样的 AI 工具,不同的提示词,产出质量可能差 10 倍。Prompt Engineering 不是"说话的艺术",而是一套可复制的工程方法——明确任务、提供上下文、约束输出格式、拆分复杂步骤。本章专门针对 Next.js 全栈开发场景,提供经过验证的提示词模板和策略。
1. 提示词基本原则
1.1 为什么"帮我写一个 XX"是糟糕的提示词
❌ "帮我写一个登录页面"
AI 不知道:
- 用什么认证方案(Clerk? NextAuth? 自建?)
- 是 Server Component 还是 Client Component?
- 用什么 UI 库(shadcn/ui? Material UI? 手写?)
- 登录方式(邮箱密码? OAuth? Magic Link?)
- 登录后跳转到哪里?
- 错误处理怎么做?
这种提示词的问题是 缺少约束——AI 会按照它训练数据中最常见的模式生成代码,而这个模式大概率不符合你的项目。
1.2 CRAFT 提示词框架
针对编程场景,我总结了 CRAFT 框架:
| 要素 | 说明 | 示例 |
|---|---|---|
| Context | 项目背景和技术栈 | "这是一个 Next.js 15 App Router 项目" |
| Reference | 参考文件或模式 | "参考 @lib/actions/project.ts 的模式" |
| Ask | 明确的任务描述 | "创建用户邀请功能" |
| Format | 输出格式和约束 | "使用 Server Action,返回 { error?: string }" |
| Test | 验收标准 | "邀请链接 24 小时过期,同一邮箱不能重复邀请" |
✅ CRAFT 示例:
Context: 这是一个 Next.js 15 SaaS 项目,使用 Drizzle ORM + PostgreSQL,
Clerk 认证,多租户架构。
Reference: 参考 @lib/actions/project.ts 的权限检查模式,
使用 @lib/db/schema.ts 中的 invitations 表。
Ask: 实现团队邀请功能——管理员输入邮箱,系统发送邀请链接,
受邀者点击链接加入团队。
Format:
- Server Action 在 lib/actions/invitation.ts
- 邮件发送用 Resend
- 邀请页面在 app/invite/[token]/page.tsx
Test:
- 邀请链接 24 小时后过期
- 同一租户下不能重复邀请同一邮箱
- 受邀者注册后自动加入对应租户
- 只有 admin 角色可以发送邀请
1.3 上下文注入策略
AI 的输出质量 = f(提示词质量, 上下文质量)。上下文越精确,输出越贴合:
| 策略 | 何时使用 | 效果 |
|---|---|---|
| @file 精准引用 | 你知道要参考哪个文件 | ★★★★★ |
| @folder 目录引用 | AI 需要理解某个模块 | ★★★★ |
| @Codebase 搜索 | 你不确定相关代码在哪 | ★★★ |
| 复制粘贴代码片段 | 关键代码 + 错误信息 | ★★★★ |
| 描述架构 | 没有参考文件时 | ★★★ |
关键原则:给 AI 看代码,而不是描述代码。
❌ "我的项目用 Drizzle ORM,请按照我的风格写查询"
✅ "参考这个查询的风格:
@lib/db/queries/project.ts
给 users 表写一个按角色分页查询"
2. Next.js 专用提示词模板
2.1 Server Component 页面
创建一个 [页面名称] 页面。
技术要求:
- Server Component(不要加 'use client')
- 数据在组件内直接 await 查询(不要 useEffect)
- 使用 Suspense 包裹异步部分,提供 Skeleton fallback
- 分页使用 URL searchParams
- 参考 @app/(dashboard)/projects/page.tsx 的结构
功能:
- [具体功能列表]
文件位置:app/(dashboard)/[路径]/page.tsx
2.2 Server Action
创建一个 Server Action:[动作描述]
要求:
- 文件:lib/actions/[模块].ts
- 'use server' 声明
- 开头调用 requirePermission('[resource]:[action]')
- 输入用 zod schema 验证
- 返回类型:{ data?: T, error?: string }
- 成功后 revalidatePath('[受影响的路径]')
- 参考 @lib/actions/project.ts 的模式
业务逻辑:
- [具体逻辑]
边界情况:
- [列出需要处理的异常]
2.3 API Route(Webhook)
创建一个 Webhook 处理路由:[来源] Webhook
要求:
- 文件:app/api/[service]/webhook/route.ts
- 只导出 POST 方法
- 验证 webhook 签名([签名验证方式])
- 使用 raw body(不要 JSON parse 之前验证)
- 错误不暴露内部信息,返回 200 避免重试风暴
- 参考 @app/api/stripe/webhook/route.ts 的模式
处理的事件:
- [event.type]: [处理逻辑]
2.4 Client Component(表单)
创建一个表单组件:[表单名称]
要求:
- 'use client' 组件
- React Hook Form + zod resolver
- 提交调用 Server Action:@lib/actions/[对应].ts
- 提交中禁用按钮,显示 loading
- 成功后 toast 提示 + 可选 redirect
- 错误显示在表单下方
- 使用 @components/ui/ 的 shadcn 组件(Input, Button, Form, Label)
- 参考 @components/create-project-form.tsx 的模式
字段:
- [字段名]: [类型] [验证规则]
2.5 数据库 Schema 变更
给 [表名] 表添加以下字段:
字段定义:
- [字段名]: [类型] [约束]
要求:
- 修改 @lib/db/schema.ts
- 新字段先设为 nullable(避免迁移失败)
- 添加必要的索引
- 更新相关的 TypeScript 类型
- 列出需要更新的 Server Actions 和查询
- 生成迁移命令:pnpm db:generate
2.6 Bug 修复
修复以下错误:
错误信息:
[粘贴完整错误堆栈]
复现步骤:
1. [步骤]
期望行为 vs 实际行为:
- 期望:[...]
- 实际:[...]
相关文件:
- @[相关文件路径]
要求:
- 先分析根因,再给出修复方案
- 不要改变现有 API 接口
- 修复后不应影响其他功能
3. 任务拆分策略
3.1 为什么要拆分
AI 工具的一次性处理能力有上限——任务越复杂,输出质量越低。拆分的本质是 降低每次交互的认知负荷:
| 任务规模 | 推荐方式 | 原因 |
|---|---|---|
| 单文件修改 | 一次完成 | AI 的舒适区 |
| 2-5 文件功能 | Composer 一次 | 在 Agent 能力范围内 |
| 5-10 文件模块 | 拆成 2-3 步 | 避免遗漏 |
| 10+ 文件重构 | 拆成 5+ 步 | 每步独立可验证 |
| 全新功能模块 | 从数据模型开始 | 自底向上构建 |
3.2 自底向上拆分法
对于一个新功能模块(如"通知系统"),推荐按依赖顺序拆分:
Step 1: 数据模型(最底层,无依赖)
"在 schema.ts 中设计 notifications 表,包含 [字段列表]"
Step 2: 数据操作(依赖数据模型)
"基于刚创建的 notifications 表,实现 CRUD Server Actions"
Step 3: 后端逻辑(依赖数据操作)
"实现通知触发逻辑——当 [事件] 发生时,创建通知记录"
Step 4: API/推送(依赖后端逻辑)
"实现通知的 SSE 推送,客户端实时收到新通知"
Step 5: 前端展示(依赖 API)
"实现通知列表组件和未读角标,参考 @components/..."
Step 6: 集成测试(依赖全部)
"给通知系统编写测试,覆盖创建、推送、标记已读"
每一步完成后都可以验证——数据模型可以用 Drizzle Studio 检查,Server Actions 可以用测试验证,UI 可以在浏览器预览。
3.3 增量式提示
对于长会话,用增量方式让 AI 保持上下文:
// 第一轮
"创建 notifications 表的 schema"
// 第二轮(引用上一步结果)
"基于你刚创建的 notifications 表,实现 createNotification 和
markAsRead 两个 Server Actions"
// 第三轮(引用前两步)
"现在参考 @lib/actions/notification.ts 中的 createNotification,
在用户被邀请加入团队时(@lib/actions/invitation.ts 的 sendInvitation)
自动创建通知"
4. 多轮对话技巧
4.1 纠错模式
AI 第一次输出不完美是常态。关键是高效纠错:
// ❌ 模糊纠错
"这不对,重新写"
// ✅ 精确纠错
"第 23 行的查询缺少 tenantId 过滤,所有查询都必须包含
.where(eq(table.tenantId, tenantId))
另外第 45 行的错误应该 return { error: message } 而不是 throw"
4.2 迭代优化模式
// 第一轮:让 AI 生成基础版本
"实现用户搜索功能,使用 SQL LIKE 查询"
// 第二轮:添加分页
"给搜索结果添加游标分页,每页 20 条"
// 第三轮:优化性能
"在 name 和 email 字段上添加 GIN 索引,
搜索改为 pg_trgm 模糊匹配"
// 第四轮:添加缓存
"将搜索结果缓存到 Redis,5 分钟过期,
用户修改信息后清除缓存"
4.3 Review 模式
让 AI 审查自己或其他人的代码:
"Review 以下代码,重点检查:
1. 安全性(SQL 注入、XSS、权限绕过)
2. 性能(N+1 查询、缺少索引)
3. 错误处理(遗漏的边界情况)
4. 是否符合项目的编码规范(参考 @.cursorrules)
@[待审查的文件]"
5. 高级提示词技巧
5.1 Few-shot:给示例
当项目有特定模式时,给一个示例比千言万语更有效:
"按照以下模式创建 lib/actions/notification.ts:
示例(@lib/actions/project.ts 第 1-30 行):
[自动引用的代码]
要求:
- 同样的权限检查模式
- 同样的输入验证模式
- 同样的错误返回模式
- 替换为 notifications 表的 CRUD 操作"
5.2 Chain of Thought:让 AI 先思考
"我想给系统添加实时通知功能。
先不要写代码,先帮我:
1. 列出技术方案的选项(SSE vs WebSocket vs Polling)
2. 分析每个方案在 Next.js + Vercel 上的可行性
3. 推荐方案并说明理由
4. 列出实现步骤
确认方案后我再让你开始写代码。"
5.3 角色扮演
"你是一个 Next.js 安全审计专家。
请审查 @app/api/ 目录下的所有路由,
重点检查:
- 认证缺失(未检查 session)
- 授权绕过(未检查 tenantId)
- 输入注入(未用 zod 验证)
- 敏感数据泄露(返回了不该返回的字段)
输出格式:
| 文件 | 问题 | 严重等级 | 修复建议 |"
5.4 负面约束
告诉 AI "不要做什么"有时比"要做什么"更有效:
"创建用户列表页面。
不要:
- 不要使用 useEffect 获取数据(用 Server Component)
- 不要使用 API Route(用 Server Action)
- 不要使用 Prisma(用 Drizzle ORM)
- 不要创建新的 UI 组件(用 @components/ui/ 的 shadcn)
- 不要使用 offset 分页(用 cursor 分页)
- 不要在 Client Component 中直接查数据库"
本章小结
- CRAFT 框架:Context + Reference + Ask + Format + Test,结构化提示词
- @引用是核心:给 AI 看代码比描述代码有效 10 倍
- 专用模板:Server Component / Server Action / Webhook / 表单 / Schema 变更 / Bug 修复
- 自底向上拆分:数据模型 → 数据操作 → 后端逻辑 → API → 前端 → 测试
- 精确纠错:指出具体行号和问题,不要说"重新写"
- 迭代优化:先基础版本,再逐步添加分页、性能、缓存
- Few-shot:给一个好的示例比解释模式更直接
- Chain of Thought:复杂任务先让 AI 分析方案,确认后再写代码
- 负面约束:"不要用 Prisma / 不要用 useEffect" 减少常见错误