引言

        大家好,我是山东大学软件学院2023级本科生张钧虹,“字节摇篮队”负责人。从这一周开始,我的关注点不再停留雨“想法是否合理”的讨论中,我更在意另外一个问题:这个项目到底应该先怎么落地,才能尽快从概念走向原型。

        对我来说,这一周最重要的工作并不是简单地多写几个页面、多开几个接口,而是要先把BabyMind的第一条核心链路真正跑通。因为只有当一条真实的数据流建立起来之后,项目才不再是“功能设想的堆叠”,而开始变成一个可以持续迭代的系统。

        因此,这一周我主要围绕三个目标推进开发:

  1. 梳理并推动前后端基础骨架成型;
  2. 明确数据库和宝宝档案的数据模型设计;
  3. 优先打通“用户注册登录—宝宝档案录入—数据持久化”这条主链路。

一、从“做什么”转向“先做什么”:我重新思考了项目推进顺序

        在项目刚启动的时候,我不断的设想应该如何在前端和后端实现AI相关功能,比如多Agent、RAG、语音交互、智能问答、营养推荐等。但这一周我在真正推进开发时,越来越强烈地意识到:一个项目早期最重要的,不是空想,而是基础框架的搭建。

        BabyMind想做的内容很多,但如果一开始就试图同时铺开所有模块,很容易出现一种情况:每个方向都做了一点,但没有任何一条流程真的能完整跑通。对我来说,这种状态是非常危险的,因为它会导致项目看似“进度很多”,实际上却始终停留在“碎片化开发”的层面。

        所以这一周我在思考项目推进顺序,确定第一条最优先推进的业务链路:

                用户注册/登录→创建宝宝档案→宝宝信息持久化→为后续模块提供个性化上下文

        BabyMind后续无论做提醒、健康记录、疫苗计划、营养推荐还是AI问答,不可能脱离宝宝的具体信息。换句话说,宝宝档案不是一个附属页面,而是整个系统后续智能能力的入口。这一周的推进思路就是先把这一条主线从前端、后端到数据库完整建立起来,而不是一开始就把精力分散在太多方向上。


二、宝宝档案设计

        宝宝档案是整个BabyMind系统的上下文中心,作为信息录入模块,包含姓名、性别、出生日期、孕周、过敏信息、备注等字段

1、为其他模块的agent提供个性化宝宝信息

        BabyMind做的是0-3岁婴幼儿科学育儿辅助,这个场景要求回答和建议必须尽可能贴近具体宝宝本身的情况。

        比如:

  • 同样是辅食添加问题,6个月和18个月宝宝的建议一定不同;
  • 同样是成长节律问题,是否早产会直接影响判断;
  • 同样是喂养或营养建议,是否存在食物过敏会成为重要限制条件;
  • 同样是健康问答,宝宝的年龄、病史、背景信息都可能影响回答的风险等级。

        因此,在我看来,宝宝档案并不是“一个先填一下的信息页”,而是系统后续进行个性化推荐、结构化问答和成长分析的前提。

2、数据库设计的基础

        除此之外,后面的很多模块对应的数据库表设计,都会直接依赖它。

例如:

  • 提醒模块需要根据出生日期计算月龄,生成不同阶段的成长提醒;
  • 疫苗模块需要根据出生日期生成接种计划;
  • 营养模块需要读取过敏信息和年龄背景;
  • AI问答模块需要把宝宝信息作为Prompt上下文的一部分;
  • 时间轴模块也要围绕一个宝宝去聚合事件。

三、项目骨架搭建:前端—后端—数据库的完整链路

1、后端分层

        一开始就把职责拆开,而不是把所有逻辑都塞进路由函数里:

  • api负责暴露接口;
  • schemas负责请求响应结构和字段校验;
  • models负责数据库实体;
  • services负责业务逻辑;
  • core负责配置、安全与通用能力。

        这样做的好处是,随着后续健康记录、提醒、时间轴、问答、营养等模块不断加入,系统不会迅速变成一个“所有逻辑都混在一起的大文件集合”。

2、前端、后端和数据库链路

        这周我完成了下面这条前端、后端和数据库链路完整闭环:

                Android前端录入宝宝信息→ViewModel发起请求→FastAPI后端接收请求→Service层处理逻辑→ORM模型写入MySQL→返回结果再同步回前端。

       这使得BabyMind具备端到端的数据流能力。后续无论我要继续做提醒、健康记录、营养推荐还是AI问答,都可以建立在这条已经被验证过的链路之上。

        下面我用几个关键代码文件来说明,这条链路是怎样一步步建立起来的。

(1)前端接口定义:先把“宝宝档案创建”变成真实请求

        在Android端,我首先要明确:前端到底要向后端发送什么请求。对应接口定义位于:

  • frontend/app/src/main/java/com/babymind/network/ApiService.kt

        宝宝档案新增与更新接口如下:

@GET("babies")
    suspend fun getBabies(@Header("Authorization") token: String): Response<List<BabyProfile>>
    @POST("babies")
    suspend fun createBaby(@Header("Authorization") token: String, @Body request: BabyCreateRequest): Response<BabyProfile>
    @PUT("babies/{baby_id}")
    suspend fun updateBaby(
        @Header("Authorization") token: String,
        @Path("baby_id") babyId: Int,
        @Body request: BabyCreateRequest
    ): Response<BabyProfile>
(2)前端状态管理:把页面输入真正送进后端

        仅仅定义接口还不够,我还需要让页面里用户输入的内容,真正进入请求链路。对应逻辑位于:

  • frontend/app/src/main/java/com/babymind/ui/viewmodel/BabyViewModel.kt

        其中宝宝档案创建逻辑如下:

    fun createBaby(request: BabyCreateRequest, onDone: (Boolean) -> Unit = {}) {
        val token = sessionManager.getAuthToken() ?: run {
            onDone(false)
            return
        }
        viewModelScope.launch {
            try {
                val response = RetrofitClient.instance.createBaby("Bearer $token", request)
                if (response.isSuccessful) {
                    fetchBabies()
                    onDone(true)
                } else {
                    onDone(false)
                }
            } catch (_: Exception) {
                onDone(false)
            }
        }
    }

        编辑更新逻辑如下:

    fun updateBaby(babyId: Int, request: BabyCreateRequest, onDone: (Boolean) -> Unit = {}) {
        val token = sessionManager.getAuthToken() ?: run {
            onDone(false)
            return
        }
        viewModelScope.launch {
            try {
                val response = RetrofitClient.instance.updateBaby("Bearer $token", babyId, request)
                if (response.isSuccessful) {
                    fetchBabies()
                    onDone(true)
                } else {
                    onDone(false)
                }
            } catch (_: Exception) {
                onDone(false)
            }
        }
    }
(3)后端路由:把前端请求正式接入FastAPI

        前端请求发出去之后,后端必须有明确的入口接收它。对应代码位于:

  • app/api/routers/babies.py

        宝宝档案创建接口如下:

@router.post("", response_model=BabyProfileRead, status_code=status.HTTP_201_CREATED)
def create_baby(
    payload: BabyProfileCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> BabyProfileRead:
    baby = create_baby_profile(db, current_user, payload)
    return BabyProfileRead.model_validate(baby)

        宝宝档案更新接口如下:

@router.put("/{baby_id}", response_model=BabyProfileRead)
def update_baby(
    baby_id: int,
    payload: BabyProfileUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> BabyProfileRead:
    baby = get_baby_profile_for_user(db, current_user, baby_id)
    if baby is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Baby profile not found.")
    updated = update_baby_profile(db, baby, payload)
    return BabyProfileRead.model_validate(updated)

        这一部分非常关键,不仅实现了接口功能,还通过get_current_user明确了数据归属关系:宝宝档案不是全局共享数据,而是属于当前登录用户的私有数据。这一点对于后续多用户隔离和真实产品逻辑来说非常重要。

(4)Service层:把宝宝档案真正写进数据库

        在后端部分,我把写库逻辑放到了Service层,把接口接收参数和业务逻辑处理分开。这样后续如果我要继续在宝宝档案创建时附带生成默认提醒、初始化营养画像,或者触发更多联动逻辑,就可以继续在Service层扩展,而不用打乱整个接口结构。对应代码位于:

  • app/services/baby_service.py

        创建逻辑如下:

def create_baby_profile(db: Session, user: User, payload: BabyProfileCreate) -> BabyProfile:
    baby = BabyProfile(user_id=user.id, **payload.model_dump())
    db.add(baby)
    db.commit()
    db.refresh(baby)
    return baby

        更新逻辑如下:

def update_baby_profile(db: Session, baby: BabyProfile, payload: BabyProfileUpdate) -> BabyProfile:
    for field, value in payload.model_dump(exclude_unset=True).items():
        setattr(baby, field, value)
    db.add(baby)
    db.commit()
    db.refresh(baby)
    return baby
(5)对象关系映射ORM

        将数据库表baby_profiles映射为类BabyProfile,对应代码位于:

  • app/models/baby_profile.py

        宝宝档案模型核心字段如下:

class BabyProfile(Base):
    __tablename__ = "baby_profiles"
    id: Mapped[int] = mapped_column(primary_key=True, index=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    gender: Mapped[str | None] = mapped_column(String(20), nullable=True)
    birth_date: Mapped[date] = mapped_column(Date, nullable=False)
    gestational_weeks: Mapped[int | None] = mapped_column(nullable=True)
    food_allergies: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    drug_allergies: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    medical_history: Mapped[str | None] = mapped_column(Text, nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

(6)Schema层:保证进入数据库之前的数据是干净的

        在后端对接口输入输出的数据结构进行统一约束,校验前端提交的数据是否合法,同时规范后端返回给前端的数据结构。对应代码位于:

  • app/schemas/baby.py

基础结构如下:

class BabyProfileBase(BaseModel):
    name: str = Field(min_length=1, max_length=100)
    gender: str | None = Field(default=None, max_length=20)
    birth_date: date
    gestational_weeks: int | None = Field(default=None, ge=20, le=45)
    food_allergies: list[str] = Field(default_factory=list)
    drug_allergies: list[str] = Field(default_factory=list)
    medical_history: str | None = Field(default=None, max_length=2000)
    notes: str | None = Field(default=None, max_length=2000)

同时我也很关注字段校验和清洗逻辑,例如:

    @field_validator("birth_date")
    @classmethod
    def validate_birth_date(cls, value: date) -> date:
        if value > date.today():
            raise ValueError("birth_date cannot be in the future")
        return value

    @field_validator("food_allergies", "drug_allergies", mode="before")
    @classmethod
    def normalize_allergy_list(cls, value: object) -> list[str]:
        if value is None:
            return []
        if not isinstance(value, list):
            raise ValueError("allergy fields must be arrays of strings")

四、当前存在的问题与我接下来的计划

        接下来我比较关注的几个方向是:

1、继续基于宝宝档案向外扩展业务能力

        既然宝宝档案已经成为系统入口,那么下一步我会更关注如何让它真正驱动后续模块,比如提醒生成、疫苗计划和健康记录。

2、进一步推进前后端联调

        只有当更多真实页面真正接上后端接口,很多隐藏问题才会暴露出来。后续我会继续关注Android页面与FastAPI接口之间的字段一致性、返回结构和状态管理问题。


五、结语

        这一周我主要搭前后端骨架、梳理数据库结构、实现宝宝档案全链路、验证前后端数据库连接存储。项目正从设想一步步实现,后面的提醒、健康、时间轴、营养和AI问答将在这个基础上逐渐形成一个完整系统。接下来,我会继续沿着这条路径,把BabyMind的核心业务链路一点点补全。

        欢迎各位老师、同学批评指正!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐