ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code实战:用AI从零搭建宠物生命周期管理App

Claude Code实战:用AI从零搭建宠物生命周期管理App

上周我把压箱底的"宠物生命周期管理App"想法用Claude Code从零做了出来。说从零是真的零:一个空目录、一张需求清单、一台普通电脑,没有现成代码可以抄。最终跑起来的App能管理宠物档案、疫苗记录、驱虫提醒、体重趋势,还能自动判断宠物处于哪个生命周期阶段。这个过程中,Claude Code负责了绝大部分编码工作,我做的是定方向、拆需求、验收代码、补边界情况。这篇文章把整套流程原原本本写下来,包括提示词写法、表结构设计、我在AI编程过程中踩到的典型坑,以及我对"用AI从零搭项目"这件事的边界认识。如果你只是想看AI写几个函数,那网上教程一抓一大把;如果你想真让AI帮你把一个完整项目从无到有做出来,这篇应该能帮你少走不少弯路。

1. 先想清楚再动手:宠物生命周期管理App的需求边界是怎么收敛的

决定做这个App之前,我对"生命周期管理"这个概念其实是模糊的。一开始我脑补的是宠物版社交网络,各种花里胡哨的功能往里塞:宠物圈、萌照墙、附近猫友……但真坐下来梳理时发现,这些功能跟"生命周期"四个字根本不搭。我重新拆解了一遍宠物主人的真实痛点,把"生命周期管理"收敛成三个问题:第一,我家宠物现在处于哪个阶段;第二,这个阶段它必须做哪些健康事项;第三,这些事项到时间了我怎么不会忘。

1.1 这个App到底要管住宠物的哪些"生命周期"

围绕上面三个问题,我按年龄段把宠物生命周期切成四个阶段:幼年期、成年期、中年期、老年期。每个阶段对应的健康任务和提醒强度完全不同,下面是猫的版本,这也是我第一版里最核心的业务规则。

阶段年龄范围(猫)核心任务提醒强度
幼年期0-1岁多针疫苗密集接种、驱虫频率高、体重增长快强提醒,按月
成年期1-7岁年度体检、常规驱虫、保持体重稳定中提醒,按季
中年期7-11岁体重控制、牙齿检查、肾脏早期筛查中高提醒
老年期11岁以上慢性病筛查、用药记录、行动能力观察高提醒,甚至按周

狗的阶段要再做一次体型校正,大型犬衰老速度明显比小型犬快,同样叫"7岁",小型犬还在成年期尾巴上,大型犬已经算中年了。这个规则我要求后端必须支持按物种和体型动态判定,不能写死。

1.2 用AI之前,先把自己的需求文档写成人话

既然AI那么强,需求文档是不是可以直接口述?我的答案是:可以,但代价是你得陪它一起混沌。Claude Code不会主动问"你要不要去掉宠物社交功能",它只会老老实实把你口头提到的功能全部加上,哪怕这些功能彼此矛盾。所以我的第一版需求文档写得很朴素,就叫需求单,格式如下。

需求单 v0.1 功能范围: 1. 添加/编辑/删除宠物档案 2. 宠物列表展示头像、名字、品种、年龄 3. 添加疫苗记录,显示下次接种日期 4. 疫苗到期前7天在提醒中心展示 5. 记录体重,展示体重变化趋势 6. 自动计算生命周期阶段(猫/狗) 不做: - 不做宠物社交 - 不做社区问答 - 不做多用户家庭共享 - 不做微信推送 - 不做移动端,第一版桌面浏览器优先

这份需求单里最关键的其实是"不做"部分。AI编程和人工带新人很像:你说清楚不做什么,它才不会发挥过度。我见过太多AI项目翻车,翻车原因往往不是AI能力不够,而是需求描述里给了AI太多自由发挥的空间。

1.3 MVP版本的功能清单与砍需求原则

在此基础上,我把MVP功能砍到只剩四件事:宠物档案、疫苗记录、提醒中心、体重记录。为什么砍得这么狠?因为四件事背后其实是"数据管理+时间提醒"两条主线,所有功能都围绕这两条主线展开,验收范围清晰。算下来MVP大概是20个后端接口、10个前端页面组件,这个量级Claude Code几天内能完成,我也能一个人完成代码评审。

砍需求的原则我只用了一条:这个功能如果上线第一周没人用,就先砍掉。宠物社交听起来有价值,但第一周一定没人用;疫苗到期提醒则是第一天就会用到的功能。剩下的功能优先级,完全是拿这个标尺量出来的。

2. 环境准备与项目骨架:让Claude Code真正理解"从零搭建"

需求明确之后,我开始准备开发环境。Claude Code是在终端里运行的AI编程工具,它能读取项目里已有的文件、执行终端命令、在文件之间跳转,更像一个驻场实习生,而不是那种只能聊天的AI窗口。它的工作方式决定了从零搭建一个新项目的流程和普通聊天式AI完全不同。

2.1 Claude Code的工作机制和高效启动方式

Claude Code启动方式很简单:先创建一个空目录,进入这个目录,然后在终端里启动claude命令。首次启动后它会扫描当前目录结构,发现是空目录,就会直接问你想做什么。如果你从一个已经有代码的项目里启动,它则会优先读取现有文件,把整个代码结构加载进上下文。

mkdir ~/projects/petcare cd ~/projects/petcare claude

我试过两种启动姿势。第一种是进去之后直接说"帮我写一个宠物管理App",第二种是把需求单原封不动丢给它,然后说"先读需求单,确认目录结构和技术方案,再开始搭骨架"。第二种方式效果好得多,因为它在一开始就建立了完整的问题上下文。这就像你给新同事派活,糊里糊涂说"做个App"和清楚告诉他背景、范围、边界,后者一定更靠谱。

2.2 技术栈选型:为什么选React + FastAPI + SQLite

技术栈我选的是前端Vite + React + TypeScript,后端FastAPI + SQLite。选这套组合不是因为它们最流行,而是因为它们最符合AI辅助开发的场景。

  • React + TypeScript的组件代码在训练语料里样本量巨大,Claude Code生成这类代码的质量最稳定,类型推导也相对可靠。
  • FastAPI的接口定义和参数校验几乎零成本,AI生成这类代码时很少遗漏Pydantic校验,天生适合快速搭建REST API。
  • SQLite单文件、零配置,省掉数据库服务的运维成本。宠物App的并发量很小,SQLite完全撑得住,没必要第一版就上独立数据库服务。

我不建议用特别冷门的新框架来做AI辅助开发。Claude Code见过越多的项目模式,生成的代码越靠谱,这是我在项目中期差点换技术栈时得出的教训。

2.3 用一次对话完成项目初始化

项目骨架的初始化,我要求Claude Code一次性完成。使用的提示词大概长这样。

请在这个空目录下搭建项目骨架: - 后端:FastAPI + SQLite,提供REST API,统一返回JSON - 前端:Vite + React + TypeScript,使用react-router-dom做页面路由 - 目录结构需要区分 src/components、src/pages、src/api、app/models、app/routers - 初始化git,并创建.gitignore 创建完成后,在README.md中写明启动方式,不要开始写任何业务功能。

注意最后那句"不要开始写任何业务功能"。不加这句,它很可能会顺手生成一个宠物类加一个建议接口,把骨架阶段和业务阶段混在一起。加了之后,它就老老实实只搭骨架。初始化完成后跑了一遍npm run dev和uvicorn,看到两个服务都能启动,我才放心进入下一阶段。

3. 数据模型与后端接口:AI生成代码前必须钉死的三张表

后端是整个App的底盘,底盘的核心是表结构。表结构一旦定错,后面所有AI生成的接口和前端页面都会跟着跑偏。这个阶段我花了大量时间跟Claude Code对齐数据模型,因为我知道后期改表代价很大。

3.1 核心表结构的设计细节

我跟Claude Code把项目核心表锁定为三张:pets、vaccines、reminders。设计表结构时有一个细节我后来很庆幸:疫苗记录统一用due_date表示"下次接种日期",而不是next_vaccine_date这类字段名。字段命名风格统一,能显著降低AI生成前后端代码时混用字段的概率。

CREATE TABLE pets ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, species TEXT NOT NULL CHECK (species IN ('cat', 'dog')), breed TEXT, birthday DATE NOT NULL, weight REAL NOT NULL DEFAULT 0, neutered BOOLEAN NOT NULL DEFAULT 0, chip_id TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE vaccines ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL REFERENCES pets(id), vaccine_name TEXT NOT NULL, given_date DATE NOT NULL, due_date DATE NOT NULL, clinic TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE reminders ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL REFERENCES pets(id), type TEXT NOT NULL CHECK (type IN ('vaccine', 'deworm', 'birthday', 'weight')), title TEXT NOT NULL, scheduled_date DATE NOT NULL, status TEXT NOT NULL DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP );

注意pets表里我把species字段限制成cat和dog两种取值,这是给AI的硬约束。如果不加CHECK约束,它会生成任意字符串,前端下拉框、后端校验、统计报表全都对不上。这种约束看起来不起眼,却是AI协作里最重要的护栏之一。

3.2 让Claude Code生成FastAPI接口的提示词模板

表结构定死后,再让Claude Code写接口。我用的提示词会同时包含三块内容:需求描述、数据模型、验收标准。下面的提示词是我在整个项目里最常用的一套模板。

请基于现有的模型代码生成以下API: 1. POST /pets 创建宠物 2. GET /pets 列表 3. GET /pets/{id} 详情 4. PUT /pets/{id} 更新 5. DELETE /pets/{id} 删除 6. GET /pets/{id}/vaccines 7. GET /reminders?start_date=...&end_date=... 要求: - 使用FastAPI的Pydantic做参数校验 - 所有接口返回 { "data": ... } 或 { "error": { "code": ..., "message": ... } } - created_at由数据库生成,不接受前端传入 生成后请用pytest风格写最小测试用例

加了验收标准以后,AI和我的协作效率翻倍。它会自己写测试,我只需要跑一遍pytest看到全绿,再去看几个边界用例有没有覆盖。如果不加"写测试"的要求,AI会默认只生成接口代码,然后你得自己补测试,这就把主动权又交回到了你手里。

3.3 数据库迁移与字段约束的验收方式

Claude Code对数据库迁移的处理不像专业后端那样严谨。最常见的问题是:改模型后它直接重建数据库,测试数据全部丢失。我的做法是干脆不用迁移工具,明确要求它维护一个migrations/schema.sql文件,每次改表都在文件末尾追加新版本,而不是替换旧文件。这样数据库结构变更就留痕了,回滚也方便。

另外,我让它生成一个seed.py脚本,用来填充演示数据。这个脚本会在测试环境里创建三只宠物、五条疫苗记录、八条提醒,涵盖已过期、今日到期、未来7天到期、未来30天到期四种状态。这个脚本在后端和前端联调时帮了大忙,几乎每个提醒场景都能靠它复现。

4. 前端页面的AI实现:从宠物档案表单到疫苗日历

后端接口稳定之后,进入前端页面开发。这是Claude Code发挥最亮眼的环节,因为React组件的写法高度模式化,训练样本多,生成质量稳定。但前端也不是无脑生成就能用,我有一套自己的拆分和验收方法。

4.1 组件拆分思路与提示词写法

前端我要求Claude Code按页面和组件的粒度分批生成,而不是一次性生成整个前端。一次生成20个组件,AI会顾此失彼,经常出现A页面引用了B页面还没创建的组件、路由路径对不上等问题。我拆解后依次生成了:宠物列表页、宠物详情页、疫苗表单、体重趋势组件、提醒中心页。每个页面生成时都给一句职责声明。

举一个例子,这是生成宠物详情页的提示词。

在现有项目里创建宠物详情页,路由 /pets/:id 页面职责: - 展示宠物基础信息 - 展示疫苗时间线 - 展示体重趋势图 - 进入页面时调用 GET /pets/{id} 和 GET /pets/{id}/vaccines 用 react-router-dom 的 useParams 读取 id 接口返回格式是 { data: ... },注意解包 组件文件放在 src/pages/PetDetail.tsx,写完后跑 tsc 检查类型

我会刻意把"接口返回格式是 { data: ... }"写进提示词,因为这是最容易漂移的约定。如果不写,AI有时会解包data,有时会直接用整个response对象,前后端联调时就会出现一堆难排查的undefined。

4.2 AI生成页面后我改得最多的三处

AI生成页面后,我改得最多的是三处。第一,TypeScript类型定义不一致:接口字段叫birthday,组件里却写成了birthDate。这类问题tsc检查能拦住一部分,但有些场景里AI会用as any绕过类型检查。第二,日期格式化问题:后端返回2025-06-01这种字符串,前端有的地方直接显示,有的地方new Date()之后又转成了带时间的字符串,同一个日期在页面上出现两种格式。第三,表单校验缺失:前端保存宠物时没有做必填校验,空名字也能提交。

这些问题不会让页面完全崩溃,但在实际使用体感上非常差。我处理的方式是给Claude Code提新需求时附上一句约定:"所有表单提交前做必填校验,日期统一用date-fns格式化。"后续生成的代码就慢慢把这套约定补上了。

4.3 疫苗提醒的本地推送逻辑与测试

疫苗提醒的交互,MVP版我做两件事:首页红点提醒加三个预置状态标签,待接种、即将到期、已过期。提醒逻辑很简单:后端按照due_date和当前日期计算出状态,前端拿到状态后把对应标签渲染出来。由于没有短信通道,我让Claude Code实现了一个浏览器Notification推送,页面打开时请求权限,到期的宠物会弹系统通知。

这里有个容易踩的坑:浏览器Notification不能作为唯一提醒方式,因为用户每次打开页面时才会触发。我让后端在reminders表里同时维护一个last_notified_at字段,避免用户在同一个页面停留时重复弹通知。测试时专门用seed数据放了一条昨天到期的疫苗和一条9天后到期的疫苗,验证状态计算和红点展示,确认无误后提醒功能才算真正验收通过。

5. 踩坑实录:Claude Code生成代码时最容易翻车的三类问题

用了Claude Code将近一周,整体体验是效率惊人,但翻车方式也很有规律。如果只看前面的顺利流程,你可能会误以为它是全能助手。实际上有三类问题在我的项目里反复出现,我把完整排查链路写出来,纯手工整理,全是实操经验。

5.1 幻觉依赖:它把不存在的库写得像真的一样

第一次遇到Claude Code编造依赖,是在后端加缓存时。它建议用某个缓存库,还说这是官方推荐方案。跑起来以后直接ModuleNotFoundError,查requirements才发现这个库名根本不存在。排查链路其实就是三层:

  1. 跑测试,看到红色报错;
  2. grep一下import来源,定位到一行不存在的库引用;
  3. 打开requirements.txt确认没有这个依赖,再回看对话记录,发现是AI凭印象生成的库名。

解决办法是立了一条硬规矩:Claude Code只能使用requirements.txt里已有依赖,如果需要新增依赖,必须先把包名和用途列出来让我确认。从那以后,我再也不让它自由发挥引入新库,这个习惯帮我避开了很多隐蔽问题。

5.2 改一处功能破坏另一处的回归问题

第二个高频坑是回归。Claude Code在修一个功能时,经常顺手把另一个文件里的代码改掉。这就像实习生想在A文件里加注释,结果把B文件的函数签名改了。最典型的一次:我让它修宠物详情页的日期格式,它顺手把疫苗表单的提交流程也改了,导致提交后刷新页面数据丢失。

我为此建立了一套硬性纪律:每次让Claude Code开始新任务前,先把当前所有改动用git提交。任务完成后,先跑测试和tsc再验收。如果验收时发现问题,我会要求它只描述改动点,不直接给修复方案,由我自己判断应该怎么改。这套流程让项目在持续被AI修改的过程中始终处于可用状态,即使某次它改坏了,也能快速回滚到上一个可用版本。

5.3 上下文窗口的遗忘边界:全局约定如何强制对齐

第三个问题是上下文遗忘。Claude Code虽然能读文件,但跨文件的全局约定很容易忘。比如项目约定统一用{data: ...}返回格式,到第7次对话时它写了个新接口直接返回数组。这类问题不是AI能力差,而是它每次对话都会重新评估上下文,早期对话里的约定在长对话后期逐渐被稀释。

我的解法是建一个docs/project-rules.md文件,把所有约定写进去:返回格式、命名规范、日期处理方式、禁止擅自新增依赖。每次启动新任务时,第一句话固定是"请先读docs/project-rules.md,然后完成以下任务"。这样做的效果非常明显,后续生成的代码风格漂移少了很多,验收通过率直线上升。

6. 部署上线与后续维护:AI生成项目的长期运营边界

功能开发完,接下来就是把项目送到真实环境里跑。Claude Code在开发和维护阶段帮了大忙,但部署环节仍然需要我自己操作,因为它对服务器状态、进程管理、网络配置这些环境的感知是有限的。

6.1 部署过程:本地跑通到Linux服务器的完整路径

部署方案我选了一台普通的Linux服务器。前端构建成静态文件,由开源Web服务器托管;后端用systemd作为常驻服务;SQLite数据库放在专门目录,每天凌晨用计划任务做一次备份。核心命令大致如下。

cd frontend && npm run build sudo cp -r frontend/dist /var/www/petcare # 后端的 systemd 服务负责启动 uvicorn,监听 127.0.0.1:8000

在上面加一个反向代理配置,把/api路径转发到本地8000端口。这样前端页面和后端API共用80端口,省掉跨域配置的麻烦。如果你有公网证书,建议把HTTP跳HTTPS一起配上。部署完第一件事是打开提醒中心,确认没有跨域问题,然后跑一遍完整业务流程:添加宠物、添加疫苗记录、触发提醒。

6.2 让AI继续维护代码的正确姿势

项目上线后,后续维护也得继续让Claude Code干活。我的维护请求模板长这样。

上下文:项目地址 /projects/petcare,规则文件在 docs/project-rules.md 需求描述:疫苗到期时间从固定日期改成 接种日期+有效期自动计算,允许手动覆盖 涉及文件:app/routers/vaccines.py, src/pages/VaccineForm.tsx, src/api/pets.ts 验收方式:新增单测覆盖有效期自动计算场景;前端表单显示自动计算结果但允许编辑

把需求描述、涉及文件、验收方式三件事写全,Claude Code的维护效率接近一个熟悉项目的兼职开发。如果它改坏了,git diff能帮你快速定位是哪一步引入的问题。维护阶段我感触最深的一点是:不要用聊天式对话让它瞎改,每一条维护请求都要像给正式开发提工单一样写清楚。

6.3 做完这个项目后我对"AI编程"的真实感受

最后聊聊边界。这个项目从空目录到MVP,前后大概用了一周时间,其中我真正纯手写代码的时间不超过三小时,但思考和验收的时间占了绝大部分。Claude Code最擅长的不是替你做决定,而是把你已经想清楚的方案用代码快速落一遍。它不擅长的是替你发现产品逻辑漏洞、决定UI审美偏好,以及判断"这个功能到底该不该做"。

换句话说,长期做AI辅助开发的人,架构能力和需求拆解能力反而更重要,编码能力只是被放大了。对我来说,这次用Claude Code从零搭建宠物生命周期管理App,最大的收获不是省下多少编码时间,而是逼着我把一个模糊想法拆成了可执行、可验收、可维护的工程方案。如果你也想用AI从零做完整项目,我的建议只有一条:把它当成一个行动特别快的实习生,而不是全知全能的架构师,你定方向,它执行,项目才能真正跑得起来。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进