一、起点:不想再让她刷题刷到哭
女儿上小学,数学作业最让人头疼的不是不会做,而是"明明会,但是粗心"。同一类错误反反复复出现,传统的做法是买一堆同步练习册,让她刷题刷到熟练为止。
但刷题解决不了"粗心"这件事。粗心的根源往往是审题不细、没有检查的习惯,靠题量堆不出来。
我是做企业信息化系统出身的,天天和Oracle、Python、ERP系统打交道,就想着:能不能用代码把"怎么审题、怎么检查"这件事变成一个孩子愿意主动做的游戏,而不是家长在旁边催"你看清楚题目了吗"。
于是就有了"数学冒险岛"——一个用Python写的、专门给小学1-3年级孩子用的数学学习桌面软件。
这篇文章想聊两件事:怎么把几个靠谱的学习方法论真正做进软件的交互设计里,以及开发过程中一次让我印象很深的Bug排查——不是什么惊天动地的系统崩溃,但足够说明"看起来正常"和"真正没问题"之间,隔着一次认真的实测。
二、教学法怎么变成代码
市面上大部分"数学学习App"本质是刷题机——出题、判对错、下一题。我想做的不是这个。
解题七步法:每道题不能直接列算式,得先走完"读题→找条件→找问题→选方法→列算式→检查→总结"七个环节。软件里这对应七个独立的界面状态,右侧有个进度条,每一步都要求孩子实际输入内容才能进入下一步——目的是把"审题"这个动作,从"应该做"变成"不做不行"。
费曼学习法:第一步"读题"要求孩子用自己的话复述一遍题目在讲什么。如果只是校验字数够不够,这个环节形同虚设——随便打两个字就能过。所以后来接了大模型,让AI判断孩子是不是真的理解了题意,理解不到位会提示一次,但第二次点击一定会放行,不会把孩子卡在这一步出不去。这个"逃生阀"设计我觉得挺重要:AI偶尔会误判,如果因为一次误判就把孩子困住,体验会非常挫败。
错题不是重做,是"复仇战":孩子答错的题不会立刻要求重做,而是被记录成一只"怪兽"(粗心怪、计算怪、读题怪、单位怪、概念怪、检查怪),3天后才会在"训练营"里以变体形式重新出现。这是心理学上验证过的间隔重复原理,也是我特意留出来的一个"父女共创"空间——怪兽的名字和形象设计,本来就是打算让她自己参与想的,比我一个人闭门造车更有代入感。
这三件事,任何一件只做在UI表面(比如"看起来"有七个步骤,但后台照样能直接跳过)都没意义。真正的工作量都在数据结构层:错题要不要出现在训练营,看的是一个具体的日期字段比较;AI判不判理解,看的是有没有配置好接口、以及有没有触发过"逃生阀"。
三、技术路线:从网页原型到PyQt5桌面版
最早的版本设想是网页端,理由很直接——跨平台、免安装、随时能改。但真正做起来,发现几个问题跟"孩子专注学习"这个场景是冲突的:
- 网页版离不开浏览器,浏览器旁边就是其他标签页,对一个容易分心的孩子来说,诱惑太大了;
- 语音朗读、语音输入这些功能,浏览器端的兼容性和稳定性都不如桌面原生调用系统能力来得直接;
- 家里电脑不一定随时联网,纯本地能跑的桌面软件更省心。
所以最后落地是Python + PyQt5的桌面应用,用tkinter先做了一版极简原型验证交互流程(毕竟标准库自带,改起来最快),流程跑通之后整个重写成PyQt5,为的是后续能打包成一个双击就能跑的exe文件,样式和图标也能做得更精致。
这个选择本身没有唯一正确答案,纯粹是"这个场景下哪个更合适"的取舍,说出来也是想给同样在犹豫技术路线的人一个参考维度:先问清楚使用场景对"专注"和"离线"的要求有多高,再决定要不要上网页方案。
四、硬核Debug记录:一个"看起来正常"的Bug
这是我觉得最值得写下来的部分,因为它不是那种一眼能看出来的崩溃,而是一种更隐蔽、也更常见的问题——界面卡死。
事情是这样的:软件后来接入了大模型做AI判题(允许孩子写计算过程,不用死板地要求答案字符串完全一致)。功能加上之后,自己随手点了几次,感觉"好像挺正常"。
但"感觉正常"这四个字,在软件工程里几乎不能算数。
我做了一个实测:搭一个人为延迟4秒响应的模拟接口,然后用一个每100毫秒跳一次的计时器,包在"点击提交答案"这个操作的前后。逻辑很简单——如果界面没被卡住,这4秒里计时器应该跳大约40次;如果界面被卡住了,计时器会一次都跳不动,因为整个事件循环都被占用了。
结果是:4秒内,计时器跳动次数是0。
这就是实锤了——AI判题这个操作,是直接写在按钮点击的回调函数里同步执行的,网络请求一发出去,整个界面就会失去响应,用户在Windows上会看到经典的"未响应"提示。这不是理论推演,是真实测出来的数字。
排查清楚之后,解决方式也不复杂:把这类耗时操作(AI判题、AI批量出题、语音识别)统一丢进QThread子线程,用信号槽机制把结果传回主线程,界面本身永远不会被阻塞。修完之后用同一套实测方法再验证一遍:点击操作本身立刻返回(耗时不到0.01秒),后台等待4秒的这段时间里,计时器正常跳动了40次左右。
分享这个不是为了显得"过五关斩六将",而是想说一个我越来越确信的道理:"看起来能用"和"经得起实测"是两回事,尤其是涉及网络请求、文件IO、多线程这些操作时,靠肉眼点几下是发现不了问题的,得真的想办法把"卡没卡住"这件事量化出来。
顺带提一句,开发过程中还踩过几个更小的Qt坑,比如自定义控件不加WA_StyledBackground属性,样式表背景色不会生效;Windows原生视觉主题下,按钮的"transparent"背景在没被鼠标悬停时其实不生效,只有真正切到跨平台的Fusion样式引擎才能保证样式表在任何系统下表现一致。这些都是些具体、可复现、有明确解法的小问题,不是什么惊天动地的系统崩溃,但一个个啃下来,软件才能真正稳定地跑在别人的电脑上,而不只是"在我这儿好使"。
五、写在最后
现在这个软件已经能让孩子自己打开、闯关、被"粗心怪"教训、然后隔几天回去"复仇"。看着一个原本讨厌刷题的孩子,愿意主动打开软件去"打怪兽",会觉得之前排查Bug到深夜是值得的。
技术本身没有温度,但技术解决的问题可以有温度。如果你也是程序员家长,与其纠结"要不要给孩子报班",不如想想手里的技术能不能直接为她做点什么——哪怕只是一个跑在自己电脑上、只有一个用户的小软件。