研途灵伴 · 第一周开发博客:后端基础服务与核心业务链路搭建
作者:郝子旭(组长 · 后端主干 & 智能体编排)
日期: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 这个接口背后有一套完整的初始化链路:
- 检查是否重复建档(幂等保护)
- 创建 UserProfile(目标分数、科目、阶段、薄弱科目等)
- 创建 UserPreference(饮食偏好、忌口、关怀风格等)
- 创建当天的 UserStateSnapshot(14 个维度的初始值)
- 同步创建 4 个默认聊天会话(主助手 / 学习助手 / 生活助手 / 心理助手)
- 异步触发初始计划生成(阶段建议 + 首周计划 + 今日计划)
- 返回完整的画像 + 偏好 + 初始状态
第 5 步和第 6 步的拆分是故意的:会话创建必须是同步的,因为用户建档一完就进主界面了,4 个聊天入口得立马能看到;计划生成丢到异步去做,因为后续要调 AI 模型,耗时不可控,总不能让用户干等在建档页面。
状态中心:系统的"数据枢纽"
user_state_snapshots 这张表是整个系统最核心的数据汇聚点。14 个维度(当前阶段、今日完成率、错题积压量、情绪分数、待复习数……)乍一看字段挺多的,但每个字段都有明确的下游消费方:
- 情绪分数 → 学习计划根据它决定是否降载
- 错题积压量 → 复习推荐根据它调整复习占比
- 是否学习中 → 主动关怀根据它决定是否触发休息提醒
- 完成率趋势 → 计划调整根据它决定是否提升/降低任务量
有一个设计决策我比较坚持:其他服务不许直接操作这张表,统一通过 ProfileService 的 update_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_break、open_plan):前端自己处理,不过后端
目前业务动作的处理逻辑还都是 501 Not Implemented——错题本、复习推荐那些服务还没做呢。不过框架搭好了,后面填肉就行。
七、学习计划服务:这周写得最"肝"的模块
这个模块是本周代码量之王,光 plan.py 一个文件就写了 1060 行。核心是任务蓝图生成算法——怎么根据用户的情况,自动编排出一天的学习任务。
三级计划体系
阶段计划(foundation/strengthen/sprint/final)
└── 周计划(本周重点科目、目标)
└── 日计划(具体任务列表)
├── new_learn(新学习任务)
├── review(遗忘曲线复习)
├── wrong_review(错题回顾)
├── quiz(小测)
└── flexible(弹性补位)
任务蓝图算法:不是随便塞几个任务
日计划的生成有一套完整的逻辑。算法会综合考虑:
- 用户画像:可用学习时长、薄弱科目、当前阶段
- 状态数据:最近完成率趋势、情绪分数、错题积压量
- 复习需求:调用复习推荐服务获取当天到期的复习任务(接口已预留,服务未实现)
- 错题候选:调用错题本服务获取低掌握度题目(同上)
然后按规则分配时间——复习类任务占总时长约 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_task和complete_task里有多次 commit,可能出现"任务标完成了但状态没同步上"的脏状态。改成了"内部 flush + 外层单次 commit"模式,事务要么整体成功要么整体回滚 - 确认了 5 个"非缺陷":比如"content_type 对图文混合消息标记为 text",乍一看像是 bug,其实符合协议约定
- 记下了 6 个需要团队拍板的产品问题:单独沉淀成了文档
这 6 个产品问题我觉得比修 bug 更有长期价值,因为它们是产品语义层面的歧义,不是谁代码写错了:
- 计划已生成但通知失败时,回退消息该说什么?
- 用户把 target_hours 调到比已完成时长还小,页面怎么展示?
- 切换备考阶段后,今天的计划要不要立即重建?
- 游标分页的 total 到底是什么含义?
- 系统要不要支持"今天不学了"?
- 重新生成日计划会不会覆盖掉昨天顺延过来的任务?
这些问题没有标准答案,得组内讨论来定。我先把每个问题的背景、可选方案和我的建议都写清楚了,后面开会可以快速过。
九、本周交付物一览
| 类别 | 内容 |
|---|---|
| API 端点 | 26 个(认证 5 + 健康 2 + 画像 7 + 会话 5 + 计划 9,含学习模式端点) |
| 数据库 | 38+ 张表,13 个模型文件,Alembic 初始迁移 |
| 测试 | 10 个集成测试全部通过 |
| 基础设施 | Docker Compose(MySQL 8.4)、完整 .env 配置模板、环境搭建文档 |
| 问题文档 | 6 份业务逻辑问题文档 |
| 代码审查 | 2 轮审查,16 个 issue 已全部定性处理 |
第一周收工。骨架立住了,下周让它真正"会说话"。
更多推荐
所有评论(0)