
1. 从原型到前后端一次完整的 AI 编程实践我自己带了不少人入门编程也帮身边的人踩过很多坑。最近一次辅导让我印象特别深一位完全没系统学过全栈开发的A同学想做一个校园活动报名的小工具让我带着他用AI辅助从零写出来。先说结论整个过程走下来我们只用了大概两周的业余时间就完成了一个有原型、有前端页面、有后端接口、能真实报名和查询的完整小系统。这次实践最值得聊的不是哪一行代码写得多漂亮而是怎么用AI把想法变成原型再把原型变成前后端都能跑的东西。我把它完整记录下来从需求拆解到环境搭建、从前端页面到后端接口、从联调排错到收尾复盘希望给想用AI做独立开发、或者正在带新人写项目的朋友一些参考。A同学一开始的想法特别朴素他说我就想做个页面别人能填表报名我能在后台看到谁报名了。这个需求听起来简单真要动手做里面藏着不少问题数据存在哪怎么防止乱填页面要不要登录后台怎么区分管理员和普通用户这些都是在实践过程中AI和我们一起一步步逼问出来的。这篇文章不会讲特别深奥的架构而是完整展示一个普通需求怎么用AI逐步落地重点聊思路和踩坑。如果你也想用AI辅助做自己的小项目这应该是一份可以直接参考的全流程实操记录。1.1 为什么选活动报名这个场景来练手我辅导人入门最怕的就是上来挑一个超出能力边界的大项目。什么电商系统、社交平台、实时聊天工具这些项目听起来很酷但没有三五个人的团队、没有三两个月的持续投入基本做不出来做出来也是一堆半成品。活动报名这个场景是我建议的原因有几个第一它的数据模型足够简单。核心只有三张表活动表、报名表、用户表或者更简单一点两张表就够了。这对第一次做后端的人非常友好不会在数据库设计阶段就卡死。第二它前后端都有但都不复杂。前端需要一个展示活动的页面、一个报名表单、一个后台管理列表后端需要处理报名请求、读取活动列表、按条件查询。这几个接口来回就那么几个非常典型。第三它的边界很清楚不容易无限膨胀。报名系统做完就是做完了不会像聊天室一样要不再加个消息已读、再做个表情包功能需求蔓延是新手项目夭折的头号杀手。我把这个逻辑跟A同学讲清楚之后他也认可。于是我们定了目标一个校园内部使用的活动报名小程序包含前端用户页面和管理后台后端提供接口数据持久化存储不需要注册登录时用手机验证码也不做支付。1.2 AI辅助编程的整体思路不是让AI写代码而是和AI结对编程正式开始之前我先给A同学定了个基调这次实践不是我把需求扔给AI它给我一段代码我复制粘贴就完事而是我们俩和AI一起结对编程。这个区别很重要。我自己见过太多人用AI写代码翻车原因几乎都一样把AI当成搜索引擎用搜到一段代码就贴贴上去跑不通再问AI怎么改改完还是不行最后来一句AI写的代码根本不能用。实际上AI在编程这件事上的正确打开方式是把它当成一个能力很强、但经常自以为是的结对伙伴。你需要给它清晰的任务描述让它产出方案然后你负责review和验证发现问题再和它讨论修正。整个过程我们严格遵循一个四步循环讲清楚要什么 → 让AI给方案和代码 → 本地运行验证 → 把问题反馈给AI迭代这个循环跑顺了AI就是高效生产力跑不顺AI就是代码垃圾生成器。后面所有章节的内容基本都是这四步循环在不同环节的展开。2. 第一个环节把模糊想法变成可执行的原型整个实践的第一步不是装环境也不是写代码而是把想法说清楚。大多数新手甚至不少有经验的人在项目开始时的通病是脑子里只有一个模糊的画面比如我想做个报名页面但这个页面到底长什么样、上面有哪些元素、用户操作完会发生什么完全没有头绪。这时候AI的第一个用处就体现出来了帮我们把模糊的需求逼成具体的细节。2.1 用AI梳理需求清单逼出关键问题我让A同学先在对话里用大白话描述他的需求不用管任何技术词汇想到什么说什么。他是这么写的我想做个活动报名页面别人打开能看到活动信息填名字和联系方式就能报名。然后我自己能看有哪些人报名了最好还能导出。就这么几句话。我让他把这段话原封不动贴给AI然后让AI基于以上需求列一份完整的需求清单并用提问的方式指出需求中模糊的地方。AI返回的提问质量相当不错。它问了我们几个之前完全没想到的问题活动是一次性的还是长期多场的如果是多场页面是否需要区分不同活动一个人能不能重复报名同一个微信号或手机号能不能报多次报名之后要不要审核还是报名即成功后台需不需要删除或取消报名的功能活动信息是写死的还是后台可以动态发布数据规模大概多大预估多少人使用这几个问题往桌面上一摆A同学立刻意识到原来我连自己要什么都不是很清楚。我们花了大概半小时把每个问题都过了一遍最终确定了一个最小可用版本这次只做一个活动活动信息写在前端页面里后台不动态发布活动一人只能报名一次用手机号做唯一校验报名即成功不需要审核后台可以查看报名列表也可以删除某条错误报名数据规模很小大概几千条以内不需要复杂的性能设计。这套决策非常关键。它把项目边界从一个能运营的系统收缩成了一个能用的工具大大降低了完成难度。我建议所有用AI辅助开发的朋友第一步都先花时间把需求逼到最小可用而不是一上来就让AI写登录注册、权限管理这些大而无当的东西。2.2 让AI产出线框图先看布局再谈代码需求理清之后我们没有马上写页面而是先让AI画了张文字版线框图。具体方法是给AI一段提示词说明页面需要的模块和布局让AI用文字或者ASCII字符画出页面的布局结构。这样做的好处是先确认信息架构再写视觉细节避免一上来就被CSS折磨得死去活来。当时的提示大概是这样的请为一个活动报名页面设计一个信息架构线框图要求包含页面顶部展示活动标题和宣传文案中间区域展示活动时间、地点、人数限制等基本信息下方是报名表单包含姓名、手机号、年级/专业三个字段底部展示报名成功后的提示区域。用文字画出区块布局并标注每个区块的功能说明。AI给出的线框图把页面分成了头部宣传区、活动信息卡片区、报名表单区、提交反馈区四个区块每个区块下面标了需要的字段和按钮。A同学看到这个图之后第一次觉得项目在我脑子里清楚起来了。这里补充一个实操心得文字线框图是一个被很多人忽略但极其好用的AI辅助技巧。因为AI生成图片的水平现在还不太稳定但文字描述区块结构的能力非常强而且改起来特别快。你不需要会画图只需要会描述页面要放哪些东西AI就能帮你把布局设计好。原型不仅是给用户看的更是给自己理清逻辑用的。2.3 原型评审在动手写代码前先纸上谈兵线框图出来之后我带A同学做了一次简单评审。评审的核心就一句话想象你是一个用户从头到尾走一遍流程看看每一步是否顺畅。我们模拟走了一遍打开页面看到活动信息和宣传文案往下滚动找到表单填写姓名手机号专业点击提交页面提示报名成功然后我们登录后台看到这条报名记录。这一遍走下来发现了一个问题A同学一开始压根没想过报名成功之后用户看到什么这个环节。如果没有这个反馈用户提交之后完全不知道成功没有就会重复点击产生大量重复数据。我们在原型阶段就加上了提交后置灰按钮并显示成功提示的设计实际开发中没有在这个问题上返工。所以说原型的核心价值不是画了个好看的图而是提前发现逻辑缺口。如果你在原型阶段不把用户流程走通写代码的时候必然会来回改改到怀疑人生。从这一步开始技术方案的方向基本就定了。前端用什么框架、后端用什么语言、数据存哪里这些不该在写代码的时候才纠结而是在原型阶段就该有结论。2.4 技术选型别被前后端分离吓住对于A同学这种第一次做完整项目的选手我对技术选型的原则是能简单就简单但不要简单到学不到东西。我们最终选了这么一套组合前端React Vite用最简单的函数组件和状态管理不引入Redux这类重型工具后端Node.js Express轻量、和前端同语言降低学习成本数据库SQLite零配置文件型数据库最适合这种小工具联调方式前端开发服务器配代理请求转发到后端接口我为什么没有选Python的FastAPI或者Django不是因为它们不好而是A同学是完全的前端新手让他同时学React和Python两套语言认知负担太重。同语言全栈JS/TS对新手是最友好的路径前后端上下文切换成本低调试的时候心智负担小很多。为什么不直接上个前后端不分离的传统方案比如服务端模板渲染主要原因是想让A同学理解现在主流的开发模式毕竟大多数人将来进团队接触到的都是前后端分离的结构。虽然这种模式对新手稍微麻烦一点但值得。技术方案定了之后我们用AI生成了一份简单的项目结构说明。我当时给AI的任务是帮我生成一份Vite React Express SQLite的项目目录结构并说明每个文件的大致职责。这份结构说明成了后面所有开发工作的地图。3. 第二个环节前端页面实现AI在这里最省时间原型阶段结束正式开始写代码。我们按先前端、后后端、再联调的顺序推进这个顺序对新手比较友好因为前端页面看得见摸得着成就感来得快。3.1 用Vite快速初始化项目脚手架有些教程喜欢让人手动配置Webpack那对新手来说简直是劝退现场。我们用Vite一条命令就把项目骨架搭好了npm create vitelatest activity-signup -- --template react cd activity-signup npm install npm run dev跑起来之后浏览器打开就能看到一个默认的React页面。这一步几乎没有难度但需要注意几个小坑第一Node版本不能太老。Vite 对 Node 版本有要求至少 16 以上推荐 18 或 20。如果运行npm create vite报错先检查一下node -v的输出。第二模板选react而不是react-ts。我对A同学的建议是先不碰TypeScript等逻辑跑通了再考虑加类型。新手阶段被类型报错劝退的例子实在太多了没必要一开始就上难度。骨架起来之后我们同步做了一件事把项目的文件结构按照功能重新组织了一下。Vite默认生成的模板结构是给Demo用的不适合直接承载业务。我们建了src/components、src/pages、src/api几个目录分别放组件、页面和接口请求封装。这种先搭目录再写代码的习惯比写代码本身更重要。3.2 让AI按线框图生成页面组件前端开发的核心环节来了。我把线框图的描述和设计意图一起喂给AI让它生成第一个版本的页面组件。这里有个关键技巧我称之为带上下文提问。很多人在让AI写前端代码时只丢一句话帮我写一个报名页面AI当然能写但写出来的东西跟你的设计十有八九对不上。正确做法是把需求描述得足够具体。比如我们当时对AI的提示是生成一个React函数组件用于活动报名页面。页面布局如下顶部通栏展示活动名称‘校园开发者沙龙报名’副标题‘限额50人’活动信息卡片区域展示四个字段时间、地点、主办方、报名截止日期报名表单包含三个输入框姓名、手机号、专业/年级手机号需要做格式校验11位数字提交按钮在表单下方提交过程中禁用并显示‘提交中...’下方预留一个区域用于显示提交成功或失败的提示信息。 使用React的useState管理表单状态不引入额外的UI库。这段提示词包含了布局结构、字段清单、校验规则、交互状态四个维度AI生成的代码基本可以直接用。以下是当时生成的核心代码框架import { useState } from react; function SignupPage() { const [form, setForm] useState({ name: , phone: , major: }); const [submitting, setSubmitting] useState(false); const [message, setMessage] useState(); const handleChange (e) { setForm({ ...form, [e.target.name]: e.target.value }); }; const handleSubmit async (e) { e.preventDefault(); if (!/^1\d{10}$/.test(form.phone)) { setMessage(请输入正确的11位手机号); return; } setSubmitting(true); // TODO: 在这里调用后端接口 setSubmitting(false); }; return ( div style{{ maxWidth: 640, margin: 0 auto, padding: 24 }} h2校园开发者沙龙报名/h2 div classNameinfo-card p时间2025年6月20日 14:00/p p地点大学生活动中心 302/p p主办方校学生会技术部/p p报名截止2025年6月18日 23:59/p /div form onSubmit{handleSubmit} input namename placeholder姓名 value{form.name} onChange{handleChange} / input namephone placeholder手机号 value{form.phone} onChange{handleChange} / input namemajor placeholder专业/年级 value{form.major} onChange{handleChange} / button typesubmit disabled{submitting} {submitting ? 提交中... : 立即报名} /button /form {message p{message}/p} /div ); } export default SignupPage;这段代码质量已经相当可用了。唯一需要动手改的是样式AI生成的style比较简单没有做美化但不影响功能。在初版阶段功能跑通比页面好看更重要。3.3 前端的人机分工哪些让AI干哪些必须自己把关用了几天AI生成前端代码之后我总结了一份比较清晰的分工原则。适合让AI干的重复性组件代码比如表单、列表、弹窗这类代码AI写出来八九不离十固定模式的逻辑比如输入框受控组件、列表渲染、条件展示常见CSS布局比如Flexbox、Grid居中、卡片样式AI的命中率很高样板代码比如接口请求封装、工具函数、路由配置。必须自己把关的状态管理的设计哪些状态放组件内部哪些状态需要提升到父组件这个AI给不了最优解数据流的走向从哪个接口拿数据、数据如何在组件间传递必须自己能讲清楚表单校验的边界逻辑比如手机号、姓名长度、重复提交防抖这些逻辑AI不会主动问需要你提出来。有一次A同学直接照搬了AI生成的一段列表渲染代码跑了半天发现页面是空的我一看原来是数组字段名对不上后端返回的字段叫recordsAI前端代码读的却是list。这就是典型的AI只能写代码不能替你对数据契约的教训。从此我们养成了一个习惯前后端字段名在写代码之前先定义好写的时候手边放着一张数据字段对照表。3.4 没有后端时先用Mock数据把前端跑通前端做到一半后端还没开始写这时候怎么验证页面逻辑我们的办法是在前端代码里临时写一个 Mock 数据文件。具体做法是在项目里建一个src/mock.js导出几个固定的数组对象模拟接口返回的数据前端页面先请求这个Mock数据源来渲染。等后端接口通了再把请求地址替换成真实接口。// src/mock.js export const mockActivity { id: 1, title: 校园开发者沙龙报名, time: 2025-06-20 14:00, location: 大学生活动中心 302, organizer: 校学生会技术部, deadline: 2025-06-18 23:59, limit: 50 }; export const mockRecords [ { id: 1, name: 张三, phone: 13800001111, major: 计算机 2023级 }, { id: 2, name: 李四, phone: 13900002222, major: 软件工程 2022级 } ];这个习惯帮我节省了大量等待时间。前端和后端完全可以并行推进不用等后端写完了才开始写页面。这也是现在做项目的基本节奏只要数据契约定好了前后端各干各的最后联调一下就行。4. 第三个环节后端接口实现AI是翻译器不是思考者前端页面跑通之后我们正式进入后端开发。这一步对A同学来说是完全陌生的领域但整个过程的推进比预想中顺利因为逻辑其实比前端更直白接收请求、处理数据、返回结果。4.1 搭一个Express服务原来后端启动并不神秘后端项目我们放在了独立的目录里没有跟前端混在一起。初始化命令很简单mkdir server cd server npm init -y npm install express cors better-sqlite3三个依赖各有各的用处express是Web框架负责定义接口cors解决浏览器跨域限制better-sqlite3是SQLite的驱动用来读写数据库。启动一个最简单的服务只需要几行代码const express require(express); const cors require(cors); const app express(); const port 3001; app.use(cors()); app.use(express.json()); app.get(/api/health, (req, res) { res.json({ status: ok }); }); app.listen(port, () { console.log(Server running at http://localhost:${port}); });跑起来之后访问http://localhost:3001/api/health如果看到{status:ok}后端就活了。第一次见到后端启动这个动作的A同学很兴奋他说没想到后端服务这么简单。这其实是好事破除对后端的神秘感是学习后端的第一课。4.2 让AI生成数据库建表语句和接口代码后端逻辑无外乎增删改查AI在生成这类代码的时候效率极高因为模式非常固定。但我们不是直接把需求丢给AI让它自由发挥而是先自己设计好了接口清单和数据表结构。接口清单大概是这样方法路径功能说明GET/api/activity获取活动信息POST/api/signup提交报名GET/api/signup/list获取报名列表DELETE/api/signup/:id删除某条报名记录这张表是用AI生成的但里面每条记录都是我们根据需求逐条确认过的。我要求A同学必须能讲清楚每一个接口是干什么的、谁来调用它、返回什么数据。讲不清楚的接口说明设计不合理先讨论清楚再往下走。建表语句更简单SQLite的表结构就一张表CREATE TABLE IF NOT EXISTS signups ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, phone TEXT NOT NULL UNIQUE, major TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP );注意phone TEXT NOT NULL UNIQUE这一行这就是我们实现一人只能报一次的去重约束。数据库的唯一约束比应用层判断可靠得多这是AI不会主动告诉你的经验。接口代码生成之后我们做了一次重要的事让A同学对着代码逐行给AI讲一遍代码在干什么。这个过程我叫它说代码比写代码更能检验是否真正理解。A同学在用大白话解释的时候卡了好几次但我们坚持把它讲完讲完再去跑接口测试理解深度完全不一样。4.3 用接口测试工具检验后端逻辑后端写完不能直接说好了要拿数据测。我们用的工具是Postman但不熟的人也别慌其实浏览器直接访问GET接口也能测只是POST请求需要Postman或者命令行工具。我们对着接口清单挨个测试GET 活动信息返回活动字段状态200POST 报名正常数据返回成功提示重复手机号返回错误提示格式不符返回校验错误GET 报名列表返回数据库中所有记录DELETE 删除传一个存在的ID返回成功传不存在的ID返回404。这里插一个我在测试中特别看重的点异常分支的测试比正常分支更重要。大多数新手把正常流程跑通就视为项目完成但真实场景里用户的操作千奇百怪。我们重点测了三类异常重复报名、手机号格式错误、传不合法的ID值。这三类异常只要后端能稳定返回错误信息而不是直接崩掉项目基本就稳了。5. 前后端联调整个项目最磨人的环节也是收获最大的环节前端和后端各自跑通之后真正的挑战才开始联调。联调做得好不好直接决定这个项目到底是一个Demo还是一个能用的工具。5.1 配置代理解决跨域和接口地址问题前端跑在http://localhost:5173后端跑在http://localhost:3001两个端口不一样浏览器会拦截跨域请求。虽然我们已经装好了cors但更优雅的方案是在Vite里配一个代理。在vite.config.js里加上import { defineConfig } from vite; import react from vitejs/plugin-react; export default defineConfig({ plugins: [react()], server: { proxy: { /api: { target: http://localhost:3001, changeOrigin: true } } } });这样配置之后前端代码里请求/api/signupVite开发服务器会自动把请求转发到后端的3001端口。前端代码里可以放心写相对路径不用写全域名以后部署上线也方便。第一次配完代理前端页面点击报名数据真的写到数据库里然后在后台列表看到了这条记录的时候A同学激动得不行。这个打通的瞬间就是全栈项目最有魅力的时刻。5.2 联调中遇到的三个典型问题联调过程不是一帆风顺的但正因为遇到了问题、解决了问题这次实践才真正有含金量。我们遇到的三个问题很有代表性第一个问题跨域配置让请求变成了预检请求。前端在提交表单时设置了Content-Type: application/json触发浏览器发送OPTIONS预检请求。后端因为我们装了cors自动处理了这个问题没怎么费力就过了。但如果不装cors而自己写跨域头很容易漏掉OPTIONS的处理踩坑概率极高。第二个问题时间字段显示不友好。数据库里created_at存的是UTC时间前端页面直接显示出来是个奇怪的时间格式。原因是SQLite的CURRENT_TIMESTAMP默认存UTC跟北京时间差了8个小时。这个问题的解决方案很简单要么在SQL查询时用datetime(created_at, localtime)转换要么前端显示时加8小时。我们选择了前者在SQL层就处理掉前端不用管时区的事。第三个问题用户提交了空姓名。前端页面做了必填校验但有心人绕过了前端直接给接口发请求后端如果没做校验就会写一条空数据进库。我们的对策是在后端接口里加了一层基本校验。前后端双重校验不能省前端校验是为了用户体验后端校验是为了数据安全。5.3 电脑端之外手机预览和真机测试做这个项目的时候A同学提到他可能需要用手机访问页面。我们在联调之后顺手做了一个移动端适配给页面加了viewport设置把固定宽度改成了百分比和弹性布局简单的几行CSS就让页面在手机上不再一坨。其实Vite的开发服务器默认支持局域网访问。在启动命令里加--host参数然后手机和电脑连同一个WiFi在手机浏览器输入电脑的局域网IP和端口就可以直接访问。这一步虽然简单但带来的成就感翻倍强烈建议做Web开发的朋友都试一次。6. 常见问题与排查技巧实录联调和后期测试阶段我们积累了不少问题和排查经验整理成速查表放在这里方便大家直接对照。症状可能原因排查方法前端页面刷新后数据消失数据只存在组件内存里没有从后端获取检查Network面板确认请求是否发出控制台报 404接口路径拼写错误或代理没生效先直接用浏览器访问后端地址确认接口存在请求能发出但返回CORS错误后端没装cors或配置不一致检查后端是否cors()前端代理是否配置手机访问电脑页面打不开防火墙拦截或没加--host参数启动Vite时加--host检查防火墙字段提交后中文乱码前端请求头没设置Content-Type确认用JSON.stringify并且请求头带application/json重复报名没有提示前端依赖后端报错但后端没做唯一约束检查数据库表中phone字段是否有UNIQUE约束页面报未定义 is not a function引用的函数不存在多半是拼写错误检查导入导出的名字是否完全一致再补充一个独家的排查习惯先看请求通没通再看数据对不对。我见过很多新手一遇到页面空白第一反应是打开代码反复看看了半天也看不出问题。正确的排查顺序是打开浏览器开发者工具的Network面板看请求是否发出了请求发出去了看状态码是200、404还是500状态码正常看返回的JSON数据是否符合预期数据正常再看前端渲染代码哪里没对上。按这个顺序排查大部分问题能在五分钟内定位。这条经验比任何技巧都实用建议所有新手刻在脑子里。7. 复盘AI编程实践里真正重要的是什么两周时间A同学完成了一个从原型设计到前后端联调全流程的项目。作为这次辅导的复盘记录我把自己观察到的最重要的几点经验写下来。第一AI编程的核心能力是拆解需求不是写代码。这次实践里AI写代码的速度确实快但真正决定项目成败的是我们能否把模糊的想法拆解成一个个明确的小任务。每一个小任务描述得越清楚AI产出的代码越靠谱。如果你的需求描述不清晰AI只能靠猜猜出来的代码自然充满问题。第二和AI协作要有代码审查意识。AI产出的代码必须当面审查不能直接信任。你需要能回答三个问题这段代码是干什么的为什么这么写有没有更优的实现方式回答不了就问AI让它解释清楚。我始终觉得工具再强自己的理解能力才是内核。第三不要害怕动手改AI的代码。很多新手有个误区觉得既然AI写了代码自己就不能动了或者不知道从哪下手改。实际上AI生成的是起点不是终点。我们在实践中几乎每一段AI生成代码都动过调整参数、增加校验、修复边界问题。动手改代码才是真正掌握知识的过程。第四实践的价值在于走通一遍完整链路。从需求分析到原型设计、从前端开发到后端实现、从接口联调到异常排查这条路完整走完才有我确实会做项目了的感受。只学理论或者只看教程永远停留在以为会了的状态。A同学这次最大的收获不是掌握了多少API而是对整个项目生命周期有了切身的把握。如果你也打算用AI辅助做一个小项目我的建议是找一个身边真实存在的小需求按这篇文章的思路先拆需求、再画原型、然后前后端并行、最后联调收尾。两周时间你也能拿下一个从原型到前后端的完整作品。最后分享一个我经常用的AI协作小技巧让AI给你总结不如让AI给你解释。遇到看不懂的代码与其让它再生成一遍不如直接问它这个函数每一行是干什么的用最通俗的话解释。AI擅长改写把这种解释能力用好你的学习速度会比自己啃文档快很多。这次实践告一段落但这个方向可以继续延伸的东西还很多加一个管理员登录、把活动信息搬到后台动态管理、把SQLite换成MySQL、做数据可视化统计……每一个都够单独写一篇。先把这次的经验消化好下一个项目自然会走得更快。