1. 为什么我选择用对话式编程从零起一个宠物生命周期管理App宠物生命周期管理这个需求乍一听像是那种做出来没人用的伪需求但我实际调研了一圈养宠人群之后发现痛点比想象中密集得多。一只猫从接回家到终老跨度可能长达十五年甚至更久这中间涉及的疫苗周期、驱虫计划、体重曲线、发情与绝育节点、慢性病用药提醒、年度体检报告归档、临终关怀决策……绝大多数铲屎官是靠脑子记、靠微信收藏、靠备忘录硬扛。信息散落在三四个App和一堆纸质单据里等到真正需要的时候——比如换了一家宠物医院医生问上次驱虫是什么时候——往往答不上来。这就是我要做这个项目的起点用一套结构化的数据模型把一只宠物从进家门到离开的全过程管起来。它不是简单的提醒事项列表而是要解决三个层次的问题。第一层是时间轴管理把疫苗、驱虫、体检、用药这些有明确周期的事件串成一条可回溯的时间线第二层是健康数据追踪体重、体温、进食量这些连续型指标要能画趋势、能对比异常第三层是决策辅助比如根据体重和年龄推算用药剂量、根据疫苗间隔判断是否该补打。那为什么标题里强调从零搭建和AI实现因为我这次刻意没有先画UML图、没有先写详细设计文档而是全程用对话式编程的方式让AI助手陪我一起把项目从空目录推到能跑起来。这个过程里踩的坑、绕的弯、以及最后总结出来的那套怎么跟AI描述需求才能一次到位的方法才是这篇博文真正想分享的东西。项目本身是个载体真正的干货是这套从零到一的人机协作开发流程。适合谁看如果你是有一定编程基础、想快速验证一个产品想法但苦于没时间写样板代码的开发者这篇会非常对味。如果你是完全的新手也能看懂因为我会把每一步的意图和判断依据都讲清楚你照着抄作业也能跑出一个能用的版本。整篇内容围绕宠物生命周期管理App这个具体场景展开但方法论可以迁移到任何CRUD为主、带一点数据可视化的中小型项目上。2. 动手之前先把数据模型想清楚否则后面全是返工2.1 宠物生命周期管理的核心实体到底有几个很多人一上来就让AI帮我写一个宠物管理App结果AI给出来的代码结构是散的因为需求本身就没收敛。我在正式让AI写第一行代码之前花了大概四十分钟只做一件事把实体和它们之间的关系在白板上画出来。这一步绝对不能省因为对话式编程最大的风险就是AI会顺着你模糊的描述自由发挥你越模糊它发挥得越离谱后面改起来比重写还累。我最终确定的核心实体是四个宠物Pet、事件Event、健康记录HealthRecord、提醒规则ReminderRule。宠物是根实体一只宠物对应多条事件、多条健康记录、多条提醒规则。事件是离散的、有明确发生时间点的东西比如2024年3月5日接种猫三联第二针。健康记录是连续的、带数值的观测比如2024年3月10日体重4.2公斤。提醒规则则是从事件和健康记录里派生出来的未来要做的事比如距离上次驱虫满90天时提醒。这里有个关键的设计决策我要解释一下为什么把事件和健康记录拆成两个实体而不是统一成一张表加个类型字段。我试过统一表的方案结果是查询逻辑变得极其恶心。事件关心的是什么时候发生的、做了什么健康记录关心的是数值是多少、趋势怎么变两者的字段重合度其实很低。硬塞进一张表要么留一堆空字段要么用JSON字段存差异化的部分前者浪费空间且约束难写后者查询和索引都难受。拆开之后事件表可以专注做时间轴展示健康记录表可以专注做图表聚合各司其职。2.2 用一段话把模型讲给AI听比贴十张图都管用确定实体之后我没有画ER图而是写了一段自然语言描述直接喂给AI。这段描述大概是这样的我要做一个宠物生命周期管理应用核心实体有宠物、事件、健康记录、提醒规则。宠物有名字、品种、出生日期、性别、绝育状态、当前体重。事件有类型疫苗/驱虫/体检/用药/其他、发生日期、备注、关联宠物。健康记录有类型体重/体温/进食量、数值、单位、记录日期、关联宠物。提醒规则有触发条件、提前天数、是否启用、关联宠物。实测下来这种实体字段关系的自然语言描述比任何图形化建模工具转出来的代码都准确。因为AI理解自然语言的能力已经足够强你给它结构化的文字它能直接映射成数据类或者数据库schema。反倒是你贴一张图它还得先做图像识别再理解中间损耗更大。这段描述我反复打磨了三遍每一遍都在删歧义。比如当前体重这个字段第一版我写的是体重AI就把它和健康记录里的体重搞混了后来改成当前体重并明确说明这是宠物表上的冗余字段为了列表页快速展示AI才没再犯错。提示给AI描述数据模型时凡是容易产生歧义的字段名都要加一句这个字段是干什么用的、和哪个字段容易混。这一句话能省掉后面至少两轮返工。2.3 技术栈选型为什么我放弃了重型框架技术栈这块我纠结了大概二十分钟。候选方案有三个一是React Native做跨平台移动端二是Flutter三是Web应用套个壳。最后我选了Web优先、移动端自适应的方案技术栈是Next.js加SQLite加Prisma。理由很实在这个项目的核心价值在数据管理和可视化不在原生体验Web方案能让我用一套代码同时覆盖桌面和手机浏览器开发调试也最快。SQLite则是单人开发阶段最省心的选择零配置、单文件、备份就是复制一个文件等真到了多用户场景再换Postgres也不迟Prisma这层ORM能把迁移成本压到很低。我把这个选型理由也同步给了AI让它知道我要的是快速验证不是生产级架构。这个上下文很重要因为如果你不说明AI默认会给你上一堆企业级的东西——什么Redis缓存、消息队列、微服务拆分对一个验证阶段的项目来说全是负担。明确告诉AI你的项目阶段它给的方案才会匹配你的真实需求。3. 让AI一次生成可运行骨架的关键分步喂需求而不是一口气全丢3.1 第一步只做数据层跑通再说很多人用AI写代码失败是因为一上来就说帮我写一个完整的宠物管理App然后AI吐出来几百行代码跑不起来报错一堆你也不知道从哪改起。我的做法是严格分层一层跑通再进下一层。第一步只让AI生成Prisma的schema文件就四个model别的什么都不做。我给AI的指令大意是基于刚才描述的数据模型生成Prisma schema数据库用SQLite注意事件类型和健康记录类型用枚举宠物和事件、健康记录、提醒规则之间是一对多关系加上创建时间和更新时间字段。AI给出的schema基本一次到位我只改了两个地方一是把枚举值的中文注释补上方便后面看二是给事件表的日期字段加了索引因为时间轴查询会频繁按日期排序。这一步跑通的标准很简单npx prisma migrate dev能成功建库npx prisma studio能打开看到四张空表。不要小看这个空表跑通的动作它是后面所有功能的地基。我见过太多人跳过这步直接写业务逻辑结果写到一半发现字段类型不对回头改schema之前写的查询全得跟着改心态直接崩。3.2 第二步生成API路由每个接口单独验证数据层稳了之后第二步是API。这里我依然没有让AI一次性生成所有接口而是按资源一个一个来。先做宠物的增删改查四个接口生成完立刻用curl或者Postman打一遍确认返回结构符合预期再做事件的接口以此类推。为什么这么磨叽因为AI生成的代码有一个特点单看每一段都对但拼在一起经常出现命名不一致、返回格式不统一的问题。比如宠物接口返回的是{ data: {...} }事件接口可能就返回裸对象。如果你一次性生成所有接口这种不一致会散落在十几个文件里找起来极其痛苦。一个一个做每做完一个就统一一次返回格式的约定后面AI会顺着前面的模式走一致性自然就保住了。这里分享一个我实测很有效的技巧在让AI生成第二个资源的接口时明确告诉它参考刚才宠物接口的返回格式和错误处理方式。AI有很强的模式跟随能力你给它一个范例它就会照着抄省掉大量重复交代。3.3 第三步才是前端而且先做列表页不做详情页前端这块我的顺序可能和很多人相反先做列表页再做详情页最后做表单。理由是列表页能最快验证数据能不能正确读出来并展示它是数据链路的终点。如果列表页能正常显示数据说明数据库、API、前端请求这三段链路全通了剩下的详情页和表单只是在通了的链路上做增补风险低得多。列表页我让AI生成的时候特意强调了移动端优先卡片式布局每张卡片显示宠物头像、名字、品种、年龄、下次提醒事项。这个下次提醒事项是个小亮点它需要前端在渲染列表时顺带查一下该宠物最近的提醒规则稍微有点复杂度但正是这种小复杂度能提前暴露API设计的问题。实测下来果然发现原本的宠物列表接口没有返回提醒信息我又回头给API加了个关联查询。如果先做简单的详情页这个问题可能要等到很后面才暴露。4. 那些AI不会主动告诉你、但一定会让你卡住的坑4.1 日期和时区宠物疫苗提醒最容易翻车的地方宠物生命周期管理里到处都是日期计算疫苗间隔21天、驱虫间隔90天、体检建议每年一次。这些计算看起来简单但只要涉及从某天算起N天后提醒时区问题就一定会冒出来。我踩的坑是这样的数据库里存的是UTC时间前端展示用的是本地时间结果一条3月5日接种的记录在某些时区下会显示成3月4日提醒也就跟着错了一天。AI生成代码时默认不会处理这个它就是用new Date()直接算。我的修复方案是所有日期在数据库里统一存成ISO格式的字符串只到日不带时间所有计算都在应用层用日期库处理展示时再格式化成用户本地习惯。具体来说我引入了dayjs并且明确规定涉及天的计算一律用dayjs的startOf(day)对齐到当天零点再算差值避免时分秒干扰。这个规则我也写进了给AI的上下文里后面它生成的日期相关代码就都带上了这个处理。注意如果你的App只服务单一地区的用户可以简化处理但存日期不存时间这个原则依然建议保留它能帮你避开绝大多数跨天计算的坑。4.2 枚举值的中英文映射别等到UI阶段才发现对不上第二个坑是枚举值。数据库里事件类型存的是VACCINE、DEWORM、CHECKUP这种英文常量前端要显示疫苗驱虫体检。我一开始偷懒直接在组件里写了个if-else映射结果这个映射在列表页、详情页、表单页各写了一遍改一个文案要改三个地方。后来我把它抽成了一个统一的常量映射文件AI生成的时候我明确要求所有枚举的中文展示都从这个文件取。这个坑的教训是凡是会在多个地方用到的映射关系一定要在第一次出现的时候就抽出来。AI不会主动帮你做这个抽象它只会就事论事地把你当前问的那段代码写对。你得自己有这个意识在指令里明确要求。4.3 表单校验的前后端一致性AI容易只顾一头第三个坑更隐蔽。表单校验这块前端要校验比如体重必须是正数、日期不能选未来后端也要校验防止绕过前端直接调接口。我让AI生成前端表单时它把校验写得很全让AI生成后端接口时它又写了一套校验。问题是两套校验的规则不一致前端允许体重填到小数点后两位后端只允许整数结果用户填了4.25前端过了后端报错体验极差。我的解决方案是把校验规则也抽成一个共享的schema用zod这类库定义一次前端后端都引用同一份。给AI的指令就变成校验规则用zod定义在shared目录下前端表单和后端接口都从这里导入。这样规则只有一处定义永远不会不一致。这个模式在对话式编程里特别值得推广因为AI很擅长照着已有的模式生成代码你只要把单一数据源这个原则立起来它就会帮你贯彻。5. 提醒引擎的实现从能提醒到提醒得准中间隔着什么5.1 提醒规则的触发逻辑该怎么设计提醒引擎是这个App的灵魂也是最容易做得似是而非的部分。最朴素的做法是每次打开App时遍历所有提醒规则算一下今天是不是触发日是就弹出来。这个做法能用但有两个问题一是用户不打开App就永远收不到提醒二是每次打开都全量计算宠物多了会卡。我采用的方案是预计算加定时任务。具体来说每条提醒规则在创建或修改时就根据它的触发条件算出下一次触发日期存到数据库里。然后有一个每天跑一次的定时任务扫描所有下一次触发日期等于今天的规则生成一条待办通知。用户打开App时只需要查今天有没有待办通知查询极快。这个设计的关键在于把计算从读的时候挪到了写的时候用一次写入时的计算换来了无数次读取时的轻量。我把这个设计思路讲给AI之后它生成的代码质量明显比我自己闷头写要高因为它会顺着预计算这个约束去组织逻辑不会写出那种每次查询都全表扫描的代码。给AI一个明确的架构约束比给它十个具体需求更能提升产出质量。5.2 提前提醒天数的处理一个容易被忽略的边界提醒规则里有个提前N天提醒的字段比如疫苗到期前3天提醒。这个字段看起来简单但边界情况不少。如果N等于0就是当天提醒如果N大于间隔周期本身呢比如驱虫间隔90天用户设了提前100天提醒那这条规则永远触发不了因为下一次触发日期减去100天还在上一次触发之前。我的处理是在保存规则时做一次校验如果提前天数大于等于间隔周期直接拒绝并提示用户。这个校验AI不会主动加你得明确要求。另外还有一个边界如果用户修改了某条事件的日期关联的提醒规则的下一次触发日期要跟着重算。这个联动逻辑我在数据层用了一个统一的重算函数任何涉及日期变更的操作都调用它保证提醒永远和实际事件对齐。5.3 通知的呈现方式别让提醒变成骚扰提醒做得太勤用户会烦做得太弱用户会漏。我的折中方案是分级呈现当天到期的提醒在App首页顶部用醒目卡片展示提前N天的提醒收在一个即将到来的折叠区里过期的提醒用户没处理用灰色标记并归入已逾期。这样用户打开App第一眼看到的是最紧急的事不会被一堆未来事项淹没。这个分级逻辑我是在前端做的后端只负责返回所有待办及其状态待处理/即将到来/已逾期。把怎么展示和有哪些数据分开是让前后端职责清晰的关键。AI生成的时候我明确说了后端只返回数据和状态枚举展示分级在前端做它就不会把展示逻辑混进API里。6. 健康数据可视化体重曲线背后的几个实现细节6.1 为什么体重曲线比想象中难画体重记录看起来就是一堆点连成线但真做起来有几个细节要处理。第一是数据点稀疏且不均匀可能这周称了三次下个月一次没称直接连线会误导用户以为体重是线性变化的。第二是单位换算有的用户习惯用斤有的用公斤存储要统一但展示要跟随用户偏好。第三是异常值处理某次称重可能因为秤不准或者宠物乱动导致数值离谱直接画进去会把整条曲线的比例尺拉爆。我的处理方案是存储统一用公斤展示层做换算曲线用平滑插值而不是直线连接并且在数据点稀疏的地方用虚线表示这段是推测的异常值用一个简单的阈值检测比如相邻两点差值超过30%就标记为可疑可疑点用不同颜色标出但不从曲线里剔除让用户自己判断。这些细节AI都不会主动想到你得把数据可能长什么样这个现实情况描述给它它才能写出健壮的代码。6.2 图表库的选择轻量优先图表库我选了Recharts理由是它基于React组件化和Next.js配合自然而且体积相对可控。ECharts功能更强但配置项太多对这个项目来说杀鸡用牛刀。选型的时候我把我只需要折线图和简单的柱状图不需要复杂交互这个约束告诉了AI它就不会给我推荐那些重型方案。实际用下来Recharts处理体重曲线这种场景绰绰有余。唯一要注意的是响应式移动端屏幕窄X轴的日期标签会挤在一起需要设置自动间隔显示。这个我在给AI的指令里加了X轴标签在移动端要能自动稀疏显示它生成的配置就带上了intervalpreserveStartEnd这类参数。6.3 数据录入的便捷性决定用户会不会坚持记录再好的可视化如果录入麻烦用户记两次就放弃了。所以我在录入这块下了点功夫体重录入支持快速选择常用值根据历史记录推荐几个接近的数值日期默认今天但可改单位跟随用户设置自动带出。这些小优化单个看都不起眼但叠加起来能把录入一次的时间从十几秒压到三五秒坚持记录的概率就高很多。这些交互细节我是分多次让AI补充的每次加一个。不要试图一次性把所有体验优化都描述清楚那样指令会变得极其冗长AI反而抓不住重点。我的节奏是先让核心功能跑通然后自己用一遍把觉得别扭的地方记下来再针对性地让AI优化。这种用一遍改一处的迭代方式比前期过度设计要高效得多。7. 从能跑到好用我做的几处关键重构7.1 把散落的日期计算收拢成一个工具模块项目跑到一半的时候我发现代码里到处都是日期计算有的地方用原生Date有的地方用dayjs有的地方自己写了个加天数的小函数。这种散落状态在功能少的时候没事功能一多就是灾难。我做了一次重构把所有日期相关的操作收拢到一个dateUtils模块对外只暴露几个语义清晰的函数addDays、diffInDays、formatDate、isToday。所有业务代码只能调这几个函数不许直接碰底层日期库。这次重构之后之前那个时区问题也顺带彻底解决了因为所有日期计算都走同一个入口我在入口处统一做了对齐处理。重构的时机很重要太早是过度设计太晚是积重难返。我的经验是当你发现同一个逻辑在三个以上地方重复出现时就该抽了。7.2 错误处理从到处try-catch改成统一中间件AI生成的代码有个通病每个接口里都包一层try-catchcatch里返回一个格式各异的错误信息。这在接口少的时候能忍接口一多就乱。我后来引入了一个统一的错误处理中间件业务代码里只管抛出自定义的业务异常中间件负责把它转成统一的错误响应格式。这个改动让代码干净了很多也让前端处理错误变得简单——所有错误响应都是同一个结构前端写一个统一的错误提示逻辑就行。统一错误格式这件事越早做越好因为它是横切关注点拖到后面改每个接口都要动。7.3 给AI的上下文做一次归档整理项目做到后期我和AI的对话已经很长了早期的一些约定它开始忘记生成的代码偶尔会偏离最初的模式。这时候我做了一件事把项目的核心约定整理成一份简短的文档包括数据模型、目录结构、命名规范、错误处理方式、日期处理原则每次开新对话或者让AI做较大改动时先把这份文档贴给它。这份文档大概就一页纸但效果立竿见影。AI拿到这份项目宪法之后生成的代码一致性明显提升。这其实揭示了一个本质对话式编程的瓶颈不在AI的能力而在你能不能在长对话中维持一致的上下文。主动维护一份约定文档就是对抗上下文漂移最有效的办法。8. 关于这套流程我踩过之后才明白的几件事第一件AI写代码快但想清楚这件事它替不了你。数据模型、技术选型、架构约束这些决策你必须自己拍板AI只能在你拍板之后帮你高效执行。我见过有人指望AI帮我设计一个App结果得到一堆看似合理但互相矛盾的建议因为AI不知道你的真实约束。第二件分步验证的价值远大于一次性生成。每跑通一层再进下一层看起来慢实际上快因为问题在最小范围内暴露修复成本最低。一次性生成一大堆代码然后debug那种痛苦我经历过一次就不想再来第二次。第三件给AI的指令里不要做什么和要做什么同样重要。明确告诉它不要引入额外依赖不要做过度抽象不要处理多用户场景能帮你挡掉大量不需要的复杂度。第四件项目跑到能用的程度之后真正的价值在于你自己用。我做完第一版之后自己录了两周的宠物数据才发现提醒的呈现方式、录入的便捷性这些地方有大量可以优化的点。这些点AI不会告诉你只有真实使用才会暴露。所以我的建议是尽早做出一个能用的版本然后自己当第一个用户用出来的问题才是真问题。这套流程我后来又用在两个小项目上基本都能在两三天内从零推到可用状态。宠物生命周期管理这个App本身也还在迭代下一步我打算加宠物照片的时间轴展示以及把体检报告的关键指标做成结构化录入。如果你也在做类似的数据管理类应用这套先模型、再数据层、再API、最后前端每层跑通再进的节奏应该能帮你少走不少弯路。