拓冰建站拓冰建站
首页 / 资讯中心 / 正文

在线教育平台学习路径推荐与进度可视化功能开发实战

简介本资源是面向Android开发初学者与项目实践者的博学谷BoXueGuApp功能增强版聚焦UI优化与用户流程完善在原项目基础上新增圆形头像显示、欢迎界面倒计时、找回密码后自动跳转登录页、每日签到功能及本地更换头像等5项实用特性。压缩包共383个文件涵盖64个XML布局与资源定义文件、58个Java业务逻辑类、159个编译后Class字节码含CircleImageView、ActionSheetDialog、UserInfoActivity等关键组件、66个PNG图标资源及20个SO库支持多架构运行整体体积45.63MB结构完整、即导即用。已有734人学习下载配套博文详细解析各功能实现原理与关键代码段。读者可直接导入Android Studio工程含project、classpath配置快速掌握自定义View、Activity跳转控制、SharedPreferences持久化签到状态、Bitmap头像裁剪与保存等典型Android开发技能。1. 项目背景与功能需求拆解1.1 BoXueGu 平台现状与本次新功能的定位收到名为“BoXueGu—新增新功能.zip”的压缩包时第一反应是这大概率是某个线上教育类项目的一次迭代更新包。BoXueGu博学谷这类在线学习平台核心用户是学生和职场提升人群常见的痛点集中在三块课程内容虽多但找不到适合自己的学习路径、学习过程中缺少即时反馈、学完就忘且没有有效的复习机制。这次拿到的新功能包从命名看属于功能增量而非重构意味着我们需要在保证老用户使用习惯不受影响的前提下把新能力平滑地嵌进现有业务链路里。我解压后看了下目录结构典型的前后端分离工程后端以 Java 为主前端是 Vue 全家桶配套了数据库变更脚本和部署说明文档。从包内文件命名能推测这次新增的功能大概率围绕“学习路径个性化推荐”和“课程进度可视化追踪”这两个方向展开。为什么这么判断一是目录里包含了 recommendation-engine 和 learning-analytics 相关的模块二是数据库脚本里新增了 user_learning_path 和 course_milestone 两张表。对于在线教育平台来说这两块恰好是提升用户留存和完课率的关键抓手。1.2 用户痛点的深挖与需求转化在看具体代码之前我习惯先把需求文档翻出来对照。在线教育平台表面上是“内容为王”但实际上“服务体验”才是决定用户是否续费的核心。想象一下一个典型场景一个新注册用户面对上千门课程没有明确方向随便点开一个课学了两天发现难度不合适于是流失。另一个场景一个老用户已经学完了一门中级课程系统却还在给他推荐初级内容体验割裂。这两个问题本质上都是“平台不知道用户该学什么”和“平台不知道用户学得怎么样”造成的。把这两个场景翻译成技术需求就变成用户画像建模需要采集用户的基础信息、学习行为点击、停留、完成率、测评结果形成可计算的特征向量。课程内容打标现有课程必须补齐难度等级、知识点标签、前置依赖关系等元数据否则推荐引擎无米下锅。路径动态调整用户的推荐路径不能是一次性算完就不管的必须根据实时学习进度和测评反馈动态微调。数据可视化用户端需要能直观看到“我学到哪了”“我离目标还有多远”这需要里程碑节点和学习热力图的支持。1.3 需求评审中的关键决策和产品过了两轮需求评审有几个决策点比较关键写出来供参考。第一MVP最小可行产品范围怎么划团队一开始想一口气把所有功能都做上包括社区互动、直播预约、学习币激励等。但考虑到迭代周期和稳定性最终确定本次只做“学习路径推荐 进度可视化”这条主链路其他功能排到下一版本。第二推荐算法用协同过滤还是基于内容的推荐团队里有人提出直接用深度学习模型。我当时的意见是我们的冷启动问题非常严重新用户没有行为数据协同过滤根本跑不起来。而基于内容知识点标签、难度、用户自评目标的规则加权推荐虽然朴素但在当前数据量级下效果最可控、可解释性也最强。最终决定采用“规则轻量算法”的混合方案先跑通再迭代。第三数据库变更要不要做兼容这次新增两张业务表同时要在现有课程表上增加打标字段。老数据必须做一次性回填否则推荐引擎上线后会把没有标签的课程全过滤掉导致部分课程“隐形”。这个在开发计划里被单独列为一项风险任务。2. 技术方案选型与架构设计2.1 后端推荐引擎的设计思路既然定了“规则轻量算法”的混合方案具体落地时我把它拆成三个子模块特征采集模块、推荐计算模块、路径管理模块。特征采集模块负责把用户的离散行为点开课程、完成章节、提交测评转成结构化记录。这里有个容易踩坑的地方——事件上报的时机。最开始设计时打算用定时任务批量拉取日志表但实时性太差用户上午学完一个章节下午推荐路径还没变化体验很糟。后来改成了 MQ 异步消费 定时兜底的策略用户在端上产生关键行为时前端调用后端事件接口后端把事件写入消息队列推荐计算服务实时消费并更新该用户的临时特征缓存同时每天凌晨两点跑一次全量批计算修正长期画像。推荐计算模块核心是一个多因子加权公式。我用四个维度给课程打分知识点匹配度课程标签与用户当前学习目标的余弦相似度。难度适配度课程难度与用户最近一次测评能力值的差值差值越小分越高。热度修正同类课程中完课率、好评率高的课程获得小幅加分权重控制在0.1以内防止头部效应淹没个性化。新鲜度惩罚用户已经学过的课程直接排零避免重复推荐。权重初始化的时候知识点匹配度占比最高0.5难度适配度次之0.3其他两项分剩余权重。这套权重不是拍脑袋定的而是结合历史完课率数据做了简单回归分析后取的初值后续每周根据线上转化情况做一次 A/B 调参。路径管理模块负责把推荐结果编排成一条可执行的“学习路径”。我把路径抽象成节点序列每个节点包含课程 ID、预计学习时长、关联里程碑 ID。用户在端上看到的是一条从“当前能力”到“目标能力”的阶梯式路线每完成一个节点路径自动解锁下一个节点。2.2 前端可视化方案选型进度可视化在技术选型上有两条路一是用成熟的图表库ECharts、AntV G2二是自研 SVG 组件。考虑到这次需要一个“学习路径地图”的交互界面节点之间要有连线、要有进度状态色块、还要支持点击跳转我选了 AntV G2 配合自定义 DOM 覆盖层的方式。为什么不用 EChartsECharts 图表能力强但要做到节点可拖拽、自定布局这种精细交互灵活度不如直接操作 DOM 少量矢量图形。数据可视化分三层总览层用户整体学习进度环形图显示已学时长/目标时长百分比。路径层学习路径的节点连线图清楚展示当前处于哪一步。里程碑层每个里程碑的完成任务列表带完成状态勾选。三层之间通过一个 React 组件树管理状态存在 Redux 里用户切换 Tab 时不需要重新请求数据。2.3 数据库表结构核心设计新增的 user_learning_path 和 course_milestone 两张表在字段设计上我花了不少心思。这里直接给出精简版的 DDL 和字段说明方便理解-- 用户学习路径主表 CREATE TABLE user_learning_path ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 用户ID, path_name VARCHAR(128) NOT NULL COMMENT 路径名称, target_level INT NOT NULL COMMENT 目标能力等级(1-5), current_node_id BIGINT COMMENT 当前所处节点ID, status TINYINT NOT NULL DEFAULT 0 COMMENT 0-进行中 1-已完成 2-已放弃, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_user_status (user_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户学习路径; -- 路径节点表一个路径包含多个节点 CREATE TABLE user_learning_path_node ( id BIGINT PRIMARY KEY AUTO_INCREMENT, path_id BIGINT NOT NULL COMMENT 路径ID, course_id BIGINT NOT NULL COMMENT 课程ID, node_order INT NOT NULL COMMENT 节点顺序(从1开始), expected_hours DECIMAL(5,2) NOT NULL COMMENT 预计学习时长(小时), milestone_id BIGINT COMMENT 关联里程碑ID, status TINYINT NOT NULL DEFAULT 0 COMMENT 0-未开始 1-进行中 2-已完成 3-已跳过, UNIQUE KEY uk_path_course (path_id, course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT学习路径节点表; -- 课程里程碑表 CREATE TABLE course_milestone ( id BIGINT PRIMARY KEY AUTO_INCREMENT, course_id BIGINT NOT NULL COMMENT 课程ID, milestone_name VARCHAR(128) NOT NULL COMMENT 里程碑名称, required_chapter_ids VARCHAR(512) NOT NULL COMMENT 需要完成的章节ID集合(逗号分隔), bonus_points INT DEFAULT 0 COMMENT 完成奖励积分, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY idx_course (course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程里程碑表;两张表之间通过 path_id 关联。user_learning_path_node 里的 milestone_id 是逻辑外键指向 course_milestone 的 id方便在路径图上直接展示里程碑节点。这里特别注意一点status 字段我用的是 TINYINT 而不是 ENUM。ENUM 在 MySQL 里的扩展性比较差后面要加一个“暂停”状态就得改表结构而 TINYINT 加个注释就能搞定查询和索引效率也更高。3. 核心功能实现细节与实操过程3.1 用户特征的采集与实时计算用户特征采集是推荐系统的地基。我在实现时基于 Spring Boot 的拦截器 注解做了一套轻量埋点机制。前端在用户完成关键行为时调用/api/v1/events接口后端通过自定义注解TrackEvent标记对应方法执行完毕后自动组装事件对象。核心事件类型就四种COURSE_VIEW用户进入课程详情页CHAPTER_COMPLETE用户完成一个章节QUIZ_SUBMIT用户提交一次测评STUDY_DURATION用户单次学习时长前端每5分钟上报一次心跳事件对象统一结构如下public class UserLearningEvent { private Long userId; private String eventType; // 事件类型 private Long targetId; // 目标ID课程ID/章节ID/测评ID private Integer durationSec; // 本次行为的持续时长秒 private Long timestamp; // 事件发生时间戳 private MapString, Object extra; // 扩展字段如测评得分 }事件先进入 RocketMQ 的learn-event-topic消费者服务拿到后做两件事第一更新 Redis 中的用户短期行为窗口保存最近 200 个行为第二异步写入 HBase 用于离线分析。为什么用 HBase因为行为日志的写入量远超 MySQL 能承受的量级而且 HBase 天然的列族结构适合按用户维度存储时间序列行为数据。用户能力值的实时更新逻辑是这样的每次用户提交测评后根据得分和题目难度用 IRT项目反应理论里的简化公式估算能力值。实际项目里我用的不是完整 IRT而是它的一个实用变体——把测评得分线性映射到 1-5 的等级再结合最近三次测评的加权平均权重按时间衰减最近一次权重 0.5前一次 0.3再前一次 0.2。这个策略简单且实测能比较好地避免单次考试失误导致的推荐大幅波动。3.2 推荐计算的核心算法实现推荐计算我写在独立的RecommendationService里核心逻辑分三步走第一步获取用户当前画像。从 Redis 拿短期行为数据最近 7 天从 MySQL 拿长期画像能力等级、学习目标、历史完成课程列表。第二步候选课程筛选。从课程库里捞取所有状态为“上架”且用户未学过的课程遍历计算四个维度得分public double scoreCourse(UserProfile profile, Course course) { // 1. 知识点匹配度余弦相似度 double matchScore cosineSimilarity(profile.getTagVector(), course.getTagVector()); // 2. 难度适配度差值越小分越高 double diffScore 1.0 - Math.abs(profile.getAbilityLevel() - course.getDifficultyLevel()) / 4.0; // 3. 热度修正完课率与好评率的线性组合 double hotScore 0.6 * course.getCompletionRate() 0.4 * course.getPositiveRate(); // 4. 新鲜度惩罚已学课程直接返回0 if (profile.getLearnedCourseIds().contains(course.getId())) { return 0.0; } // 加权求和 return 0.5 * matchScore 0.3 * diffScore 0.2 * hotScore; }第三步按分数降序取 Top N默认 10再拼接成学习路径节点序列写入 user_learning_path_node。拼接时有一个细节需要保证节点之间的课程在知识点上有递进关系。所以 Top N 课程不是简单按分数排完事而是用了一个贪心策略——从得分最高的课程开始每选一个节点课程就要求下一个节点的课程与当前节点的课程知识点相似度不能低于 0.3。这个约束能有效把“东一榔头西一棒槌”的推荐串成有逻辑的路径。推荐结果的缓存策略也提一下每个用户的学习路径在 Redis 里缓存 30 分钟。用户完成一个章节后推荐服务会被触发重新计算但计算完成后会保留原有路径中未学习的节点只追加新推荐节点。这样避免用户每次刷新都看到一条全新的路径减少认知负担。3.3 前端学习路径地图的实现过程前端这部分我负责的是路径地图组件技术栈是 Vue 3 TypeScript AntV G2。组件名叫LearningPathMap.vue核心功能是渲染用户的学习路径节点并展示当前学习状态。组件内部维护了一个pathData对象结构如下interface PathNode { id: number; courseName: string; nodeOrder: number; expectedHours: number; status: locked | current | completed | skipped; milestoneName?: string; } interface PathData { pathName: string; targetLevel: number; currentProgressPercent: number; nodes: PathNode[]; }页面加载时调用后端接口/api/v1/learning-path/{userId}获取全量路径数据。接口返回后组件在onMounted生命周期里先渲染总览环形图再渲染路径节点地图。节点地图的布局我采用了横向时间轴结构最左边是起点用户当前能力最右边是终点目标能力中间每个节点按 nodeOrder 依次排列。每个节点画成一个卡片卡片底色按状态区分已完成绿色底右上角打勾进行中蓝色底带“正在学习”角标未开始灰色底已跳过黄色底带“跳过”标记节点之间的连线用 SVG path 绘制曲线类型选了smooth贝塞尔曲线视觉上更柔和。鼠标悬浮在节点上时显示 Tooltip包含预计学习时长、里程碑名称、课程简介摘要。实现过程中有个坑值得记录AntV G2 的坐标系在组件销毁时如果不调用chart.destroy()会造成内存泄漏。尤其在用户频繁切换 Tab 的场景下页面会越来越卡。我们的代码在beforeUnmount里统一加了销毁逻辑onBeforeUnmount(() { if (progressChart.value) { progressChart.value.destroy(); } });还有一个交互细节用户点击某个节点卡片时会跳转到对应课程详情页并把滚动位置定位到课程大纲模块。这里用了 Vue Router 的带 query 跳转课程详情页监听到courseId参数后自动滚动到目标位置。这个小功能虽然不复杂但极大提升了学习路径和课程的联动体验。3.4 里程碑逻辑与奖励机制里程碑功能相对独立它的后端逻辑在MilestoneService里。用户完成一个课程的全部指定章节后系统自动判定里程碑达成。判定的触发时机是“章节完成事件”到达时消费端调/api/v1/milestone/check接口。判定逻辑我特意做了幂等处理Transactional public void checkAndCompleteMilestone(Long userId, Long courseId) { // 查询该课程所有里程碑 ListCourseMilestone milestones milestoneMapper.selectByCourseId(courseId); // 查询用户已完成的章节集合 SetLong completedChapterIds chapterProgressMapper.selectCompletedChapterIds(userId, courseId); for (CourseMilestone milestone : milestones) { // 已达成跳过 if (userMilestoneMapper.exists(userId, milestone.getId())) { continue; } ListLong requiredIds parseIds(milestone.getRequiredChapterIds()); boolean allCompleted requiredIds.stream().allMatch(completedChapterIds::contains); if (allCompleted) { userMilestoneMapper.insert(userId, milestone.getId(), LocalDateTime.now()); // 加积分 pointService.addBonus(userId, milestone.getBonusPoints(), MILESTONE); } } }这里幂等处理很关键。消息队列消费是“至少一次”语义如果章节完成事件被重复投递没有幂等保护就会产生重复积分。我用 user_milestone 表的唯一索引user_id, milestone_id作为第二道保障即使并发请求进来数据库也会拒绝重复插入。用户端里程碑展示的是一串成就卡片每个卡片有锁定态和完成态两种样式。完成态卡片会显示达成时间并且伴随一个短暂的动画效果放大缩小后恢复。这个动画用 CSS transition 实现不做额外库依赖性能表现很好。4. 测试策略与上线部署实录4.1 数据回填与一致性校验这次上线最大的风险点不在代码逻辑而在存量数据的迁移。课程表新增了 difficulty_level 和 knowledge_tags 两个字段上线前必须保证全量课程都有值。我们在测试环境造了两类数据验证一类是手工构造的 200 门课程覆盖 5 个难度级别、20 个知识点标签另一类是从生产库脱敏复制的 1 万门真实课程。回填脚本用 Python 写的从课程表和章节表读取数据通过关键词规则 人工抽检的方式补充标签。这里分享一个判断标签质量的技巧回填完成后抽查 100 门课程把每门课的知识点标签生成一个词云然后让教研同事人工核对。如果词云里课程标题的核心词没有出现在标签里说明打标逻辑有问题需要调规则。这个步骤虽然费时间但能避免推荐引擎上线后出现“标签与内容严重不符”的尴尬。数据一致性校验我写了三个 SQL 查询-- 检查是否有课程缺少难度级别 SELECT COUNT(*) FROM course WHERE difficulty_level IS NULL; -- 检查是否有课程标签为空 SELECT COUNT(*) FROM course WHERE knowledge_tags IS NULL OR knowledge_tags ; -- 检查学习路径节点是否引用了不存在的课程 SELECT clpn.id FROM user_learning_path_node clpn LEFT JOIN course c ON clpn.course_id c.id WHERE c.id IS NULL;上线前这三个检查必须全部返回 0否则不允许发布。4.2 接口压测与性能调优推荐计算接口和路径查询接口是本次的核心接口压测目标定的是 QPS 大于 500P95 延迟小于 500ms。压测工具用的 JMeter测试环境配置是 4 核 8G 的云主机模拟 200 个并发用户持续压测 20 分钟。第一轮跑完结果不太理想推荐接口 P95 延迟 1.2s路径查询接口 P95 延迟 800ms。排查过程是这样的推荐接口慢在候选课程遍历上。课程库有 1 万门课每门课都要算一次余弦相似度虽然单次计算只要 0.1ms但 1 万次累加就是 1s。优化方案是引入 Redis 缓存课程特征向量并做了一个简单的倒排索引根据用户目标标签先筛出前 200 门候选课程再对 200 门做精确打分。这样计算量直接从 1 万降到 200接口响应时间降到 150ms 左右。路径查询接口慢在 SQL 上。原语句没有利用到联合索引每次查询都走了全表扫描。优化方式是给 user_learning_path_node 表加了KEY idx_path_order (path_id, node_order)联合索引并调整查询条件只取 status ! 3 的节点减少数据传输量。优化完成后重新压测推荐接口 P95 延迟 180ms路径查询接口 P95 延迟 100msQPS 稳定在 800 以上达标。4.3 灰度发布与监控告警上线流程我们走的是标准的灰度发布先在预发环境验证 2 天然后生产环境按 5%、20%、50%、100% 四步放量。每步之间观察 30 分钟重点看三个指标接口错误率不能超过 0.1%推荐点击率灰度期间推荐位点击率是否明显低于旧版本这里如果低于旧版的 80%要立即停止放量日志异常数RocketMQ 消费堆积量是否持续增长监控告警用 Prometheus AlertManager配置了三个核心告警规则接口错误率超过 5% 持续 5 分钟P1 告警电话通知消息队列积压超过 10 万条持续 15 分钟P2 告警钉钉通知推荐服务 CPU 使用率超过 85% 持续 10 分钟P2 告警钉钉通知灰度期间真的抓到过一个隐藏 bug5% 流量放量后有用户反馈“学习路径页面打不开”。查日志发现是路径节点时间轴组件在部分浏览器版本下解析 SVG 曲线时报错。定位到是某个旧版 Chrome 对path命令的smooth曲线语法兼容性问题。修复方案是给推荐路径地图组件加了一个renderer降级策略当检测到浏览器不支持平滑曲线时自动退回折线绘制。这个兼容性坑没有真实用户流量基本测不出来因为测试环境大家都用最新版 Chrome。5. 常见问题与排查技巧实录5.1 推荐结果一直不变上线后收到的最多反馈就是“推荐怎么老不更新”。排查思路先看两个地方第一用户事件是否正常上报到 MQ第二推荐服务消费后有没有触发重新计算实际排查中发现一个典型案例用户完成了章节 A但章节完成事件在 Redis 里已经写入推荐服务却没感知到。最后定位是消息队列消费组配置的问题——推荐服务消费的是learn-event-topic这个主题但消息的生产者把事件发到了learn-event-topic-pre预发环境主题。配置不一致导致消费端订阅不到消息。这个问题的预防措施是在代码里加一个环境变量强校验生产环境启动时检查生产者与消费者的 Topic 配置必须一致不一致直接拒绝启动。5.2 前端地图出现多余节点有段时间测试同学反馈进度地图上会出现一些不该存在的节点比如用户已经学完课程 B但地图上仍显示课程 B 待学。原因是节点状态更新逻辑里没有做“已完成课程反查”。具体来说用户在推荐路径之外自己主动通过搜索功能学习了课程 B。这种情况下user_learning_path_node表里课程 B 的状态仍然是“未开始”。而节点的状态更新只依赖学习路径上下文没有联动全局学习记录。修复方案是在节点状态初始化时增加一道校验查询用户全量章节完成记录如果某节点对应的课程所有章节都已学完自动将该节点状态置为“已完成”并顺延更新后续节点的推荐逻辑。5.3 积分重复发放里程碑积分曾经出现过重复发放的情况。原因不是幂等逻辑失效而是消息重试机制生产者在发送QUIZ_SUBMIT事件后由于网络抖动RocketMQ 客户端重试发送了一次但第一次消息其实已经到达消费端并完成了里程碑判定。第二次消息到达后消费端重新触发判定。虽然user_milestone表有唯一索引兜底但这条链路里点券服务的积分发放是在同一个事务里提交的如果数据库事务隔离级别设置不当并发场景下两个事务可能都读到“不存在记录”然后都执行了插入其中一个被唯一索引挡住后回滚但积分加减操作因为属于远程调用无法回滚。修复措施是把积分发放从本地事务里拆出来改为先插入 user_milestone 记录带唯一索引插入成功后再发送一个“积分发放”的异步消息。这样即使消息重发了里程碑记录插入也会被唯一索引挡住不会触发第二次积分发放。5.4 压测数据下 SQL 慢查询排查清单上线后运维偶尔会发现几个慢 SQL我把排查思路整理成清单方便自查症状可能原因排查命令路径列表加载慢缺少联合索引EXPLAIN SELECT ... WHERE path_id ? AND status ! 3推荐接口超时候选集过大SHOW PROCESSLIST 查看是否有长时间运行的查询里程碑判定慢子查询全表扫描检查 required_chapter_ids 字段是否走索引事件入库慢批量插入 buffer 太小查看 RocketMQ 消费端日志是否频繁 flush6. 功能上线后的效果验证与后续规划6.1 上线两周的核心数据变化功能全量上线两周后拉了几组核心数据做效果评估学习路径功能使用率约 38% 的周活跃用户点击过学习路径页面其中 41% 的用户点击了路径推荐课程。完课率对比使用学习路径功能的用户两周内完成至少一门课程的比例是 19.2%而未使用路径推荐功能的老用户同指标只有 8.7%。提升效果显著。平均学习时长使用路径地图的用户日均学习时长 42 分钟比其他用户高出约 15 分钟。里程碑达成率上线第一周有 1200 多名用户达成了至少一个课程里程碑累计发放积分 5 万余点。虽然这些数据会受用户群体差异影响能主动打开学习路径的用户本身学习意愿更强但整体趋势足以说明方向是对的。6.2 推荐算法后续迭代方向目前这套规则加权推荐在“冷启动”场景下表现不错但也暴露了局限性。比如对于学习目标模糊的用户没有主动选择目标等级推荐结果比较平淡。后续准备在两个方向迭代第一个方向是引入协同过滤做补充。等用户行为数据积累到一定程度后训练一个基于物品的协同过滤模型ItemCF根据“学完 A 的人也学了 B”的规律做召回。这能发现规则引擎发现不了的跨知识点关联。第二个方向是做强化学习式的路径动态调整。当前路径调整粒度是“章节完成”级别响应已经够快但精细度不够。后续计划把调整频率细化到“小节学习”级别并且引入 A/B 测试框架自动评估不同路径顺序对完课率的影响。6.3 代码结构与团队协作的经验沉淀这次迭代除了功能本身团队在工程协作上也攒了不少经验分享三点第一需求评审阶段一定要统一数据字典。比如“完成”这个概念产品视角是“学完全部章节”运营视角是“章节测验及格”技术视角是“前端上报了 CHAPTER_COMPLETE 事件”。如果不提前拉齐开发到一半就会发现接口定义对不上。第二数据库变更脚本要有版本管理。这次我们用了 Flyway 做数据库版本管理所有 DDL 变更都走 migration 脚本禁止手工在测试库执行 SQL。好处是任何环境测试、预发、生产的库表结构都能从脚本完全复现排除了“测试环境改了表结构但生产环境没改”这种低级问题。第三压测不要只压接口要压全链路。第一次压测我们只压了推荐接口发现 P95 延迟很低但一放开全链路压测就发现瓶颈在 MQ 消费端的上游——数据库写入线程池打满。所以压测一定要从网关到数据库全链路串起来做才能发现真实瓶颈。写在最后的体会这次“BoXueGu 新增新功能”的迭代从拿到压缩包到全量上线用了三周时间整体节奏比较紧凑但也踩了不少坑。我个人最深的体会是在线教育平台的“个性化推荐”技术难点不在算法本身多深奥而在数据链路的完整性和业务规则的可解释性。规则引擎虽然“土”但胜在稳定可控、出问题能快速定位等用户量和数据量都上来了再逐步升级模型能力也不迟。如果你也在做类似的学习平台功能建议先把“用户事件埋点 - 特征存储 - 推荐计算 - 前端展示”这条闭环跑通后续的优化才有抓手。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门