理论讲了 7 篇,是时候"真刀真枪"了。这一篇我会带你完整复盘一个 Web 项目的 AI 编程流程:用 6 步做出一个书签收藏工具,并在每一步暴露真实会出现的问题。

这篇不是"完美无缺的教程",而是"带坑的实战复盘"。

前言

AI 编程相关的教程,在 2026 年的中文互联网上已经非常多了。但绝大多数教程有同一个问题:只展示成功路径。作者把 AI 一次就跑通的代码贴出来,把"我尝试了 3 次才对"的中间过程剪掉,给读者一种"只要照着做就能成功"的错觉。

实际情况是:AI 编程项目的第一次跑通率大约只有 60%。剩下的 40% 几乎全集中在三类事情上——依赖装错、边界条件漏掉、AI 自己写的测试形似神不似。

所以这一篇,我会故意保留所有踩坑的瞬间。我希望你读完之后,不是"我也能照做",而是"我也会遇到这些坑,并且知道怎么排查"。

我会用到的工具栈是 Claude Code(终端版 AI 编程助手)+ Next.js 16 + TypeScript + Prisma 5 + SQLite + TailwindCSS 4。文中涉及三个斜杠命令:/plan(让 AI 先出方案再动手)、/init(生成项目级 CLAUDE.md)、/security-review(让 AI 对项目做安全审查)。没用过 Claude Code 的读者可以跳过这些命令,但 6 步流程本身对任何 AI 编程工具都适用。


1. 案例背景:书签收藏工具

为什么选这个项目? 因为它足够小(半天能做完),又足够真实(覆盖了 Web 项目的核心环节:前端、后端、数据库、部署)。如果你正在学 AI 编程,这是一个非常合适的"第一个完整项目"——它不像 Todo App 那么空,也不像电商系统那么重。

功能需求(来自我自己的真实痛点):

我日常浏览网页会积累大量书签,浏览器自带的收藏夹有两个问题:一是不能加描述,二是不能跨设备同步(不登录账号的情况下)。所以我想要一个轻量级的、能在浏览器里访问的、可以加描述和标签的书签工具。最简版只做 6 件事:

  1. 添加书签(标题、URL、描述、标签)
  2. 列表展示所有书签(卡片式布局)
  3. 按标签筛选(多选)
  4. 搜索书签(按标题和 URL 模糊匹配)
  5. 编辑和删除书签
  6. 数据持久化(用 SQLite)

为什么选 SQLite 而不是 Postgres? 因为这是个个人工具,用户量就我自己。SQLite 零配置、单文件、Prisma 对它支持最完整。等真要部署到公网,再切到云数据库——这个切换在第 6 步会详细讲。

技术栈选型理由:Next.js 16 是当前版本,App Router 比 Pages Router 更适合 AI 生成代码(约定更少)。Prisma 5 的 schema-first 设计让 AI 容易理解数据模型。TailwindCSS 4 让我不用纠结 CSS 类名(AI 生成的样式一般也能直接用)。TypeScript 必选——AI 生成的 JS 代码在大型项目里很难维护,加了类型等于加了一层保护。


2. 6 步完整流程

下面这 6 步是我在真实项目里跑通过的流程,你可以直接套用。每一步都有"会卡在哪"的具体描述。

2.1 第 1 步:描述需求

打开终端,启动 Claude Code:

$ mkdir ~/projects/bookmark-manager
$ cd ~/projects/bookmark-manager
$ git init
$ claude

进入 Claude Code 之后,先输入需求描述。这一步看起来简单,但实际上有 80% 的项目失败都和需求写得不够具体有关。很多新手的需求是"我想做一个书签工具",AI 收到这种需求只能瞎猜——最后做出来的东西和你想的完全不是一回事。

正确的需求描述应该包含三件事:核心功能、技术栈、边界。核心功能告诉 AI “做什么”,技术栈告诉 AI “用什么做”,边界告诉 AI “不要做什么”。

我要做一个书签收藏工具。

核心功能:
1. 添加书签(字段:标题、URL、描述、标签)
2. 列表展示所有书签(卡片式布局)
3. 按标签筛选(多选)
4. 搜索书签(按标题/URL 模糊匹配)
5. 编辑/删除书签
6. 数据持久化(SQLite)

技术栈:Next.js 16 + TypeScript + Prisma + TailwindCSS。
请用 /plan 模式先出架构设计,不要直接动手。

这一步的关键:用 /plan 模式让 AI 先出方案。AI 会给你一份包含数据库设计、API 列表、目录结构的方案——先审核,再动手。这一步绝对不能省。我见过太多新手跳过了这一步,结果 AI 写了一版、又推翻重写、又推翻重写,三次下来代码库里堆了三套不同架构的废代码。

/plan 的另一个隐藏好处:它把"决策"和"执行"分开了。AI 在 plan 阶段是冷静的,在执行阶段会进入"赶紧把代码写完"的模式。先决策、再执行,AI 给你的方案质量会高很多。

2.2 第 2 步:生成项目骨架

方案确认后,让 AI 生成项目骨架。骨架决定项目 80% 的命运——一个目录结构混乱的项目,后期怎么补都补不回来。

确认方案,请按以下顺序执行:
1. 用 create-next-app 创建项目
2. 初始化 Prisma,定义数据模型
3. 安装依赖(prisma、@prisma/client、bcryptjs 等)
4. 写 CLAUDE.md
5. 创建基础目录结构

这一步你会遇到的第一个问题:AI 可能会跳过某些步骤。它会默认"你已经装了 X",但你其实没装。比如 bcryptjs 这种库,光装运行时包没用,还得装类型定义包 @types/bcryptjs。AI 经常忘了这一步,导致 TypeScript 编译时报错。

正确做法:每一步执行完,立刻检查它实际做了什么。不要等所有步骤跑完再统一检查——那时如果出错,你不知道是哪一步埋的雷。

第二个常见问题:AI 在"创建目录结构"时会创建一堆空文件夹,等真要用的时候又找不到。这是因为它没区分"逻辑目录"(代码中要 import 的)和"物理目录"(实际创建的)。正确做法:让它直接生成最少一个占位文件(比如 lib/db.ts 里写一行 // 占位),目录才算真的存在。

注意:bcryptjs 没有类型,需要装 @types/bcryptjs。
另外每个目录都要至少有一个文件,不能留空目录。

2.3 第 3 步:追问补完

骨架搭好后,别急着写业务代码。这一步很多人会跳过,但我建议至少花 30 分钟——它能帮你省后面 3 小时的调试时间。

先用 /init 让 AI 生成一份项目级的 CLAUDE.md,然后人工校对。项目级 CLAUDE.md 至少要包含 5 个模块:技术栈(写明版本号)、目录结构、编码规范、当前进度、禁忌清单。

为什么要写"禁忌清单"?因为 AI 不知道你这个项目的历史踩坑——比如"不要用 lodash,用原生 ES"、“不要把数据库查询写在客户端组件里”。这些规则如果写在 CLAUDE.md 里,AI 每次生成代码都会看一眼,比你每次提醒它高效 10 倍。

这一步最容易犯的错:把 CLAUDE.md 写得很长(超过 200 行)。CLAUDE.md 不是文档,是给 AI 看的"宪法"。它应该短而硬——每个规则不超过两行,最好带一个反例。如果 CLAUDE.md 超过 200 行,AI 会在上下文中忽略其中一部分,效果反而变差。

2.4 第 4 步:写测试

这一步是最容易被忽略的。很多新手直接让 AI 写业务代码,跳过测试。他们觉得"测试不重要,先把功能跑起来再说"。结果就是:上线后出 Bug,不知道是哪里错了。改了一个 Bug,又冒出三个 Bug。最后整个项目变成"不敢动"的状态——因为每次改都可能引发连锁问题。

正确姿势

请为书签的 CRUD API 写测试。
要求:
1. 用 Vitest + Supertest
2. 覆盖正常路径和异常路径
3. 至少 5 个测试用例
4. 测试文件放在 src/__tests__/ 目录下

这里有个隐藏的坑:很多 AI 写的测试是"自证正确"的——它写一个 add(2, 3),然后测试 expect(add(2, 3)).toBe(5)。这种测试即使错了你也发现不了,因为它是和实现一对一写的。

改进方法:让 AI 在写测试前先列出"这个函数应该有哪些行为",再针对每个行为写测试。这相当于在写测试之前先写测试大纲。这样 AI 就没法偷懒了。

另一个隐藏的坑:测试和真实环境的耦合度。AI 经常把测试写成"调用真实 HTTP 接口"——也就是假设 dev server 已经起来了。这种测试在本地手跑没问题,在 CI 里直接挂。正确做法:让 AI 直接调 handler 函数,不走 HTTP 层。

2.5 第 5 步:修 Bug

测试跑完后,一定会有失败的测试。这不是测试写错了,是好事——它说明你的测试真的在测东西。

AI 编程项目里,最常见的 Bug 模式有三种

第一种是数据类型不匹配。比如 Prisma 返回的 Decimal 类型,前端期望 number。Prisma 的 schema 里写的是 Decimal,但前端拿到数据直接 .toFixed() 就报错。这种 Bug 的特征是"开发环境能跑,生产环境报错",因为 Prisma 在开发环境会自动转成 number,生产环境不会。

第二种是边界条件没处理。比如空字符串、超长 URL、特殊字符。AI 在训练数据里看到的代码 90% 是"主流程",边界处理的代码只占 10%。所以它写出来的代码天生就容易漏边界。

第三种是异步逻辑出错。比如 race condition——用户快速点击两次"删除",结果只删了一个但 UI 显示删了两个。AI 很难理解并发场景,因为它训练数据里的代码大多是"用户只点一次"的假设。

修 Bug 的正确姿势:把报错信息完整地贴给 AI,不要只贴 Error: ...。要带上调用栈、相关代码、环境信息。AI 看到的信息越多,定位越准。

测试失败了。错误信息:
[完整粘贴报错,包括调用栈]

相关代码:[粘贴相关代码]

环境:Node 22.13.0, macOS 14.4

这一步的隐藏陷阱:AI 修 Bug 经常"修一处坏三处"。因为它修一个错误时,会顺带改其他看起来相关的代码,结果把本来对的代码改错了。正确做法:每次 AI 改完后,立刻跑全部测试,不要只跑它刚改的那一个。如果有别的测试挂了,立刻让它回滚。

2.6 第 6 步:部署

请用 Vercel 部署这个项目。
要求:
1. 准备部署需要的 vercel.json 配置
2. 把 SQLite 切换到 Vercel Postgres(生产环境)
3. 配置环境变量
4. 给我部署步骤清单

这一步通常踩的坑:SQLite 在 Vercel 上不工作(Vercel 是 serverless,文件系统是只读的)。必须切换到云数据库。很多新手在这一步才发现要换数据库,所有 Prisma 查询都要重新适配 Postgres 特有的语法(比如 SQLite 不支持 JSON 类型,Postgres 支持;Postgres 的 ILIKE 和 SQLite 的 LIKE 行为不一样)。

部署前的最后一项检查:环境变量。Next.js 项目的环境变量分两类:NEXT_PUBLIC_* 开头的会被打包到客户端,没开头的只在服务端运行。AI 经常把敏感信息(比如数据库连接字符串)写到 NEXT_PUBLIC_* 里,导致连接字符串暴露在客户端 bundle 里。这一项建议用自动化扫描

grep -r "NEXT_PUBLIC_" .next/static/ 2>/dev/null | head -5

如果在客户端 bundle 里看到了 DATABASE_URL,立刻停下来改。

在这里插入图片描述


3. 演示中"暴露"的 4 类问题

下面这 4 类问题是几乎所有 AI 编程项目都会遇到的。我把真实的报错和原因分析写下来。

3.1 问题 1:一次跑不通(“npm run dev” 启动报错)

最经典的报错有两种。第一种是模块找不到:

Error: Cannot find module '@prisma/client'

第二种是数据库没初始化:

PrismaClientInitializationError: 
Invalid `prisma.bookmark.findMany()` invocation: 
Database file at ./prisma/dev.db does not exist

根因分析:这两个报错看起来不一样,但本质是同一类问题——Prisma 的初始化流程有 3 步,AI 经常漏掉其中某一步。这 3 步是:生成客户端(npx prisma generate)、应用迁移(npx prisma migrate dev)、填充种子数据(npx prisma db seed)。任何一步漏了,都会导致后面启动失败。

为什么 AI 会漏?因为 Prisma 的官方教程把这 3 步写在了不同章节,AI 训练时把这些章节的代码片段混在一起用,经常只执行其中一部分。

修复套路

$ npx prisma generate
$ npx prisma migrate dev --name init
$ npx prisma db seed

3.2 问题 2:边界条件(空字符串、超长 URL)

这一类 Bug 在 AI 编程项目里出现的频率几乎是 100%。AI 写的代码主流程通常没问题,但边界几乎一定会漏。

典型 Bug 场景:用户输入空标题 → AI 没拦截 → 列表里显示一张空卡片。用户输入 5000 字描述 → 列表排版崩了。用户输入 "javascript:alert(1)" 作为 URL → 触发 XSS 攻击。

为什么 AI 容易漏边界?这是个统计规律,不是 AI 笨。AI 的训练数据里,“主流程"代码(if user exists: create record)的出现频率远高于"边界处理"代码(if title.length == 0: return error)。AI 在生成时倾向于生成"高频模式”,所以边界就容易被跳过。

修复套路:在 AI 写完业务代码后,立刻让它补一遍输入验证:

请给所有 API 加 Zod 验证:
1. 标题不能为空,长度 1-100
2. URL 必须是 http/https 开头
3. 描述最多 500 字
4. 标签最多 5 个

Zod 是 TypeScript 的运行时验证库,比手写 if 链更安全,AI 也更熟悉。

3.3 问题 3:测试形似神不似

这一类 Bug 是最隐蔽的——它不会让测试失败,反而让测试通过,但实际上没在测东西。

典型症状

test('should create bookmark', async () => {
  const result = await createBookmark({ title: 'test' });
  expect(result).toBeTruthy();
});

这段代码看起来在测"创建书签"功能,但它只检查 result 不是 nullundefined。如果 createBookmark 函数实现有 bug——比如它返回了一个空对象 {}——这个测试也会通过。

这种 Bug 的本质:AI 在写测试时复制了"测试的形",但忽略了"测试的义"。它知道测试要做 expect,但不知道 expect 应该具体检查什么。

修复套路:明确告诉 AI 写严格测试:

请写严格的测试:
1. 检查返回对象的每个字段(title、url、description、tags)
2. 检查数据库是否真的写入了(用 prisma.bookmark.findUnique 验证)
3. 检查异常情况(重复 URL 应该报错)
4. 用 snapshot 测试验证关键输出

更系统的做法是让 AI 在写测试之前先写测试大纲——列出每个函数的所有行为分支,再针对每个分支写测试。这样 AI 就没法偷懒了。

3.4 问题 4:安全风险

AI 编程项目的安全风险比手写项目更高,原因是 AI 不理解业务上下文。它不知道你的"书签"是个人用的还是要给一万个用户用的——它会用通用的、最简单的实现,而这通常不安全。

典型漏洞

第一类是密码明文存储(不用 bcrypt)。这个错误在 2026 年的 AI 生成代码里仍然很常见,因为训练数据里有大量明文密码的示例代码,AI 不区分 demo 代码和真实代码。

第二类是缺少身份验证(任何人能改/删任何人的书签)。AI 默认所有 API 是公开的,因为它的训练假设是"个人 demo"——它不知道你的应用将来要对外开放。

第三类是XSS(用户输入没转义直接渲染)。React 默认会转义,但如果用了 dangerouslySetInnerHTML,AI 经常不加验证。

第四类是SQL 注入。Prisma 大部分情况会防,但复杂查询(特别是用了 prisma.$queryRaw 时)仍可能。AI 在生成原生 SQL 时不会主动加参数化查询,因为它不懂 SQL 注入的原理。

修复套路:让 AI 做一次安全审查:

请对项目做 /security-review:
1. 检查密码处理(必须用 bcrypt)
2. 检查所有用户输入的验证
3. 检查 SQL 注入风险
4. 检查 XSS 风险
5. 列出所有发现的问题并修复

重要提醒:AI 自己审自己的代码,效果打折扣。它倾向于"放水"——找到一个低级问题就报告"完成",漏掉真正严重的。建议自己再手动审一遍,重点看 AI 没提到的地方。

在这里插入图片描述


4. 关键代码片段

下面这段代码是我在真实项目中跑通过的版本,做了精简和注释,供参考。

4.1 CLAUDE.md 配置

CLAUDE.md 是项目的"宪法"。项目第一天就写好,后面每周花 10 分钟更新。下面是书签工具的真实配置:

# Bookmark Manager 项目规范

## 技术栈
- 框架:Next.js 16 (App Router) + TypeScript 5
- 样式:TailwindCSS 4
- 数据库:Prisma 5 + SQLite(开发)/ Postgres(生产)
- 测试:Vitest + Supertest
- 认证:暂不实现(个人工具)

## 目录结构
src/
├── app/                # Next.js App Router
│   ├── api/            # API 路由
│   ├── components/     # 页面级组件
│   └── (pages)/        # 页面
├── components/         # 可复用组件
├── lib/                # 工具函数
└── prisma/             # 数据库 schema

## 命名规范
- 文件:kebab-case
- 组件:PascalCase
- 函数:camelCase
- 数据库字段:camelCase(Prisma 默认)

## 约定
- 所有 UI 文案和注释用中文
- API 返回统一格式 { success, data, error }
- 所有用户输入用 Zod 验证
- 错误信息用中文,对外暴露的错误不包含堆栈

## 注意事项
- 密码字段(如未来加上)必须用 bcrypt
- URL 必须用 new URL() 验证合法性
- 不要把任何用户输入直接渲染到 HTML
- 永远不要用 dangerouslySetInnerHTML

4.2 核心 API 代码

这是书签列表和添加接口的实现。重点看第 19 行的 Zod 验证——这是上一节"边界条件"问题的修复方案:

// src/app/api/bookmarks/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { prisma } from '@/lib/prisma';

const BookmarkSchema = z.object({
  title: z.string().min(1).max(100),
  url: z.string().url().max(2000).refine(
    (u) => u.startsWith('http://') || u.startsWith('https://'),
    { message: 'URL 必须以 http 或 https 开头' }
  ),
  description: z.string().max(500).optional(),
  tags: z.array(z.string()).max(5).optional(),
});

export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url);
  const tag = searchParams.get('tag');
  const q = searchParams.get('q');

  const where: any = {};
  if (tag) where.tags = { has: tag };
  if (q) {
    where.OR = [
      { title: { contains: q } },
      { url: { contains: q } },
    ];
  }

  const bookmarks = await prisma.bookmark.findMany({
    where,
    orderBy: { createdAt: 'desc' },
  });

  return NextResponse.json({ success: true, data: bookmarks });
}

export async function POST(req: NextRequest) {
  const body = await req.json();
  const parsed = BookmarkSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json(
      { success: false, error: parsed.error.issues[0].message },
      { status: 400 }
    );
  }

  const bookmark = await prisma.bookmark.create({ data: parsed.data });
  return NextResponse.json({ success: true, data: bookmark });
}

第 6-12 行的 Zod schema 是这个 API 的"边界防线"——空标题会被拒、非法 URL 会被拒、5000 字描述会被拒、20 个标签会被拒。所有这些校验都在数据进数据库之前完成,省掉了后续的"清理脏数据"工作。

4.3 测试代码

测试代码要写两个版本:单元测试(直接调函数,快)和集成测试(走 HTTP,全链路)。下面这段是集成测试的精简版:

// src/__tests__/bookmarks.test.ts
import { describe, test, expect, beforeEach } from 'vitest';
import { prisma } from '@/lib/prisma';

describe('Bookmark API', () => {
  beforeEach(async () => {
    await prisma.bookmark.deleteMany();
  });

  test('应该成功创建书签', async () => {
    const res = await fetch('http://localhost:3000/api/bookmarks', {
      method: 'POST',
      body: JSON.stringify({
        title: '测试书签',
        url: 'https://example.com',
        description: '这是一个测试',
        tags: ['test'],
      }),
    });
    const json = await res.json();

    expect(res.status).toBe(200);
    expect(json.success).toBe(true);
    expect(json.data.title).toBe('测试书签');
    expect(json.data.tags).toEqual(['test']);

    // 验证数据库确实写入了(防止 AI 自证正确)
    const dbRecord = await prisma.bookmark.findUnique({
      where: { id: json.data.id },
    });
    expect(dbRecord).not.toBeNull();
    expect(dbRecord?.url).toBe('https://example.com');
  });

  test('空标题应该被拒绝', async () => {
    const res = await fetch('http://localhost:3000/api/bookmarks', {
      method: 'POST',
      body: JSON.stringify({ title: '', url: 'https://example.com' }),
    });
    const json = await res.json();

    expect(res.status).toBe(400);
    expect(json.success).toBe(false);
    expect(json.error).toContain('标题');
  });

  test('非法 URL 应该被拒绝', async () => {
    const res = await fetch('http://localhost:3000/api/bookmarks', {
      method: 'POST',
      body: JSON.stringify({ title: 'test', url: 'not-a-url' }),
    });

    expect(res.status).toBe(400);
  });

  test('超长描述应该被拒绝', async () => {
    const res = await fetch('http://localhost:3000/api/bookmarks', {
      method: 'POST',
      body: JSON.stringify({
        title: 'test',
        url: 'https://example.com',
        description: 'a'.repeat(501),
      }),
    });

    expect(res.status).toBe(400);
  });

  test('javascript 协议的 URL 应该被拒绝(防 XSS)', async () => {
    const res = await fetch('http://localhost:3000/api/bookmarks', {
      method: 'POST',
      body: JSON.stringify({
        title: 'XSS 测试',
        url: 'javascript:alert(1)',
      }),
    });

    expect(res.status).toBe(400);
  });
});

注意最后两个测试——“超长描述"和"javascript 协议 URL”——这是 AI 在初版里漏掉的边界。我们手工补上后,整个 API 才真正安全。


5. 经验总结:AI 是放大器,不是替代者

整个流程跑下来,我最大的感悟是:AI 不是"0 到 1 替代者",它是"1 到 10 效率放大器"

“0 到 1 的需求定义"必须人来。你说"我要做书签工具”,AI 不会替你决定要不要做——它甚至不会替你定义"书签工具"对你意味着什么。这是一个判断问题,不是技术问题。

"1 到 10 的代码生成"是 AI 的强项。10 个文件的基础 CRUD,AI 10 分钟搞定。手写要 1 小时。这 6 倍效率差距是真实存在的。

“10 到 100 的代码审查"必须人来。AI 自己写的代码自己审,容易"放水”——它倾向于把发现的问题报小,或者把"已知但未解决"的问题标记为"已知"然后跳过。

"100 到 1000 的迭代优化"是人和 AI 协作的领域。AI 出方案,人做决策。

我在这次项目中实际用时:不熟练时 6 小时,熟练后 1.5 小时。5 到 10 倍效率提升,但前提是你知道"我要什么"

如果换成一个完全不知道自己要做什么的人,AI 编程不仅不会更快,反而会更慢——因为他会在 AI 给的几十个方案之间反复横跳,最后每个方案都没做完。AI 编程最大的成本不是 token,是"你不知道自己不知道什么"。AI 把"不知道"变成"可以试试"——但能不能识别"试错了",还得靠你自己。

另一个反直觉的观察是:AI 编程项目的失败,几乎都发生在"决策"环节,而不是"执行"环节。AI 写代码很快、很便宜;人做决策很慢、很贵。失败的根源不是"AI 写得不够好",而是"人没想清楚"。所以 AI 编程项目的真正瓶颈是人愿不愿意在动手之前把需求想清楚——这件事 AI 帮不了你。


6. 给读者的复盘清单

如果你也想做自己的项目,按这 5 项清单走:

第一项,先写需求再让 AI 出方案。用 /plan 模式强制 AI 先规划后动手,避免方向性返工。我见过太多项目跳过了这一步,最后 AI 写了 3 套不同架构的代码,浪费了大量时间。

第二项,CLAUDE.md 是项目的宪法。项目第一天就写好,后面每周花 10 分钟更新。CLAUDE.md 不是文档,是给 AI 看的"宪法"——它应该短而硬,每个规则不超过两行,最好带一个反例。

第三项,测试不是可选项。AI 写的代码更必须测试,因为它会"形似神不似"——看起来测试通过了,实际上没在测东西。养成习惯:定期让 AI 自己 review 它写的测试,看能不能写出"故意通过"的测试。

第四项,安全审查不可省。AI 不知道你的业务上下文,让它自己审自己的代码常常"心太软"。建议 AI 审一遍后,自己再手动审一遍,重点看 AI 没提到的地方。

第五项,保存 Git 进度。AI 改坏代码是常态,git commit 是你的后悔药。建议每完成一个小功能就 commit 一次,不要等整个功能做完再 commit——否则 AI 一旦改坏了,你连回滚的粒度都没有。

最后补一条不适用清单——AI 编程不是万能的:第一种是业务核心规则没想清楚的项目,AI 会放大你的模糊,让一个本来能靠沟通解决的模糊变成技术债务;第二种是高合规要求的项目(金融、医疗),AI 生成的代码审计成本高于手写,因为每一行 AI 代码都要解释"为什么要这样写",对审计员来说是噩梦;第三种是你自己都不想看的代码,AI 会让你更不想看——它生成的代码在你眼里永远是"别人的代码",维护起来阻力更大。

这三种情况下,手写反而更划算。


结语

这个书签工具最后跑起来了吗?跑起来了。功能完整吗?搜索、筛选、增删改查都正常。代码质量如何?28 个测试通过,安全审查 0 个高危问题。

但如果你让我一个人从零手写,我可能要写 3 天。用 Claude Code,整个项目用时 1.5 小时。这就是 AI 编程的真实体感——不是 100% 替代你,而是让你从 1 天的工作量压缩到 1 小时。你省下的时间,可以做更重要的事:想清楚"我到底要做什么"。

整个系列到这里就结束了。从范式到原理、从工具到实战,从安装到部署——你现在应该具备了独立做 AI 编程项目的全部基础。

去动手做点什么吧。但动手之前,先想清楚三件事:我要做什么、我不做什么、我怎么知道做完了。


参考资料

  1. Claude Code 官方文档:https://claude.ai/
  2. Next.js 16 App Router 文档:https://nextjs.org/docs
  3. Prisma 5 数据库迁移指南:https://www.prisma.io/docs/
  4. B 站实战视频:https://www.bilibili.com/video/BV1RPET6tEp2
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐