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

发布时间:2026/10/9 23:28:18
AI辅助开发实战:用Claude Code从零搭建宠物生命周期管理App
1. 项目缘起与整体设计思路1.1 为什么选宠物生命周期管理这个方向宠物生命周期管理这个选题乍一听好像是个小众赛道但实际拆开看它覆盖的需求链条非常长。从宠物领养或购买那一刻起疫苗提醒、驱虫周期、体重曲线、发情期记录、配种管理、孕期跟踪、幼崽档案、老年病监测、临终关怀一直到离世后的纪念档案每一个节点都是独立的功能模块但彼此之间又有强关联。这种“长链路、多状态、强时序”的业务特征恰好是检验一个AI辅助开发流程是否靠谱的绝佳试金石。我选择用Claude Code从零搭建这个项目核心目的不是做一个多完美的App而是想验证一件事在真实项目里AI到底能承担多少比例的编码工作哪些环节必须人工介入哪些环节AI反而会拖后腿。宠物生命周期管理这个场景业务逻辑足够复杂但又不涉及敏感数据和高精尖算法非常适合做这种验证。1.2 技术选型的底层逻辑技术栈的选择上我定了几个硬性原则。第一必须是AI训练数据里覆盖最广的框架组合这样Claude Code生成代码的准确率最高。第二前后端要能快速联调不能把时间浪费在环境配置上。第三数据库设计要能直观反映业务实体关系方便AI理解上下文。最终选型如下层级技术选择选择理由前端框架React Native ExpoAI对RN的组件生成质量极高Expo免去原生配置状态管理Zustand轻量AI生成代码不易出错比Redux简洁后端框架FastAPIPython生态AI生成路由和模型代码准确率高数据库PostgreSQL SQLAlchemy关系型建模清晰AI对SQLAlchemy ORM支持好认证方案JWT bcrypt标准方案AI不会乱发挥部署Docker Compose一键起服务减少环境差异这套组合的核心考量是“降低AI的认知负担”。React Native的组件化思维和FastAPI的声明式路由都是AI训练数据里出现频率极高的模式。你让AI写一个Vue 3的Composition API它可能给你混着Options API写但你让它写React函数组件它几乎不会跑偏。1.3 项目模块拆解与AI分工策略整个App我拆成了六个核心模块每个模块的AI参与度不同宠物档案模块CRUD为主AI全权负责人工只做字段审核健康记录模块涉及疫苗周期计算、体重曲线AI生成基础逻辑人工校准算法繁殖管理模块状态机复杂AI生成骨架人工补全状态流转规则提醒引擎模块定时任务推送AI生成代码人工配置触发条件多宠家庭模块数据隔离和权限AI生成人工测试边界情况纪念档案模块静态展示为主AI全权负责这个分工策略的核心判断标准是业务规则的确定性越高AI参与度越高业务规则的模糊性越高人工介入越深。疫苗周期计算有明确的医学指南AI可以照做但“什么情况下该提醒用户考虑临终关怀”这种问题AI给不出靠谱答案必须人工定义规则。2. 环境搭建与Claude Code初始化实操2.1 开发环境准备清单在让Claude Code写第一行代码之前我花了大约四十分钟把基础环境搭好。这一步不能省因为AI生成的代码再准跑不起来也是白搭。以下是我实际使用的环境配置# 操作系统macOS 14.xWindows下WSL2也可但路径问题会多一些 # Node版本管理 nvm install 20.11.0 nvm use 20.11.0 # Python环境 python3 -m venv venv source venv/bin/activate pip install --upgrade pip # 全局工具 npm install -g expo-cli npm install -g anthropic-ai/claude-codeClaude Code的安装方式我试过两种全局npm安装和项目内本地安装。全局安装的好处是任何目录下都能直接调用坏处是版本管理麻烦。项目内安装更干净但每次要npx调用。我最终选了全局安装因为在这个项目里我会频繁在前后端目录之间切换全局调用更顺手。注意Claude Code首次运行需要配置API密钥。我建议把密钥放在环境变量里不要硬编码在任何项目文件中。具体做法是在~/.zshrc或~/.bashrc里加一行export ANTHROPIC_API_KEY你的密钥然后source一下。2.2 项目目录结构设计目录结构这件事很多人觉得无所谓但对AI辅助开发来说结构就是AI的“地图”。结构清晰AI生成的代码路径引用就准结构混乱AI会到处乱放文件。我最终采用的目录结构如下pet-lifecycle-app/ ├── backend/ │ ├── app/ │ │ ├── models/ # SQLAlchemy模型 │ │ ├── schemas/ # Pydantic校验 │ │ ├── routers/ # API路由 │ │ ├── services/ # 业务逻辑 │ │ └── utils/ # 工具函数 │ ├── alembic/ # 数据库迁移 │ ├── tests/ │ └── main.py ├── frontend/ │ ├── src/ │ │ ├── screens/ # 页面 │ │ ├── components/ # 通用组件 │ │ ├── stores/ # Zustand状态 │ │ ├── api/ # 接口封装 │ │ └── utils/ │ ├── App.tsx │ └── package.json ├── docker-compose.yml └── README.md这个结构的关键在于前后端完全分离但共享同一套业务术语。比如后端叫Pet前端也叫Pet后端叫HealthRecord前端也叫HealthRecord。AI在生成代码时看到前后端术语一致跨端联调的错误率会大幅下降。2.3 Claude Code初始化与项目上下文注入Claude Code启动后第一件事不是让它写代码而是给它“喂上下文”。我创建了一个CLAUDE.md文件放在项目根目录内容如下# 项目上下文 ## 项目名称 宠物生命周期管理App ## 技术栈 - 前端React Native Expo Zustand - 后端FastAPI SQLAlchemy PostgreSQL - 认证JWT ## 核心业务实体 - Pet宠物基本信息 - HealthRecord健康记录疫苗、驱虫、体重 - BreedingRecord繁殖记录 - Reminder提醒事项 - Memorial纪念档案 ## 编码规范 - Python遵循PEP8使用type hints - TypeScript使用strict模式 - API路径统一以/api/v1开头 - 所有数据库操作通过service层不在router里直接写查询 ## 禁止事项 - 不要生成任何硬编码的密钥 - 不要使用any类型 - 不要跳过错误处理这个文件的作用相当于给AI画了一个圈。实测下来有了这个文件之后Claude Code生成的代码风格一致性提升了非常多不会出现一会儿用驼峰一会儿用下划线的情况。实操心得CLAUDE.md不要写太长控制在100行以内。太长了AI反而会忽略部分内容。重点写清楚技术栈、实体关系和禁止事项就够了。3. 数据库设计与后端核心模块实现3.1 宠物档案模型设计数据库设计是整个项目的根基。我的做法是先让Claude Code根据业务描述生成初版模型然后人工逐字段审核。以下是我实际使用的Prompt请为宠物生命周期管理App设计SQLAlchemy模型包含以下实体 1. Petid, name, species, breed, gender, birth_date, weight, avatar_url, owner_id, created_at, updated_at 2. HealthRecordid, pet_id, record_type, record_date, next_due_date, notes, vet_name 3. BreedingRecordid, pet_id, partner_id, mating_date, expected_due_date, status, offspring_count 4. Reminderid, pet_id, reminder_type, remind_at, is_completed, repeat_rule 5. Memorialid, pet_id, passed_date, epitaph, photo_urls 要求 - 使用UUID作为主键 - 所有时间字段使用timezone-aware - 添加适当的索引 - 关系使用relationship声明Claude Code生成的初版模型质量相当高但有几个问题需要人工修正。第一它把species字段设成了Enum但宠物种类远不止猫狗Enum会限制扩展性我改成了String。第二repeat_rule它用了简单的字符串我改成了JSONB类型方便存储复杂的重复规则。第三它忘了给owner_id加索引这个在查询用户宠物列表时很关键。修正后的核心模型片段如下import uuid from datetime import datetime from sqlalchemy import Column, String, DateTime, ForeignKey, JSON, Index from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.orm import relationship from app.database import Base class Pet(Base): __tablename__ pets id Column(UUID(as_uuidTrue), primary_keyTrue, defaultuuid.uuid4) name Column(String(50), nullableFalse) species Column(String(30), nullableFalse) breed Column(String(50)) gender Column(String(10)) birth_date Column(DateTime(timezoneTrue)) weight Column(String(20)) avatar_url Column(String(500)) owner_id Column(UUID(as_uuidTrue), ForeignKey(users.id), nullableFalse) created_at Column(DateTime(timezoneTrue), defaultdatetime.utcnow) updated_at Column(DateTime(timezoneTrue), defaultdatetime.utcnow, onupdatedatetime.utcnow) health_records relationship(HealthRecord, back_populatespet, cascadeall, delete-orphan) breeding_records relationship(BreedingRecord, back_populatespet, foreign_keysBreedingRecord.pet_id) reminders relationship(Reminder, back_populatespet, cascadeall, delete-orphan) memorial relationship(Memorial, back_populatespet, uselistFalse) __table_args__ ( Index(idx_pet_owner, owner_id), Index(idx_pet_species, species), )3.2 疫苗周期计算服务的实现细节疫苗周期计算是这个项目里最有技术含量的部分之一。不同疫苗的接种间隔不同幼年宠物和成年宠物的接种策略也不同。我让Claude Code先生成了一个基础版本然后根据实际兽医指南做了修正。核心逻辑是这样的每种疫苗有一个基础间隔天数幼年宠物小于一岁需要额外接种加强针老年宠物大于七岁需要缩短某些疫苗的间隔。Claude Code生成的初版只考虑了基础间隔我补充了年龄分段逻辑。from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta VACCINE_INTERVALS { rabies: {base_days: 365, booster_months: 12}, distemper: {base_days: 365, booster_months: 12}, parvovirus: {base_days: 365, booster_months: 12}, bordetella: {base_days: 180, booster_months: 6}, } def calculate_next_due(pet_birth_date: datetime, vaccine_type: str, last_date: datetime) - datetime: interval VACCINE_INTERVALS.get(vaccine_type) if not interval: raise ValueError(f未知疫苗类型: {vaccine_type}) age relativedelta(datetime.utcnow(), pet_birth_date) if age.years 1: # 幼年宠物基础间隔缩短30% days int(interval[base_days] * 0.7) elif age.years 7: # 老年宠物基础间隔缩短15% days int(interval[base_days] * 0.85) else: days interval[base_days] return last_date timedelta(daysdays)注意事项这个计算逻辑我简化了实际兽医指南会更复杂比如还要考虑宠物的健康状况、疫苗品牌等。但作为项目演示这个复杂度已经足够展示AI辅助开发的能力边界了。3.3 提醒引擎的定时任务实现提醒引擎我用了APScheduler配合FastAPI的启动事件。Claude Code生成这部分代码时最大的问题是它默认用了同步的BackgroundScheduler但在FastAPI的异步环境里应该用AsyncIOScheduler。这个坑我踩过提醒任务会阻塞主线程导致API响应变慢。修正后的实现from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.interval import IntervalTrigger scheduler AsyncIOScheduler() app.on_event(startup) async def start_scheduler(): scheduler.add_job( check_and_send_reminders, triggerIntervalTrigger(minutes15), idreminder_checker, replace_existingTrue, ) scheduler.start() async def check_and_send_reminders(): now datetime.utcnow() async with AsyncSessionLocal() as session: result await session.execute( select(Reminder).where( Reminder.remind_at now, Reminder.is_completed False, ) ) reminders result.scalars().all() for reminder in reminders: await send_push_notification(reminder) reminder.is_completed True await session.commit()这个15分钟的检查间隔是我权衡后的结果。太频繁了数据库压力大太稀疏了提醒不及时。对于宠物疫苗提醒这种场景15分钟的精度完全够用。4. 前端核心页面与状态管理实现4.1 宠物列表页的组件拆分策略前端部分我让Claude Code从宠物列表页开始写。这个页面看起来简单但涉及数据获取、状态管理、下拉刷新、空状态展示等多个细节。我的Prompt策略是“先描述页面结构再让AI生成组件”。页面结构描述如下宠物列表页包含 1. 顶部导航栏标题“我的宠物”右侧添加按钮 2. 宠物卡片列表每张卡片显示头像、名字、品种、年龄、下次疫苗提醒 3. 空状态没有宠物时显示插画和引导文案 4. 下拉刷新 5. 点击卡片进入详情页Claude Code生成的组件拆分很合理它把PetCard单独拆出来了PetList负责数据获取和渲染。但有一个问题它把数据获取逻辑直接写在了组件里没有抽离到自定义Hook。我手动重构了一下把数据逻辑抽到了usePetsHook里。// hooks/usePets.ts import { useEffect, useState } from react; import { usePetStore } from ../stores/petStore; import { fetchPets } from ../api/pet; export const usePets () { const { pets, setPets } usePetStore(); const [loading, setLoading] useState(false); const [error, setError] useStatestring | null(null); const loadPets async () { setLoading(true); setError(null); try { const data await fetchPets(); setPets(data); } catch (e) { setError(e instanceof Error ? e.message : 加载失败); } finally { setLoading(false); } }; useEffect(() { loadPets(); }, []); return { pets, loading, error, refresh: loadPets }; };这个Hook抽离的好处是宠物列表页和宠物选择页可以复用同一套数据逻辑不用重复写请求代码。4.2 Zustand状态管理的Store设计状态管理我选了Zustand原因是它足够简单AI生成代码不容易出错。Redux的action、reducer、dispatch那一套AI经常生成冗余代码。Zustand一个create函数搞定AI理解起来也直接。我设计了三个StorepetStore、healthStore、reminderStore。每个Store的结构都很相似以petStore为例import { create } from zustand; import { Pet } from ../types; interface PetState { pets: Pet[]; currentPet: Pet | null; setPets: (pets: Pet[]) void; setCurrentPet: (pet: Pet | null) void; addPet: (pet: Pet) void; updatePet: (id: string, updates: PartialPet) void; removePet: (id: string) void; } export const usePetStore createPetState((set) ({ pets: [], currentPet: null, setPets: (pets) set({ pets }), setCurrentPet: (pet) set({ currentPet: pet }), addPet: (pet) set((state) ({ pets: [...state.pets, pet] })), updatePet: (id, updates) set((state) ({ pets: state.pets.map((p) (p.id id ? { ...p, ...updates } : p)), })), removePet: (id) set((state) ({ pets: state.pets.filter((p) p.id ! id) })), }));实操心得Zustand的Store不要设计得太复杂。我见过有人把API请求也塞进Store里结果Store变成了一个巨大的上帝对象。我的做法是Store只存数据API请求放在Hook或单独的api层里。4.3 健康记录页面的表单处理健康记录页面涉及表单输入包括日期选择、下拉选择、文本输入等。Claude Code生成表单代码时最大的问题是它默认用了受控组件但每个字段都写一个useState导致代码冗长。我改成了用一个对象state管理所有表单字段。const [formData, setFormData] useState({ recordType: , recordDate: new Date(), nextDueDate: null as Date | null, notes: , vetName: , }); const updateField (field: string, value: any) { setFormData((prev) ({ ...prev, [field]: value })); };这种写法比每个字段一个useState简洁得多而且AI在后续生成提交逻辑时直接formData一把梭就行不容易漏字段。表单验证我用了zod配合react-hook-form。Claude Code对这两个库的支持很好生成的schema基本不用改。const healthRecordSchema z.object({ recordType: z.string().min(1, 请选择记录类型), recordDate: z.date(), nextDueDate: z.date().nullable(), notes: z.string().max(500).optional(), vetName: z.string().max(100).optional(), });5. 常见问题与排查技巧实录5.1 Claude Code生成代码的典型问题在用了Claude Code完成这个项目之后我总结了几类它最常犯的错误。这些问题不是Claude Code独有的其他AI编码工具也有类似倾向但Claude Code的表现形式有些特点。问题一过度使用Optional。Claude Code在生成TypeScript类型时特别喜欢给字段加?。比如Pet类型它会把name、species都标成可选。这在业务上是不对的宠物名字和种类是必填的。我的应对策略是在CLAUDE.md里明确写“除非业务上确实允许为空否则不要使用可选类型”。问题二异步错误处理不完整。Claude Code生成的try-catch经常只console.log错误不向上抛出也不设置错误状态。这在生产环境里会导致用户看到无限loading。我的做法是每次生成异步代码后手动检查catch块确保错误被正确传递到UI层。问题三数据库查询N1。在生成宠物列表接口时Claude Code默认用了懒加载导致每查一只宠物就多查一次健康记录。我改成了selectinload预加载。# Claude Code生成的版本有N1问题 pets await session.execute(select(Pet).where(Pet.owner_id user_id)) # 修正后的版本 pets await session.execute( select(Pet) .where(Pet.owner_id user_id) .options(selectinload(Pet.health_records)) )5.2 前后端联调的典型坑前后端联调阶段我遇到了几个典型问题这里整理成速查表问题现象根本原因解决方案前端请求返回422Pydantic schema字段类型不匹配检查前端发送的JSON字段类型特别是日期格式跨域请求被拦截FastAPI未配置CORS添加CORSMiddleware允许前端域名JWT token过期后无提示前端未处理401响应在axios拦截器里统一处理401跳转登录页图片上传失败Expo的FormData格式与FastAPI不兼容使用FormData时设置Content-Type: multipart/form-data数据库迁移冲突Alembic版本不一致每次迁移前先alembic downgrade base再upgrade head避坑技巧前后端联调时我建议先用Postman或curl把后端接口全部测通再让前端对接。这样出问题时能快速定位是前端还是后端的问题。我一开始偷懒直接前后端一起调结果一个字段名拼写错误查了半小时。5.3 性能优化的几个关键点项目基本跑通之后我做了一轮性能优化。以下是几个见效最快的优化点第一宠物列表接口加缓存。宠物列表是访问最频繁的接口但数据变化频率很低。我加了Redis缓存TTL设了5分钟。实测接口响应时间从平均120ms降到了15ms。第二前端图片懒加载。宠物头像用的是网络图片列表长了之后加载很慢。我用了react-native-fast-image配合FlatList的windowSize参数滚动流畅度提升明显。第三数据库索引优化。除了主键索引我给owner_id、pet_id、remind_at都加了索引。特别是remind_at提醒引擎每15分钟查一次没索引的话全表扫描宠物多了之后会越来越慢。第四API响应字段裁剪。宠物列表接口一开始返回了宠物的所有字段包括created_at、updated_at这些前端不用的。我改成了只返回必要字段响应体积减少了约40%。6. AI辅助开发的边界与个人体会6.1 哪些环节AI真的能提效这个项目做下来我对AI辅助开发的边界有了比较清晰的认识。AI提效最明显的环节是样板代码生成和CRUD逻辑编写。比如宠物档案的增删改查后端路由、service、schema、前端页面、API封装这一整套Claude Code能在几分钟内生成人工只需要审核字段和业务规则。这部分工作如果手写至少需要大半天。另一个提效明显的环节是错误信息解读。遇到报错时把错误信息贴给Claude Code它给出的排查方向通常很准。特别是依赖冲突、类型不匹配这类问题它比搜索引擎快得多。6.2 哪些环节AI反而拖后腿但有些环节AI不仅不提效反而会制造麻烦。复杂状态机是第一个。繁殖管理模块的状态流转我让Claude Code生成了三版每版都有状态遗漏或非法流转。最后我手动画了状态图自己写的状态机。业务规则模糊的需求是第二个。比如“什么情况下该给用户推荐临终关怀服务”这种问题AI给不出靠谱答案它只会生成一堆if-else但每个条件的阈值都需要人工定义。性能敏感代码是第三个。AI生成的数据库查询经常有N1问题生成的React组件经常有不必要的重渲染。这些在开发阶段可能不明显但上线后会成为瓶颈。6.3 我最终的工作流经过这个项目的摸索我形成了一套相对稳定的AI辅助开发工作流人工定义数据模型和业务规则这是根基不能让AI乱来AI生成CRUD和样板代码这部分AI效率最高人工审核AI生成的代码重点看错误处理、类型定义、数据库查询AI辅助排查报错把错误信息贴给AI快速定位方向人工做性能优化和边界测试这部分AI靠不住这套工作流下我的编码效率大概提升了40%到50%。不是翻倍但已经相当可观了。关键是省下来的时间可以用在业务逻辑设计和用户体验打磨上而不是浪费在写重复的CRUD代码上。最后分享一个小技巧用Claude Code时Prompt里加上“请先解释你的实现思路再写代码”这样AI生成的代码质量会明显提升。因为它被迫先思考再动手减少了直接生成时的逻辑漏洞。这个技巧我在项目后期才发现感觉之前浪费了不少时间在修AI的“想当然”代码上。