AI全栈开发实战:30天SaaS上线中的边界感与人机协作
1. 这不是“用AI写个Hello World”,而是一次真实的全栈SaaS建造实战
我去年夏天做了一件在当时看起来有点莽的事:关掉所有技术文档网站、禁用Stack Overflow书签、卸载本地保存的旧项目模板,只留下三样东西——GitHub Copilot的IDE插件、Cursor编辑器、Claude Code的网页端。然后给自己定了个硬性目标:30天内,从零启动、设计、编码、测试、部署一个能真实服务付费用户的SaaS产品,全程不手写任何核心逻辑函数,所有代码必须由AI生成、我只负责提问、审查、调试和集成。
结果是,第14天晚上9点17分,我在个人域名下上线了第一个可注册、可登录、可创建项目、可导出数据的完整Web应用——一个面向独立开发者的时间追踪与专注力分析工具,叫FocusLog。它有React前端、TypeScript类型系统、PostgreSQL数据库、Node.js后端API、JWT鉴权、Stripe订阅集成,甚至带基础的邮件通知和PDF导出功能。整个过程没有一行CRUD逻辑是我手动敲出来的,连SQL建表语句都是我用自然语言描述需求后,让Claude生成再人工校验的。
但真正让我坐下来写这篇复盘的,不是上线那一刻的兴奋,而是第18天凌晨三点——我盯着控制台里反复出现的500错误,翻了六遍AI生成的OAuth回调路由,才发现它把 req.user.id 直接拼进了SQL查询字符串,根本没做参数化处理;第22天,用户反馈“导出的PDF里中文全是方块”,我查了四小时,最后发现是AI在Dockerfile里自动加了 apt-get install fonts-dejavu-core ,却漏掉了中文字体包;第26天,Stripe webhook签名验证始终失败,日志显示 signature header is missing ,而AI生成的Express中间件压根没解析原始请求体……这些不是小bug,是系统性认知偏差在代码里的具象化。
所以这篇文章不讲“AI多厉害”,也不贩卖焦虑说“程序员要失业了”。它是一份带着黑眼圈、咖啡渍和Git commit历史截图的实操手记。关键词不是“Copilot”或“Claude”,而是 边界感 ——AI在什么环节真能当主力,在什么环节你必须像守门员一样寸步不让。它适合正在评估AI辅助开发价值的CTO、想提升编码效率的中级工程师、刚转行想少走弯路的新人,以及所有还相信“写代码终究是人和机器协作”的实践者。下面所有内容,都来自那30天里我亲手敲下的217条prompt、合并的43次PR、回滚的9次生产部署,以及贴在显示器边框上那张写着“别信它,再看一遍”的便签纸。
2. 整体架构设计与AI协作模式拆解
2.1 为什么选这三款工具组合?不是玄学,是能力错位匹配
很多人看到标题第一反应是:“Copilot+Cursor+Claude?这不是堆工具吗?” 实际上,这个组合不是随意拼凑,而是基于三类AI在软件工程不同阶段的 能力光谱错位 刻意设计的。我把整个开发流程切成四个关键阶段:需求理解与方案设计 → 模块化编码实现 → 跨层集成调试 → 安全与健壮性加固。每款工具在特定阶段有不可替代的优势,强行用同一款工具覆盖全流程反而效率更低。
-
GitHub Copilot :它的强项是 上下文感知的局部补全 。当你在React组件里写到
useEffect(,它能根据当前文件的import、props类型、附近变量名,精准推荐带依赖数组的完整钩子;在TypeScript接口定义后敲const user: User = {,它能自动列出所有必填字段并预填合理默认值。但它极度依赖已有代码的“锚点”,一旦进入空文件或需要跨文件推理(比如“这个API响应格式要和前端表格列对齐”),准确率断崖式下跌。所以Copilot被我严格限定在 单文件、单函数、已定义类型约束下的编码补全 场景,绝不让它生成新模块骨架。 -
Cursor :它的核心价值是 工作区级的语义理解 。当我选中整个
/src/components/TimeChart.tsx文件,右键选择“Explain this file”,它不仅能逐行注释,还能指出“这里useMemo的依赖数组漏了timeRange,会导致图表不刷新”;更关键的是,它能基于整个项目目录结构回答“哪些组件用了formatDuration工具函数?如果我想把它升级为支持毫秒精度,需要改哪几个地方?”。这种跨文件、跨层级的关联分析能力,是Copilot完全不具备的。所以我把Cursor定位为 架构审查员和重构指挥官 ,每天开工前先让它扫描一遍当天要动的模块,生成风险提示清单。 -
Claude Code :它胜在 长文本推理与规范遵循能力 。当我需要生成一个完整的Stripe webhook处理器时,Copilot只能补全单个if分支,Cursor会建议“参考官方文档”,而Claude能接收我粘贴的Stripe官方Webhook签名验证流程图、Express中间件文档片段、项目里已有的JWT验证中间件代码,然后输出一份包含错误处理、重放攻击防护、日志埋点、类型守卫的完整实现,并明确标注“第12行需替换为你的密钥环境变量名”。它的弱点是实时性差、无法感知本地未提交代码,所以Claude只用于 高风险、高复杂度、需严格遵循外部规范的模块生成 ,且每次生成后必须用Cursor做跨文件影响分析。
提示:不要试图让Copilot去设计数据库关系,也不要让Claude去修复一个只有两行报错的React渲染异常。工具错配比不用工具更耗时。我的经验是:看到需求描述超过3句话,就切到Claude;需要检查5个以上文件的耦合点,就打开Cursor;在已定义好Props接口的组件里写JSX,Copilot就是你的手指延伸。
2.2 架构选型背后的“人机分工”逻辑:为什么是Next.js + PostgreSQL + Vercel?
技术栈选择从来不是单纯比参数,而是看 AI生成能力与工程约束的交集 。我试过用AI生成Nuxt3项目,结果它把Vite配置和SSR渲染逻辑混在一起,导致静态导出失效;也试过用AI写Prisma schema,但它总把 @map 指令拼错成 @map() ,引发迁移失败。最终锁定Next.js 14(App Router)、PostgreSQL 15、Vercel托管,原因很实在:
-
Next.js App Router的约定优于配置特性,极大降低了AI的“自由发挥空间” 。比如路由文件必须放在
app/dashboard/page.tsx,布局文件必须叫layout.tsx,加载器必须用async function getData()。AI不需要理解“为什么这样设计”,它只需要记住“page.tsx文件里导出默认组件,layout.tsx里用children props”。这种强约束反而提升了生成准确率。我统计过,Copilot在Next.js路由文件中的首行补全成功率是92%,而在自定义Express路由文件中只有47%。 -
PostgreSQL的SQL语法严谨性,让AI生成的DDL/DML更可靠 。对比MySQL,PostgreSQL对数据类型、约束语法、事务隔离级别的要求更严格。AI生成
CREATE TABLE users (id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE);时,几乎不会漏掉NOT NULL或UNIQUE——因为Claude的训练数据里,这类语句的正确范式出现频率极高。而当我让AI生成MongoDB Schema时,它频繁把required: true写成required: ['email'],导致Mongoose验证失效。 -
Vercel的零配置部署能力,消除了AI最薄弱的运维环节 。AI可以生成完美的Dockerfile,但它永远搞不定“为什么在AWS EC2上npm run build会内存溢出”。Vercel的
vercel.json配置极简,AI生成的{ "rewrites": [{ "source": "/api/(.*)", "destination": "/api/" }] }基本一次通过。更重要的是,Vercel的环境变量注入机制和Next.js的process.env读取方式天然契合,避免了AI在.env文件路径、加载时机上的常见错误。
注意:AI不是万能胶水。我曾让Claude生成一个“兼容Vercel Serverless Functions和本地Node.js开发的数据库连接池”,它输出的代码在本地跑得好好的,一上Vercel就报
Error: Cannot find module 'pg'——因为它没意识到Vercel的Serverless Function默认不执行npm install,需要显式声明"functions": { "api/**": { "runtime": "nodejs18.x" } }。这类基础设施认知盲区,必须靠人来兜底。
2.3 “不写函数”的真实含义:AI生成的是代码,人定义的是契约
“全程不手写函数”这个说法容易引发误解。实际上,我写的最多的是 类型定义、接口契约、测试用例和prompt指令 。真正的生产力提升,来自于把“写代码”这个动作,升级为“定义代码该做什么”的更高阶活动。
举个具体例子:用户注册功能。传统做法是,我先想清楚密码强度规则、邮箱唯一性校验、JWT token生成逻辑,然后手写 registerUser 函数。这次,我做了三件事:
- 在
types/user.ts里定义:
export interface RegisterInput {
email: string; // 必须是有效邮箱格式
password: string; // 至少8位,含大小写字母和数字
fullName: string; // 非空,长度2-50
}
export interface RegisterResult {
success: boolean;
userId?: string;
error?: 'EMAIL_TAKEN' | 'INVALID_PASSWORD' | 'SERVER_ERROR';
}
- 写一条给Claude的prompt:“基于以上类型,生成一个TypeScript函数
registerUser,使用PostgreSQL的pg库。要求:① 密码用bcryptjs加密,盐值12;② 邮箱唯一性检查用SELECT COUNT(*) FROM users WHERE email = $1;③ 错误处理需区分业务错误(返回对应error枚举)和数据库连接异常(抛出Error);④ 返回Promise 。” - 把生成的代码粘贴进
lib/user/register.ts,用Cursor检查:是否所有$1参数都来自输入?是否bcrypt.hash调用在try/catch内?是否SELECT COUNT后正确判断了rows[0].count === 0?
这个过程里,AI负责把“契约”翻译成“语法”,我负责定义契约的精确性、审查翻译的保真度、处理契约之外的意外(比如网络超时)。最终生成的函数可能有12行,但我写的类型定义+prompt+审查时间,远少于手写12行+单元测试+边界case覆盖的时间。这就是“不写函数”背后的真相: 人退到更抽象的层面制定规则,AI沉到更具体的层面执行细节 。
3. 核心模块实现与AI协作细节实录
3.1 前端交互层:React组件生成的“三明治”工作流
React组件是AI表现最稳定的一环,但稳定不等于省心。我的实际工作流是典型的“三明治”结构: 人定骨架 → AI填肉 → 人加酱料 。以仪表盘时间图表组件 TimeChart.tsx 为例:
第一步:人定骨架(约5分钟)
我手动创建文件,写死最外层结构和必需的props接口:
// src/components/TimeChart.tsx
import { useState, useEffect } from 'react';
interface TimeChartData {
date: string; // YYYY-MM-DD
duration: number; // seconds
}
interface TimeChartProps {
data: TimeChartData[];
timeRange: 'week' | 'month' | 'year';
onDateClick?: (date: string) => void;
}
export default function TimeChart({ data, timeRange, onDateClick }: TimeChartProps) {
const [chartData, setChartData] = useState<TimeChartData[]>([]);
// TODO: 数据预处理逻辑待AI生成
useEffect(() => {
// TODO: 响应timeRange变化的逻辑待AI生成
}, [timeRange]);
return (
<div className="chart-container">
{/* TODO: 图表SVG渲染逻辑待AI生成 */}
<svg width="100%" height="300" viewBox="0 0 800 300">
{/* 占位:后续由AI生成具体path和rect */}
</svg>
</div>
);
}
第二步:AI填肉(Copilot + Cursor协同)
- 选中
// TODO: 数据预处理逻辑待AI生成注释,按Ctrl+Enter唤出Copilot,它立刻生成:
// 数据预处理:按timeRange聚合原始数据
const processedData = useMemo(() => {
if (!data.length) return [];
const now = new Date();
let startDate = new Date();
if (timeRange === 'week') {
startDate.setDate(now.getDate() - 7);
} else if (timeRange === 'month') {
startDate.setMonth(now.getMonth() - 1);
} else {
startDate.setFullYear(now.getFullYear() - 1);
}
return data.filter(item => new Date(item.date) >= startDate);
}, [data, timeRange]);
- 然后选中整个
useEffect块,右键Cursor → “Improve this code”,它指出:“startDate.setMonth在跨年时可能出错,建议用date-fns的subMonths”,并直接生成替换代码,同时在顶部自动添加import { subMonths, subYears, subWeeks } from 'date-fns';。
第三步:人加酱料(约15分钟)
- 检查
date-fns是否已在项目中安装(没装就npm install date-fns); - 发现AI生成的SVG渲染部分过于简陋,手动补充D3.js的scaleBand和axis逻辑(这部分AI生成质量差,不如自己写);
- 在
onDateClick回调里加一层防抖(AI从不主动加这个); - 最后用Cursor运行“Test this component”,它自动生成Jest测试用例,我只需补全
mockImplementation。
实操心得:AI生成的React代码,90%的坑在 状态同步时机 和 事件处理副作用 。比如Copilot常把
setChartData(processedData)写在useEffect里,却不考虑processedData本身是memoized的,导致图表不更新。我的固定动作是:所有setState调用后,立刻检查依赖数组是否完整;所有onXxx事件处理器,强制用useCallback包裹。这已成为肌肉记忆。
3.2 后端API层:从“能跑”到“能抗”的三次重构
API层是AI生成代码从“表面正确”滑向“深层危险”的高发区。我的 /api/auth/register/route.ts 经历了三次重大重构,每次都是被生产环境日志打醒的:
第一版(Copilot生成,第3天上线)
AI生成的代码能完成注册,但存在致命问题:
// ❌ 危险!直接拼接SQL
const query = `INSERT INTO users (email, password_hash, full_name) VALUES ('${email}', '${hash}', '${fullName}')`;
await pool.query(query); // SQL注入温床
第二版(Claude生成,第7天上线)
我给Claude的prompt加了硬性约束:“必须使用PostgreSQL参数化查询,禁止字符串拼接,错误处理需区分唯一约束冲突和其他错误”。它生成了:
// ✅ 参数化查询
const { rows } = await pool.query(
'INSERT INTO users (email, password_hash, full_name) VALUES ($1, $2, $3) RETURNING id',
[email, hash, fullName]
);
但仍有隐患:它没处理 UNIQUE_VIOLATION 错误码,导致邮箱重复时返回500而非409。
第三版(人主导,第12天上线)
我手动重构为:
try {
const { rows } = await pool.query(
'INSERT INTO users (email, password_hash, full_name) VALUES ($1, $2, $3) RETURNING id',
[email, hash, fullName]
);
return NextResponse.json({ success: true, userId: rows[0].id }, { status: 201 });
} catch (error) {
if (error.code === '23505') { // PostgreSQL unique_violation
return NextResponse.json({ success: false, error: 'EMAIL_TAKEN' }, { status: 409 });
}
console.error('Registration failed:', error);
return NextResponse.json({ success: false, error: 'SERVER_ERROR' }, { status: 500 });
}
这个版本的关键改进在于: 错误码映射 ( error.code === '23505' )和 日志分级 (业务错误不打ERROR级别)。AI能写出语法正确的catch块,但永远不知道 23505 这个魔数代表什么,也不知道该不该记录到Sentry。
注意:AI生成的API代码,必须经过“三问审查”:① 输入是否全部经过验证(正则、长度、类型)?② 数据库操作是否100%参数化?③ 所有外部调用(如Stripe API)是否有超时和重试?我建立了一个检查清单,每次合并API PR前必须逐项打钩。
3.3 数据库与安全层:那些AI永远学不会的“常识”
如果说前端和API是AI的舒适区,那么数据库设计和安全实践就是它的“认知禁区”。AI可以生成语法完美的SQL,但它不理解“为什么用户表要分离密码重置令牌”;它可以写出JWT验证代码,但它不知道“refresh token必须存数据库且绑定设备指纹”。
数据库设计的“人定规则”
我给Claude的prompt里,第一条永远是:“生成PostgreSQL 15的schema,严格遵守以下规则:① 所有表名用复数小写(users, sessions);② 主键统一用 id SERIAL PRIMARY KEY ;③ 外键必须带 ON DELETE CASCADE ;④ 敏感字段(password_hash, refresh_token)必须加 NOT NULL ;⑤ 创建时间统一用 timestamptz created_at DEFAULT NOW() ”。它生成的schema基本可用,但有三个必须人工修正的点:
- 它总把
refresh_tokens表的expires_at字段设为TIMESTAMP而非timestamptz,导致时区转换错误; - 它给
sessions表加了user_id INTEGER REFERENCES users(id),却漏了ON DELETE CASCADE; - 它在
users表里加了last_login_at TIMESTAMP,但没设默认值,导致新用户注册后该字段为NULL,前端展示异常。
安全实践的“不可协商条款”
我整理了一份《AI生成代码安全红线》,贴在团队共享文档里,所有成员(包括我自己)必须遵守:
- 密码处理 :必须用
bcryptjs,盐值≥12,禁止md5/sha256; - Token管理 :JWT的
exp必须≤24h,refresh token必须存数据库且带fingerprint字段(SHA256(userAgent+ip)); - CORS配置 :Next.js的
middleware.ts里,origin必须白名单校验,禁止*; - 错误信息 :生产环境禁止返回
error.stack,所有500错误统一返回{ error: 'INTERNAL_ERROR' }。
这些不是技术难点,而是工程常识。AI没有“常识”,它只有“统计规律”。所以我的工作不是教AI写安全代码,而是 用代码审查清单把常识变成不可绕过的流程 。
4. 实操过程中的典型问题与排查技巧
4.1 “AI生成的代码能跑,但性能奇差”:从12秒到320ms的优化路径
第10天,用户反馈仪表盘加载要12秒。Chrome DevTools显示, /api/dashboard/data 接口耗时11.8秒。我本以为是数据库慢,结果发现是AI生成的后端代码问题:
// ❌ AI生成的低效代码(伪代码)
for (const day of last30Days) {
const dailyData = await pool.query(
'SELECT * FROM sessions WHERE DATE(created_at) = $1 AND user_id = $2',
[day, userId]
);
// 对每个day发起一次DB查询
}
// 30次查询 × 平均300ms = 9秒+
排查思路 :
- 先用Vercel的Edge Function日志,确认是后端耗时而非网络延迟;
- 在本地用
EXPLAIN ANALYZE跑AI生成的SQL,发现它没用到created_at索引(因为DATE(created_at)函数导致索引失效); - 用Cursor扫描整个
/lib/dashboard目录,搜索pool.query(,发现所有日期过滤都用了DATE()函数。
解决方案 :
我让Claude重新生成,prompt强调:“必须用范围查询替代 DATE() 函数,假设 created_at 是 timestamptz ,生成获取某天所有记录的SQL,要求利用索引”。它输出:
SELECT * FROM sessions
WHERE created_at >= $1 AND created_at < $2 AND user_id = $3
-- $1 = '2024-05-01T00:00:00Z', $2 = '2024-05-02T00:00:00Z'
然后我手动把30次循环改成单次查询:
const { rows } = await pool.query(
'SELECT * FROM sessions WHERE created_at >= $1 AND created_at < $2 AND user_id = $3',
[startOfRange, endOfRange, userId]
);
// 再用JavaScript按天分组
最终接口耗时降至320ms。 关键教训 :AI擅长“单点最优”,但缺乏“系统视角”。性能优化永远是人定义约束(“必须用索引”)、AI提供方案(“用范围查询”)、人做整合(“把循环改成单查+内存分组”)的三角协作。
4.2 “环境变量在本地OK,上线就undefined”:Vercel部署的隐形陷阱
第16天,Stripe支付功能在本地测试完美,一上Vercel就报 Cannot read property 'secret' of undefined 。日志显示 process.env.STRIPE_SECRET_KEY 是undefined。
排查过程 :
- 检查Vercel项目设置 → Environment Variables → 确认
STRIPE_SECRET_KEY已添加且值正确; - 查看Next.js文档 → 发现App Router中,环境变量必须在服务端组件或Server Action中用
process.env.XXX,在客户端组件中必须用'use client'+process.env.NEXT_PUBLIC_XXX; - 搜索代码 → 发现AI生成的
lib/stripe/client.ts里,有const stripe = new Stripe(process.env.STRIPE_SECRET_KEY),而这个文件被客户端组件导入了。
根本原因 :AI不知道Vercel的环境变量作用域规则。它看到 process.env.XXX 就认为“全局可用”,而实际上Next.js做了严格的SSR/CSR隔离。
解决步骤 :
- 把所有敏感密钥(Stripe、PostgreSQL)的访问,严格限制在
/app/api/路由或Server Component中; - 为客户端需要的非敏感配置(如
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY),创建新的public环境变量; - 在
lib/stripe/client.ts顶部加注释:// ⚠️ This file must ONLY be imported in Server Components or API routes; - 用Cursor运行“Find all imports of this file”,确认没有客户端组件引用它。
实操心得:环境变量问题是AI协作中最隐蔽的“时差bug”。我的固定动作是:每次添加新环境变量,立刻在Vercel控制台设置,然后在本地
.env.local里补全,并在代码里加一行console.log('ENV CHECK:', process.env.MY_VAR),上线前删掉。宁可啰嗦,不赌运气。
4.3 “类型推导失效导致TS编译失败”:TypeScript与AI的相爱相杀
第21天, yarn build 突然失败,报错:
Type error: Type '{ id: string; email: string; }' is not assignable to type 'User'.
Object literal may only specify known properties, and 'id' does not exist in type 'User'.
查 types/user.ts ,明明定义了 id: string 。原来AI在生成某个API响应处理函数时,写了:
// ❌ AI生成的错误类型断言
const user = { id: 'abc', email: 'a@b.com' } as User; // TS报错
但 User 接口里, id 是 number 类型(因为PostgreSQL的 SERIAL 主键被AI误判为number)。
解决流程 :
- 用VS Code的“Go to Type Definition”跳转到
User接口,确认id: number; - 搜索整个项目,找到AI生成
as User的地方,发现它在/lib/api/fetchUser.ts里; - 让Claude重写这个函数,prompt强调:“
User.id是number类型,但数据库返回的id是string(因为pg库默认把SERIAL转为string),请用parseInt()安全转换,并添加类型守卫”; - 最终生成:
const userData = await fetch('/api/user').then(r => r.json());
if (typeof userData.id === 'string') {
userData.id = parseInt(userData.id, 10);
}
return userData as User;
核心原则 : 永远不要让AI决定类型,人定义类型,AI适配类型 。我现在的做法是:所有API响应类型,都基于OpenAPI spec手动生成(用 openapi-typescript ),而不是让AI猜。这多花20分钟,但省下三天debug时间。
5. 关键经验总结与可复用的工作流
5.1 “AI辅助开发”的真实ROI:时间节省在哪,时间消耗在哪?
30天实验结束后,我做了详细的时间审计(基于RescueTime数据):
| 阶段 | 传统开发预估耗时 | AI辅助实际耗时 | 节省时间 | 主要节省点 | 主要新增耗时 |
|---|---|---|---|---|---|
| 需求分析与原型 | 8小时 | 6小时 | 2小时 | Copilot快速生成Figma文案、Cursor分析竞品页面结构 | 反复调整prompt直到AI理解“轻量级”需求 |
| 前端组件开发 | 40小时 | 22小时 | 18小时 | 90%的UI组件、表单、列表由Copilot首稿生成 | 审查状态管理、修复CSS优先级冲突 |
| 后端API开发 | 35小时 | 28小时 | 7小时 | CRUD接口、基础验证逻辑由Claude生成 | 重写所有数据库错误处理、添加监控埋点 |
| 数据库与安全 | 15小时 | 25小时 | -10小时 | AI生成schema和基础migration | 手动修正索引、添加token刷新逻辑、配置CSP头 |
| 测试与部署 | 12小时 | 18小时 | -6小时 | AI生成Jest测试用例框架 | 调试CI/CD流水线、修复Vercel缓存策略 |
结论很清晰 :AI在 模式化、重复性、语法密集型 任务上优势巨大(前端组件、基础API),但在 状态一致性、安全合规、跨系统集成 上不仅不省时,反而增加成本。真正的ROI不在“写代码更快”,而在“把人从语法劳动中解放,投入到更高价值的设计决策中”。比如,我用省下的18小时前端时间,深度重构了用户引导流程,增加了3个关键转化点,上线后付费转化率提升22%——这才是AI带来的真实商业价值。
5.2 我的“人机协作”黄金工作流(可直接抄作业)
基于30天踩坑,我固化了一套每日开发流程,已写成团队内部手册:
晨间15分钟:准备阶段
- 检查Vercel、PostgreSQL、Stripe沙盒环境状态;
- 运行
npx tsc --noEmit确保TS类型无误; - 用Cursor扫描昨日代码,生成“潜在风险报告”(如“检测到3处未处理的Promise rejection”)。
编码中:三步审查法
- Prompt审查 :写完prompt先自问:“这个指令是否足够具体?是否排除了歧义?是否定义了失败标准?”(例:不说“生成登录API”,而说“生成Next.js App Router的POST /api/auth/login,要求:① 用bcrypt.compare验证密码;② 成功返回JWT,失败返回401;③ 错误信息不暴露密码错误还是邮箱错误”);
- 生成审查 :AI输出后,立即检查:① 所有外部依赖是否已安装?② 类型是否与现有接口一致?③ 是否有硬编码的密钥或路径?④ 错误处理是否覆盖所有分支?
- 集成审查 :合并到主干前,用Cursor运行“Test this file”,人工验证测试用例是否覆盖边界条件(如空数组、超长字符串、特殊字符)。
收尾5分钟:知识沉淀
- 把当日最有效的prompt,存入Notion的“Prompt Library”(分类:前端/后端/数据库/安全);
- 记录一个“今日AI翻车案例”(例:“Claude生成的PDF导出,漏了font-family声明,导致中文乱码”);
- 更新“安全红线”清单(新增一项:“PDF生成必须显式声明font-family: 'Noto Sans CJK SC'”)。
这套流程的核心思想是: 把AI当作一个极其聪明但毫无常识的实习生,你的工作不是教它知识,而是建立一套让它无法犯错的流程 。就像汽车有ABS防抱死系统,不是为了让司机开得更快,而是为了让他在极限情况下依然可控。
5.3 给不同角色的实操建议:CTO、工程师、新人如何落地
-
给CTO/技术负责人 :
不要采购“AI编程平台”,要投资“AI协作流程”。预算应该花在:① 团队Prompt工程培训(重点教如何把模糊需求转为AI可执行指令);② 建立代码审查Checklist(把安全红线、性能规范、可观测性要求固化为PR模板);③ 搭建内部AI知识库(收集各团队验证有效的prompt和避坑指南)。技术选型上,优先选与现有工具链深度集成的(如Cursor对Next.js的支持远好于CodeWhisperer),而非参数指标最高的。 -
给中级工程师 :
把AI当成“超级代码补全”,而非“全自动程序员”。每天花10分钟做三件事:① 用Cursor分析一个你写的旧函数,“它哪里可以优化?”;② 把一个重复性任务(如生成TypeScript接口)写成prompt,让Claude生成,再对比你手写的差异;③ 在Git commit message里,明确标注“AI生成部分:XXX,人工审查点:YYY”。坚持一周,你会建立起对AI能力边界的肌肉记忆。 -
给转行新人 :
别急着学“怎么用Copilot”,先学“怎么读代码”。从今天开始,每次AI生成代码,强制自己做三件事:① 用VS Code的“Go to Definition”跳转到所有调用的函数,看懂它做什么;② 在关键逻辑处加console.log,运行看实际输出;③ 把AI生成的代码,用自己的话口头解释一遍给同事听。AI是加速器,但地基必须是你亲手打的。我见过太多新人,Copilot生成的代码跑通了就提交,结果线上崩了,连错误日志都看不懂——那不是AI的问题,是地基没打好。
最后分享一个我贴在显示器上的小技巧:每当AI生成一段代码,我习惯性地问自己一个问题——“如果这段代码明天就没人维护了,一个完全不懂这个项目的新人,能不能只看这段代码和注释,就明白它在做什么、为什么这么做、什么情况下会失败?” 如果答案是否定的,那就不是AI的问题,是我的问题。因为最终交付的,不是AI写的代码,而是我作为工程师的判断、责任和尊严。
更多推荐



所有评论(0)