【OpenHarmony/HarmonyOs 】数学知识点掌握度评估:基于正确率的端侧学习分析实践
【OpenHarmony/HarmonyOs 】数学知识点掌握度评估:基于正确率的端侧学习分析实践
项目类型:OpenHarmony / HarmonyOS ArkTS 数学学习应用
项目名称:数学视界
对应主题:端侧 AI、元服务能力集成、隐私保护方案
关键词:端侧分析、知识点掌握度、正确率、题库筛选、学习画像、ArkTS 🎯
一、这篇和“挑战模块拆解”有什么区别?
另一个项目已经写过“知识挑战模块拆解”,所以这篇不再泛泛讲挑战页流程,而是聚焦数学项目里更有区分度的部分:如何基于答题结果,在端侧评估学生对数学知识点的掌握度。
在数学视界中,题库不是随便放一组题,而是围绕:
- 年级;
- 知识点;
- 分类;
- 难度;
- 题型;
- 答题结果;
- 正确率;
- 最近挑战记录。
这些数据组合起来,就可以形成一个轻量的端侧学习分析系统。
二、年级体系:从小学到高中
项目中定义了 12 个年级:
export const GRADES: Grade[] = [
{ id: 'g1', name: '一年级', shortName: '小一', level: 1 },
{ id: 'g2', name: '二年级', shortName: '小二', level: 2 },
{ id: 'g3', name: '三年级', shortName: '小三', level: 3 },
{ id: 'g7', name: '七年级', shortName: '初一', level: 7 },
{ id: 'g10', name: '高一', shortName: '高一', level: 10 },
{ id: 'g12', name: '高三', shortName: '高三', level: 12 },
]
真实代码里每个年级还有:
color:主题色;bgColor:背景色;icon:展示图标;description:学习内容描述;sortOrder:排序字段。
这让挑战页可以根据年级展示不同的学习入口,而不是简单写死按钮。
三、知识点体系:数学学习分析的核心
项目中的知识点覆盖几何、代数、函数、概率、三角、数论、应用题等分类:
export interface KnowledgePoint {
id: string
name: string
shortName: string
category: string
icon: string
color: string
bgColor: string
description: string
grades: string[]
difficulty: number
questionCount: number
sortOrder: number
}
一个知识点示例:
{
id: 'kp_quadratic_func',
name: '二次函数',
shortName: '二次',
category: '函数',
icon: '📈',
description: '二次函数的图像、开口、顶点',
grades: ['g9', 'g10', 'g11'],
difficulty: 4,
questionCount: 0,
sortOrder: 17
}
这种结构非常适合端侧分析,因为每一道题都可以绑定一个或多个知识点,答题结果也能反向统计到知识点上。
四、题库筛选:按年级和知识点取题
项目中的题库筛选函数很清晰:
export function getQuestionsByGradeAndKnowledge(
gradeId: string,
knowledgeIds: string[]
): Question[] {
if (knowledgeIds.length === 0) {
return getQuestionsByGrade(gradeId)
}
return QUESTION_BANK.filter((q: Question): boolean =>
q.gradeId === gradeId &&
knowledgeIds.some((kid: string): boolean =>
q.knowledgeIds.indexOf(kid) >= 0
)
)
}
这个函数支持两种模式:
- 没选知识点:返回该年级全部题;
- 选了知识点:只返回对应知识点相关题目。
挑战页使用它来构建题池:
let pool: Question[] =
getQuestionsByGradeAndKnowledge(
this.selectedGradeId,
this.selectedKnowledgeIds
)
这就是后续“智能组卷”的基础。
五、难度过滤:让练习更精细
挑战配置中还支持难度过滤:
if (this.selectedDifficulty > 0) {
pool = pool.filter((q: Question): boolean =>
q.difficulty === this.selectedDifficulty
)
}
然后再随机抽题:
const questions: Question[] = shuffleQuestions(pool, this.selectedCount)
shuffleQuestions() 使用 Fisher-Yates 洗牌:
export function shuffleQuestions(questions: Question[], count: number): Question[] {
const shuffled: Question[] = [...questions]
for (let i: number = shuffled.length - 1; i > 0; i--) {
const j: number = Math.floor(Math.random() * (i + 1))
const temp: Question = shuffled[i]
shuffled[i] = shuffled[j]
shuffled[j] = temp
}
return shuffled.slice(0, Math.min(count, shuffled.length))
}
这样可以避免每次练习都出现同样顺序,提升练习的新鲜感。
六、挑战结果:端侧分析的数据来源
每次答题完成后,会生成 ChallengeResult:
const resultData: ChallengeResult = {
id: Date.now().toString(),
config: this.config ?? { gradeId: '', knowledgeIds: [], questionCount: 0 },
startTime: this.questionStartTime - totalTime * 1000,
endTime: Date.now(),
questions: challengeQuestions,
correctCount,
totalCount: this.questions.length,
totalTime,
score,
gradeId: this.config?.gradeId ?? '',
knowledgeIds: this.config?.knowledgeIds ?? [],
isCompleted: true,
}
这里面最适合分析的是:
questions:每道题的作答情况;correctCount:正确数量;totalCount:总题数;score:本次得分;gradeId:年级;knowledgeIds:本次练习覆盖的知识点。
这些数据都在端侧生成,不需要上传到服务器。
七、统计总成绩:整体正确率和最好成绩
recordChallengeResult() 会累计整体数据:
recordChallengeResult(result: ChallengeResult): void {
const stats = this.challengeStats
stats.totalChallenges++
stats.totalQuestions += result.totalCount
stats.totalCorrect += result.correctCount
stats.totalTimeSpent += result.totalTime
if (result.totalCount > 0) {
stats.averageScore =
Math.round((stats.totalCorrect / stats.totalQuestions) * 100)
}
if (result.score > stats.bestScore) {
stats.bestScore = result.score
}
}
这部分用于回答几个基础问题:
- 用户一共挑战了多少次?
- 一共做了多少题?
- 总正确率是多少?
- 最高分是多少?
- 总学习时长是多少?
这已经是学习报告的基础。
八、知识点正确率:端侧掌握度评估
项目里最关键的函数是 getKnowledgeCorrectRate():
private getKnowledgeCorrectRate(knowledgeId: string): number {
let total = 0
let correct = 0
for (let i = 0; i < this.challengeStats.recentResults.length; i++) {
const r = this.challengeStats.recentResults[i]
for (let j = 0; j < r.questions.length; j++) {
if (r.questions[j].question.knowledgeIds.indexOf(knowledgeId) >= 0) {
total++
if (r.questions[j].isCorrect) correct++
}
}
}
return total > 0 ? correct / total : 0
}
它的逻辑非常直接:
- 遍历最近挑战结果;
- 找出包含某个知识点的题;
- 统计总题数和正确题数;
- 返回正确率。
这就是一个本地掌握度模型:
- 正确率低于 60%:需要复习;
- 正确率 60% 到 80%:需要巩固;
- 正确率高于 80%:可以挑战更高难度。
九、从正确率到学习建议
基于这个函数,可以很自然地生成学习建议:
function buildMasteryText(rate: number): string {
if (rate < 0.6) {
return '建议先复习概念和例题'
}
if (rate < 0.8) {
return '已经入门,适合继续专项练习'
}
return '掌握较好,可以尝试限时挑战'
}
这类建议虽然不是大模型生成的,但非常可解释。学生知道为什么系统推荐他复习,因为最近正确率确实偏低。
端侧 AI 不一定要复杂。对学习应用来说,“准确、透明、可解释”往往比“看起来很智能”更重要。
十、掌握年级和掌握知识点
项目会把达到一定正确率的知识点加入 masteredKnowledge:
if (stats.masteredKnowledge.indexOf(kid) < 0) {
const correctRate = this.getKnowledgeCorrectRate(kid)
if (correctRate >= 0.7) {
stats.masteredKnowledge.push(kid)
}
}
年级掌握度也类似:
if (stats.masteredGrades.indexOf(result.gradeId) < 0) {
const correctRate = this.getGradeCorrectRate(result.gradeId)
if (correctRate >= 0.7) {
stats.masteredGrades.push(result.gradeId)
}
}
这里用 0.7 作为掌握阈值,简单但有效。后续可以继续细化:
- 至少答过 10 道题才计算掌握;
- 最近 7 天权重更高;
- 高难度题权重更高;
- 连续两次达标才标记掌握。
十一、隐私保护:学习画像留在本地
知识点掌握度听起来像“学习画像”,确实需要谨慎。数学视界当前的好处是:这些数据都在本地 AppState 中完成。
不会上传:
- 学生错了哪些题;
- 哪个知识点薄弱;
- 学习时长;
- 得分;
- 收藏内容。
这和“禁止 AI 识图、精细化权限管控”的主题是一致的。不是不做智能,而是优先做端侧智能。
十二、元服务扩展:今日一题与薄弱点复习
如果未来把这个能力接到元服务,可以做两个轻量入口:
- 今日一题:根据最近薄弱知识点抽一道题;
- 薄弱点复习:展示 3 个正确率较低的知识点。
数据来源完全可以复用:
const rate = this.getKnowledgeCorrectRate(knowledgeId)
这样元服务不需要重新建一套学习系统,只需要从已有端侧统计中取数据。
十三、总结
这篇文章的重点不是挑战页 UI,而是数学知识点掌握度分析,和另一个项目的“挑战模块拆解”区分开了。
核心实现包括:
- 🎓 用
GRADES建立年级体系; - 🧩 用
KnowledgePoint建立知识点体系; - 📚 用
getQuestionsByGradeAndKnowledge()进行题池筛选; - 🎲 用
shuffleQuestions()做随机抽题; - 📊 用
ChallengeResult保存答题结果; - 🧠 用
getKnowledgeCorrectRate()计算知识点正确率; - 🏅 用
masteredKnowledge和masteredGrades标记掌握状态; - 🔐 全部分析在端侧完成,不上传学习画像。
对数学学习 App 来说,这种端侧掌握度评估非常实用。它既能支撑智能推荐,又能保护隐私,还能自然扩展到今日一题、薄弱点复习、学习报告等元服务场景。🚀

更多推荐

所有评论(0)