【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
}

它的逻辑非常直接:

  1. 遍历最近挑战结果;
  2. 找出包含某个知识点的题;
  3. 统计总题数和正确题数;
  4. 返回正确率。

这就是一个本地掌握度模型:

  • 正确率低于 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 识图、精细化权限管控”的主题是一致的。不是不做智能,而是优先做端侧智能。

十二、元服务扩展:今日一题与薄弱点复习

如果未来把这个能力接到元服务,可以做两个轻量入口:

  1. 今日一题:根据最近薄弱知识点抽一道题;
  2. 薄弱点复习:展示 3 个正确率较低的知识点。

数据来源完全可以复用:

const rate = this.getKnowledgeCorrectRate(knowledgeId)

这样元服务不需要重新建一套学习系统,只需要从已有端侧统计中取数据。

十三、总结

这篇文章的重点不是挑战页 UI,而是数学知识点掌握度分析,和另一个项目的“挑战模块拆解”区分开了。

核心实现包括:

  • 🎓 用 GRADES 建立年级体系;
  • 🧩 用 KnowledgePoint 建立知识点体系;
  • 📚 用 getQuestionsByGradeAndKnowledge() 进行题池筛选;
  • 🎲 用 shuffleQuestions() 做随机抽题;
  • 📊 用 ChallengeResult 保存答题结果;
  • 🧠 用 getKnowledgeCorrectRate() 计算知识点正确率;
  • 🏅 用 masteredKnowledgemasteredGrades 标记掌握状态;
  • 🔐 全部分析在端侧完成,不上传学习画像。

对数学学习 App 来说,这种端侧掌握度评估非常实用。它既能支撑智能推荐,又能保护隐私,还能自然扩展到今日一题、薄弱点复习、学习报告等元服务场景。🚀

img

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐