小家菜单

家庭饮食管理与 AI Agent 全栈练习项目。从需求梳理到前后端实现、数据建模、权限设计、AI 接入与部署链路,完整走了一遍全栈开发的流程。目前仍在学习中,持续补充和重构。

项目背景

普通家庭的饮食记录通常分散在聊天记录、备忘录和临时拍的图片里——菜单、库存和点单之间没有统一上下文,导致「今天吃什么」这个高频问题一直靠临场发挥解决。

这个项目想把这些信息串成一条业务链:家庭成员、菜单菜谱、冰箱食材、收藏和点单放在同一个家庭空间里,再用 AI 帮忙查询和解释饮食信息。AI 只负责只读的查询与建议,真正修改业务数据的动作仍然由用户确认后走正常接口。

它同时是我用来补齐全栈能力的练习场——重点不在做成产品,而在于把每一层都真正写一遍。

技术栈

层次技术选型承担的角色
用户端UniApp · Vue 3 · TypeScript家庭、菜单、冰箱、收藏、点单与 AI 交互,用 uni.* 统一跨端调用
管理端Vue · JavaScript家庭管理、用户审核、角色、通知与审计
后端Python · FastAPI · UvicornREST API、参数校验、鉴权与业务编排
数据层SQLAlchemy 2 async · Alembic · PostgreSQL异步 ORM、结构迁移、事务持久化
缓存Redis营养查询缓存与 AI 每日配额计数
AIOpenAI 兼容接口 · httpx · 手写 ReAct 循环对话、受限工具调用与菜品识图
AI 协议MCP 客户端 / MCP Server向外查询营养数据;向内暴露只读数据工具

后端分层设计

后端采用五层结构,避免把 SQL、权限和业务规则全部堆在路由函数里:

API 路由 → Schema → Service → Repository → Model / Database

这样做的直接好处是:普通 API、AI 工具、管理后台三个入口能复用同一套 Service 权限逻辑,不会出现某条路径绕过越权检查。

几个我在意的设计点

权限不能交给模型判断

家庭数据都带家庭标识,Service 层在查询和写入前统一做成员关系校验。客户端传来的家庭标识不被信任——真实家庭归属从已认证用户推导。

AI 工具也遵循同一条约束:不接受模型自行指定的家庭 ID,不直接拼 SQL,统一经 Service 走权限路径。因为模型输出是概率性的,如果它能自己选数据范围,就可能跨家庭读到不该读的内容。

AI 只读,写入由用户确认

Agent 提供有限的只读工具,步数有上限。需要修改数据的场景,由前端出确认卡片,用户确认后再调用正常业务接口——重新经过一遍权限与参数校验。牺牲了一点自动化程度,换来可解释、可回滚的边界。

降级优先于报错

AI 是加分项,不是主业务的单点。菜单、冰箱、家庭管理这些核心流程不依赖 AI 也能用。配置缺失、外部超时、解析失败都有可解释的降级路径,并且结果会明确标注来源,不把估算结果伪装成精确识别。

当前状态

这是一个本地练习项目,仍在学习中。功能在持续补充和重构,还没有面向真实用户运营,也不作为成熟产品对外提供服务。文中的技术选型和设计思路,是我在练习过程中真实采用并验证过的部分。

相关笔记:手写一个有限的 ReAct Agent:为什么不用框架,以及边界怎么划

← 返回首页