我给AI素养课做了个自测平台:整个思考过程,和一套可以直接抄的题库解析代码
智课工坊生成了20道题的题库md文件,但只有文件没有交互——学生没法自测,老师没法批改。花一下午做了个单文件HTML自测平台,从题库解析到错题循环,把思考过程摊开写,附上可以直接抄的解析引擎代码。
1. 起点
智课工坊跑了一门入门AI素养课,第五步「题库考核」产出了一个20题的md文件。格式长这样:
## 1. 【单选】在第1课中,用AI做出第一个成品时,最适合的做法是?
- A. 先学习编程基础再动手
- [√] B. 直接使用AI对话工具生成内容并保存
- C. 只观看演示不自己操作
- D. 等待老师提供成品模板
**答案**:B | **难度**:easy | **对应课时**:第1课
**解析**:课程强调零代码、有产出...
单选用「【单选】」标注,多选用「【多选】」标注,正确选项前面有个 [√] 标记(智课工坊实际用√符号标记正确选项)。答案、难度、对应课时、解析都在 **答案** 和 **解析** 行里。
题目有了,但怎么用?老师拿去打印纸质卷子?太浪费了——这些题目有难度标签、有课时归属、有详细解析,应该做成一个学生打开浏览器就能用的东西。
2. 第一次推翻:不要Python脚本,要零部署的网页
我最初想的是写个Python脚本:学生跑脚本答题,终端里输出分数。
跑了一版发现不对——目标用户是大学新生,大部分人的电脑上连Python都没装。让他们装Python再跑命令行,门槛太高了。而且终端里没法做选项点选、进度条、错题回顾这些交互。
推倒重来。调研了一圈,决定做单文件HTML:一个.html文件,双击就能打开,不依赖任何后端、不装任何东西。所有题目直接嵌在文件里(也可以拖放导入外部题库md),用纯前端JavaScript搞定全部逻辑。
这个选择有一个关键好处:部署就是复制文件。放到静态服务器上、塞进课程包里、微信发个文件——学生拿到就能用。零运维成本。
3. 第二次推翻:不要一页一题,要三阶段模式
第二版我做成了一页一题的翻页模式:看完一题点下一题,最后统一提交。
做了几题发现体验很差:学生在第8题想回看第3题的题干,要往回翻6页。而且不知道总共多少题、自己答了多少。
推翻重来。改成三阶段模式:
- 阶段一:选题。列出所有题目,可以按课时筛选(只看第3课的题)、按难度筛选(只做中等题)。一目了然。
- 阶段二:答题。还是逐题,但顶部有进度条(第3/20题),底部有上一题/下一题导航,也可以直接点进度条跳题。当前做的题数据在内存里,来回切换不丢失。
- 阶段三:看结果。提交后显示总分(答对X题/共Y题)、每道题的正确答案和解析。答错的题标红,答对的标绿。最关键的——有个「错题再考」按钮,只拿答错的题再来一轮。
三个阶段用 display:none/block 切换,不用路由、不用多页面,一个HTML搞定。
4. 题库解析引擎(可以直接抄)
整个平台的核心是这个解析函数——把智课工坊的md题库格式转成结构化数据。格式前面展示过了,正则匹配就行:
function parseQuestions(raw) {
const questions = [];
const blocks = raw.split(/\n---+\n/);
for (const block of blocks) {
const hMatch = block.match(/^##\s*\d+\.\s*【(单选|多选)】\s*(.+)/m);
if (!hMatch) continue;
const qType = hMatch[1] === '单选' ? 'single' : 'multi';
const title = hMatch[2].trim();
const opts = [];
// 匹配选项行,正确选项前有勾选标记
const optRe = /^-\s+(\[√\]\s*)?([A-F])\.\s*(.+)/gm;
let m;
while ((m = optRe.exec(block)) !== null) {
opts.push({ label: m[2], text: m[3].trim(), correct: !!m[1] });
}
if (opts.length === 0) continue;
const ansMatch = block.match(/\*\*答案\*\*:\s*(.+?)\s*[||]\s*/);
const diffMatch = block.match(/\*\*难度\*\*:\s*(\w+)/);
const lessonMatch = block.match(/\*\*对应课时\*\*:\s*(.+)/);
const explainMatch = block.match(/\*\*解析\*\*:\s*([\s\S]+?)(?=\n*(?:---|$))/);
questions.push({
id: questions.length + 1,
title, type: qType, options: opts,
answer: ansMatch ? ansMatch[1].trim() : '',
difficulty: diffMatch ? diffMatch[1] : 'medium',
lesson: lessonMatch ? lessonMatch[1].trim() : '',
explanation: explainMatch ? explainMatch[1].trim() : ''
});
}
return questions;
}
这段代码处理了几个边界情况:
- 题块分隔:智课工坊的题库用
---分隔每道题。直接用split(/\n---+\n/)切开。 - 题型识别:从
【单选】或【多选】读类型,决定后续用radio还是checkbox。 - 正确选项定位:不是通过「答案」行反查——直接解析选项行里的勾选标记。这样即使「答案」行写错了,正确选项也丢不了。
- 多选处理:
filter(o => o.correct)收集所有打勾的选项,多选答案可能是 A、B、D。
提交判断时,把用户选的选项 label 排序后拼成字符串,跟正确答案字符串比——单选用 ['B'] 拼成 'B',多选用 ['A','B','C'] 拼成 'ABC',一个比较搞定。
5. 两个关键设计决策
拖放导入题库:FileReader API读文件内容 → 喂给上面的parseQuestions → 替换当前题库。学生拿到新题库md后拖进页面就能用,不需要改HTML源码。这个功能让平台从「预置20题的demo」变成了「通用自测工具」。
错题再考循环:提交后如果答错X题,点「错题再考」就把 filteredQuestions 替换成答错的题集,重置作答状态,回到答题阶段。再考完还能再考——直到全对为止。这个循环让学生不是「做完看一眼分数就关」,而是「反复擦直到会」——符合学习规律。
6. 总结
三个判断:
- 单文件HTML是被低估的交付形态。不需要npm install、不需要docker、不需要服务器。一个.html文件,双击即用,拷到哪儿都能跑——对学生场景来说是零摩擦。
- 题库格式设计决定了解析成本。智课工坊的md格式用勾选标记标注正确选项、
---分隔题块——这些约定让解析器不到60行就搞定了。如果格式是「答案单独放文件末尾」,解析要复杂很多。 - 错题循环是小功能但大价值。自测的核心不是打分,是让学生把不会的题反复做到会。这个循环把「一次性考试」变成了「学习工具」。
平台代码已经放在AI素养课课程包里,预置了入门版20题。题库文件拖进去就能用。
- 点赞
- 收藏
- 关注作者
评论(0)