作者:郝子旭(组长 · 后端主干 & 智能体编排)
日期:2026-03-29
本周关键词:FastAPI 脚手架、数据库 38 张表落地、用户建档链路、学习计划生成算法、代码审查与业务沉淀


一、本周整体情况

第一周,说实话节奏比我预想的还紧凑一些。

本来想的是先把脚手架搭利索、模型定义好就算第一周的活了,结果写着写着发现很多东西不往下推一步,接口的合理性就验证不了——比如建档流程不写完,就不知道状态中心的 14 个维度到底够不够用;计划生成算法不落地,就不知道任务蓝图的表结构设计有没有漏字段。所以索性一口气把认证、建档、会话消息、学习计划四个模块全都推完了。

最后盘了一下,这周一共交付了 26 个 API 端点,跑通了 10 个集成测试,还顺手沉淀了 6 份业务逻辑问题文档——后面这个其实比代码本身更值钱,后面会专门说。

下面按模块聊聊这一周干了什么,以及过程中踩的坑和一些技术选型上的考量。


二、后端脚手架:把"地基"打舒服

脚手架这东西吧,做完之后看起来平平无奇,但它决定了后面所有人写代码时的手感。我在几个地方花了不少心思:

异步数据库连接

项目用的是 SQLAlchemy 2.0 async 模式 + aiomysql。选异步不是为了赶时髦——我们后续有大量 AI 模型调用(OpenAI 兼容接口),这些调用慢起来动辄好几秒甚至十几秒。要是用同步 ORM,一个用户问一道题,整个线程就干等着模型回话,其他请求全排后面。异步模式下,等模型的时候事件循环可以去忙别的,对我们这种 AI 密集型后端来说不是锦上添花,是刚需。

连接池配置 pool_size=10, max_overflow=20,演示环境绰绰有余。这里记一个小坑:expire_on_commit=False 这个参数必须加。SQLAlchemy 默认在 commit 之后让对象过期,再碰属性会偷偷发一次查询。在异步环境里这个隐式查询特别容易炸——“在已关闭的 session 上发起查询”,排查起来很头疼。关掉它,commit 完了对象属性还好好待在内存里,清清爽爽。

统一响应格式与异常处理

全局定了 ApiResponse(code, message, data) 结构,业务异常走 BusinessException,Pydantic 校验错误自动转成 code=2000 系列。这件事做的时候没什么感觉,好处要等联调时才能真正体会——前端同学不用猜"这个接口到底返回啥格式",错误处理逻辑写一套就能通吃。

JWT 双 Token 机制

access_token 60 分钟过期,refresh_token 7 天。目前用的是固定窗口策略,refresh_token 不会因为使用而续期。要不要改成滑动窗口(每次 refresh 自动延期),取决于"用户几天没用要不要强制重新登录"这个产品判断,团队内部还没拍板。先记着,不急。


三、数据库建模:一口气把 38 张表全铺完

这一步是我觉得本周最值得的工作之一。13 个模型文件、38 张表,把整个系统的所有业务域一次性铺完了:

模型文件 覆盖的表
user.py users、user_profiles、user_preferences
state.py user_state_snapshots(14 维度日快照)
conversation.py conversations、messages、agent_route_logs
plan.py study_phase_plans、weekly_plans、daily_plans、study_tasks、study_sessions
course.py course_context_sessions、context_frames、context_ocr_blocks、course_notes、course_memories
question.py question_sets、question_items、quiz_sessions、quiz_session_items、question_records、answer_analyses
wrong_book.py wrong_questions、wrong_question_tags、review_tasks、review_records、mastery_records
mood.py mood_records、care_records
meal.py meal_menus、meal_records
learning_state.py learning_state_snapshots、advice_knowledge_items、advice_match_records、advice_push_records
report.py daily_summaries、weekly_reports、report_snapshots
config.py prompt_templates、care_rules

为什么要一口气全建完,而不是"用到哪张建哪张"?道理很简单:后面其他同学做新模块的时候,模型层已经现成的了,不用等我。比如镇亚后面做错题本,直接 import WrongQuestion 就完事,不需要再来找我对字段、等迁移。组长嘛,能帮队友少等一会儿就少等一会儿。

当然一下子铺这么多也有风险——万一需求变了要改字段呢?这就是 Alembic 的看家本领了。目前只有一个 init 迁移文件,后续有变更直接 alembic revision --autogenerate 增量处理就好,不慌。


四、用户认证服务

认证这块相对常规,5 个端点:注册、登录、刷新令牌、获取当前用户、修改密码。没什么特别出彩的地方,稳稳当当就好。

倒是有个小插曲值得记录:Schema 层做了严格的输入校验,用户名限定 ^[a-zA-Z0-9_]+$ 且 3-64 字符,密码 8-128 字符。结果 Service 层我又写了一遍密码长度判断——代码审查的时候被揪出来了,说这是冗余的"死代码",Schema 已经挡住了,Service 再判一遍纯属自我安慰。说得对。一个人写代码时确实容易下意识"保险起见多校验一遍",但维护两份同样的校验逻辑只会埋隐患。审查的价值就体现在这种地方。


五、用户画像与状态中心:整个系统的"起手式"

这是我个人觉得本周最有意思的模块。它不只是个 CRUD,建档接口是整个系统的初始化入口——用户第一次进来,一切故事都从这里开始。

建档 7 步流程

POST /profile/onboarding 这个接口背后有一套完整的初始化链路:

  1. 检查是否重复建档(幂等保护)
  2. 创建 UserProfile(目标分数、科目、阶段、薄弱科目等)
  3. 创建 UserPreference(饮食偏好、忌口、关怀风格等)
  4. 创建当天的 UserStateSnapshot(14 个维度的初始值)
  5. 同步创建 4 个默认聊天会话(主助手 / 学习助手 / 生活助手 / 心理助手)
  6. 异步触发初始计划生成(阶段建议 + 首周计划 + 今日计划)
  7. 返回完整的画像 + 偏好 + 初始状态

第 5 步和第 6 步的拆分是故意的:会话创建必须是同步的,因为用户建档一完就进主界面了,4 个聊天入口得立马能看到;计划生成丢到异步去做,因为后续要调 AI 模型,耗时不可控,总不能让用户干等在建档页面。

状态中心:系统的"数据枢纽"

user_state_snapshots 这张表是整个系统最核心的数据汇聚点。14 个维度(当前阶段、今日完成率、错题积压量、情绪分数、待复习数……)乍一看字段挺多的,但每个字段都有明确的下游消费方:

  • 情绪分数 → 学习计划根据它决定是否降载
  • 错题积压量 → 复习推荐根据它调整复习占比
  • 是否学习中 → 主动关怀根据它决定是否触发休息提醒
  • 完成率趋势 → 计划调整根据它决定是否提升/降低任务量

有一个设计决策我比较坚持:其他服务不许直接操作这张表,统一通过 ProfileServiceupdate_state_field()increment_state_field() 来更新。好处很简单——状态变更只有一个入口,后面出了 bug 不用满世界找"到底谁偷偷改了这个字段"。

建档恢复:防着网络波动

实现的时候多想了一步:如果用户建档到一半出了问题(画像存好了但偏好创建失败了),再次调建档接口时,系统会检测哪些步骤已经完成,只补做缺失的部分,而不是粗暴报个"你已经建过档了"。这在实际使用中还挺有必要的——网络一抖、客户端一崩,建档中断的情况肯定会有。


六、会话与消息服务:给聊天系统铺好路

4 个角色(主助手 / 学习 / 生活 / 心理)的聊天会话在架构上是统一的——同一张 conversations 表,用 persona 字段区分就好。消息服务管的是纯粹的数据读写,不碰任何 AI 逻辑。AI 那部分后面交给智能体编排模块来处理。

游标分页

消息查询同时支持传统分页(page + page_size)和游标分页(before_id + page_size)。聊天场景天然适合游标分页——用户往上滚加载历史消息,每次传"比这条更早的 N 条"就行了。不过这里有个接口契约的坑得跟前端对清楚:total 字段在游标模式下到底代表什么? 全量消息总数还是当前窗口内的数量?现在返回的是全量,但前端如果拿它判断"是不是还有更多历史"就会出错。已经记成 issue 了,等明翰前端开始做聊天模块的时候一起敲定。

动作协议:消息不只是文字

消息上可以挂可选动作(actions 字段),比如 AI 讲完一道题后带个"加入错题本"、"安排复习"的按钮。动作分两类:

  • 业务动作(如 add_wrong_book):点了之后前端调 POST /chat/conversations/{id}/action,后端路由到对应服务
  • 本地动作(如 take_breakopen_plan):前端自己处理,不过后端

目前业务动作的处理逻辑还都是 501 Not Implemented——错题本、复习推荐那些服务还没做呢。不过框架搭好了,后面填肉就行。


七、学习计划服务:这周写得最"肝"的模块

这个模块是本周代码量之王,光 plan.py 一个文件就写了 1060 行。核心是任务蓝图生成算法——怎么根据用户的情况,自动编排出一天的学习任务。

三级计划体系

阶段计划(foundation/strengthen/sprint/final)
  └── 周计划(本周重点科目、目标)
       └── 日计划(具体任务列表)
            ├── new_learn(新学习任务)
            ├── review(遗忘曲线复习)
            ├── wrong_review(错题回顾)
            ├── quiz(小测)
            └── flexible(弹性补位)

任务蓝图算法:不是随便塞几个任务

日计划的生成有一套完整的逻辑。算法会综合考虑:

  1. 用户画像:可用学习时长、薄弱科目、当前阶段
  2. 状态数据:最近完成率趋势、情绪分数、错题积压量
  3. 复习需求:调用复习推荐服务获取当天到期的复习任务(接口已预留,服务未实现)
  4. 错题候选:调用错题本服务获取低掌握度题目(同上)

然后按规则分配时间——复习类任务占总时长约 9%(错题堆积严重时拉到 30%),新学习任务按薄弱科目加权,弹性任务补足剩余。

不过说实话,目前这套纯规则驱动的方案我自己写完就觉得有点"硬"了。规则是死的,阈值是写死的,面对真实用户千差万别的学习节奏,光靠几条 if-else 肯定不够灵活。我心里更想做的是 AI + 规则的混合方案——规则负责兜底和约束(比如每天最多学多久、复习任务不能被跳过这种硬性保障),AI 来做更柔性的判断(比如根据用户最近的聊天情绪、学习反馈来动态调整任务难度和节奏)。现在先用纯规则把链路跑通、把接口协议定下来,后面智能体编排层起来之后,再逐步让 AI 参与到计划生成的决策环节里来。这个是后续要重点设计的方向。

动态调整:让计划"活"起来

系统不是生成完就甩手不管了,目前先落地了 4 种规则驱动的自动调整:

条件 处理
情绪 ≤ 3 且近两天完成率 < 50% 次日总时长 × 0.7
错题积压 > 10 道 复习占比上调到 30%
连续 3 天完成率 > 85% 新学习任务比例 +10%
23:59 任务仍 pending 标记 deferred → 顺延到次日

这里的设计思路是:规则管兜底,AI 管灵活。目前这些规则先把"系统不会做出离谱决策"这条底线守住,行为可预测、可调试;后续等智能体编排层就绪,我打算让 AI 介入到调整决策里——不是取代规则,而是在规则划定的安全边界内,做更细腻、更个性化的判断。比如同样是"情绪低落",规则只能粗暴地乘个 0.7,但 AI 可以结合这个用户最近聊了什么、哪科卡住了,给出更有针对性的调整建议。这块是后面要花大力气打磨的。


八、代码审查与业务问题沉淀

这周的代码经过了两轮正式审查,合计 16 个 issue。说实在的,这个过程比我预期的收获更大:

  • 改了 1 个实打实的 bug:任务完成和状态更新之间的事务一致性——原来 update_taskcomplete_task 里有多次 commit,可能出现"任务标完成了但状态没同步上"的脏状态。改成了"内部 flush + 外层单次 commit"模式,事务要么整体成功要么整体回滚
  • 确认了 5 个"非缺陷":比如"content_type 对图文混合消息标记为 text",乍一看像是 bug,其实符合协议约定
  • 记下了 6 个需要团队拍板的产品问题:单独沉淀成了文档

这 6 个产品问题我觉得比修 bug 更有长期价值,因为它们是产品语义层面的歧义,不是谁代码写错了:

  1. 计划已生成但通知失败时,回退消息该说什么?
  2. 用户把 target_hours 调到比已完成时长还小,页面怎么展示?
  3. 切换备考阶段后,今天的计划要不要立即重建?
  4. 游标分页的 total 到底是什么含义?
  5. 系统要不要支持"今天不学了"?
  6. 重新生成日计划会不会覆盖掉昨天顺延过来的任务?

这些问题没有标准答案,得组内讨论来定。我先把每个问题的背景、可选方案和我的建议都写清楚了,后面开会可以快速过。


九、本周交付物一览

类别 内容
API 端点 26 个(认证 5 + 健康 2 + 画像 7 + 会话 5 + 计划 9,含学习模式端点)
数据库 38+ 张表,13 个模型文件,Alembic 初始迁移
测试 10 个集成测试全部通过
基础设施 Docker Compose(MySQL 8.4)、完整 .env 配置模板、环境搭建文档
问题文档 6 份业务逻辑问题文档
代码审查 2 轮审查,16 个 issue 已全部定性处理

第一周收工。骨架立住了,下周让它真正"会说话"。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐