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轴标签在移动端要能自动稀疏显示",它生成的配置就带上了interval="preserveStartEnd"这类参数。
6.3 数据录入的便捷性:决定用户会不会坚持记录
再好的可视化,如果录入麻烦,用户记两次就放弃了。所以我在录入这块下了点功夫:体重录入支持快速选择常用值(根据历史记录推荐几个接近的数值),日期默认今天但可改,单位跟随用户设置自动带出。这些小优化单个看都不起眼,但叠加起来能把录入一次的时间从十几秒压到三五秒,坚持记录的概率就高很多。
这些交互细节我是分多次让AI补充的,每次加一个。不要试图一次性把所有体验优化都描述清楚,那样指令会变得极其冗长,AI反而抓不住重点。我的节奏是:先让核心功能跑通,然后自己用一遍,把觉得别扭的地方记下来,再针对性地让AI优化。这种"用一遍改一处"的迭代方式,比前期过度设计要高效得多。
7. 从能跑到好用:我做的几处关键重构
7.1 把散落的日期计算收拢成一个工具模块
项目跑到一半的时候,我发现代码里到处都是日期计算:有的地方用原生Date,有的地方用dayjs,有的地方自己写了个加天数的小函数。这种散落状态在功能少的时候没事,功能一多就是灾难。我做了一次重构,把所有日期相关的操作收拢到一个dateUtils模块,对外只暴露几个语义清晰的函数:addDays、diffInDays、formatDate、isToday。所有业务代码只能调这几个函数,不许直接碰底层日期库。
这次重构之后,之前那个时区问题也顺带彻底解决了,因为所有日期计算都走同一个入口,我在入口处统一做了对齐处理。重构的时机很重要,太早是过度设计,太晚是积重难返。我的经验是:当你发现同一个逻辑在三个以上地方重复出现时,就该抽了。
7.2 错误处理从"到处try-catch"改成统一中间件
AI生成的代码有个通病:每个接口里都包一层try-catch,catch里返回一个格式各异的错误信息。这在接口少的时候能忍,接口一多就乱。我后来引入了一个统一的错误处理中间件,业务代码里只管抛出自定义的业务异常,中间件负责把它转成统一的错误响应格式。
这个改动让代码干净了很多,也让前端处理错误变得简单——所有错误响应都是同一个结构,前端写一个统一的错误提示逻辑就行。统一错误格式这件事,越早做越好,因为它是横切关注点,拖到后面改,每个接口都要动。
7.3 给AI的上下文做一次"归档整理"
项目做到后期,我和AI的对话已经很长了,早期的一些约定它开始"忘记",生成的代码偶尔会偏离最初的模式。这时候我做了一件事:把项目的核心约定整理成一份简短的文档,包括数据模型、目录结构、命名规范、错误处理方式、日期处理原则,每次开新对话或者让AI做较大改动时,先把这份文档贴给它。
这份文档大概就一页纸,但效果立竿见影。AI拿到这份"项目宪法"之后,生成的代码一致性明显提升。这其实揭示了一个本质:对话式编程的瓶颈不在AI的能力,而在你能不能在长对话中维持一致的上下文。主动维护一份约定文档,就是对抗上下文漂移最有效的办法。
8. 关于这套流程,我踩过之后才明白的几件事
第一件,AI写代码快,但"想清楚"这件事它替不了你。数据模型、技术选型、架构约束这些决策,你必须自己拍板,AI只能在你拍板之后帮你高效执行。我见过有人指望AI"帮我设计一个App",结果得到一堆看似合理但互相矛盾的建议,因为AI不知道你的真实约束。
第二件,分步验证的价值远大于一次性生成。每跑通一层再进下一层,看起来慢,实际上快,因为问题在最小范围内暴露,修复成本最低。一次性生成一大堆代码然后debug,那种痛苦我经历过一次就不想再来第二次。
第三件,给AI的指令里,"不要做什么"和"要做什么"同样重要。明确告诉它"不要引入额外依赖""不要做过度抽象""不要处理多用户场景",能帮你挡掉大量不需要的复杂度。
第四件,项目跑到能用的程度之后,真正的价值在于你自己用。我做完第一版之后自己录了两周的宠物数据,才发现提醒的呈现方式、录入的便捷性这些地方有大量可以优化的点。这些点AI不会告诉你,只有真实使用才会暴露。所以我的建议是:尽早做出一个能用的版本,然后自己当第一个用户,用出来的问题才是真问题。
这套流程我后来又用在两个小项目上,基本都能在两三天内从零推到可用状态。宠物生命周期管理这个App本身也还在迭代,下一步我打算加宠物照片的时间轴展示,以及把体检报告的关键指标做成结构化录入。如果你也在做类似的数据管理类应用,这套"先模型、再数据层、再API、最后前端,每层跑通再进"的节奏,应该能帮你少走不少弯路。