1. 项目概述:当编程教育遇上“视觉化”评估难题
在编程教育的世界里,Scratch 已经成为了全球超过一亿学习者的启蒙工具。它用色彩斑斓的积木块取代了晦涩的代码,让孩子们通过拖拽就能创造出会动的故事、能玩的游戏。然而,当老师们面对一个班级几十份、甚至上百份充满奇思妙想的 Scratch 作品时,一个巨大的挑战也随之而来:如何高效、公平地评估这些作品?传统的“看代码、跑程序、给分数”模式,在 Scratch 这种高度视觉化、事件驱动且实现路径千变万化的编程环境中,显得力不从心。想象一下,一个要求学生“画一个五角星”的作业,有的学生用循环画,有的用多个画笔指令拼接,有的画得快,有的画得慢,但最终屏幕上都呈现了一个标准的五角星。传统的自动化测试工具很可能因为代码逻辑与预设的“参考答案”不完全一致,而错误地判定后者为“错误”。这正是当前 Scratch 自动化评估的困境:我们过于依赖对内部程序状态的精确断言,却忽略了编程教育,尤其是入门教育,其核心成果往往是那个最终呈现在舞台上的、动态的、可交互的视觉行为。
Raven 框架的提出,正是为了彻底扭转这一评估范式。它不再执着于追问“你的代码是不是按我预设的每一步执行的?”,而是转向一个更本质、也更符合教学实际的问题:“你的程序最终运行起来,是否达到了任务要求的效果?” 为了实现这一目标,Raven 做了一次大胆的“跨界”融合:它将大语言模型(LLM)的语义理解能力与视频分析技术相结合,构建了一个基于视频的自动化评估框架。简单来说,Raven 会让学生的 Scratch 程序“跑起来”,录下运行视频,然后像一位经验丰富的老师观看学生演示一样,去分析视频中的动画效果是否满足了评分标准。这种方法的核心优势在于,它将评估的抽象层级从“代码实现”提升到了“任务行为”,从而能够包容学生多样的创意和实现策略,只要最终视觉效果达标,即可获得认可。对于一线教育工作者、课程开发者乃至在线编程学习平台而言,Raven 提供了一种全新的可能性:一种既能保证评估一致性、减轻教师负担,又能尊重学生创造性、适配 Scratch 开放特性的自动化评估方案。
2. 核心设计思路:从“状态断言”到“行为验证”的范式迁移
要理解 Raven 的创新之处,我们首先需要剖析传统 Scratch 自动化评估工具的局限性。以目前最先进的框架 Whisker 为例,它的工作模式非常接近于我们熟悉的单元测试:教师或评估系统需要为每个作业预先编写一系列测试用例。每个测试用例包含三个部分:初始化程序状态(如设置精灵位置、变量初值)、定义交互序列(如模拟按下空格键、点击鼠标)、以及设置状态断言(如断言精灵的 x 坐标在事件后等于 100)。程序运行时,Whisker 会像一个自动化机器人,严格按脚本操作,并检查每一步后的程序状态是否与断言完全一致。
这套方法在测试传统软件时非常有效,但在 Scratch 的语境下却暴露了四大硬伤,我将其总结为“开放性”、“视觉性”、“交互性”和“灵活性”挑战。
2.1 传统断言式评估的四大困境
2.1.1 开放性任务覆盖不足Scratch 作业的本质是开放的。同一个“小猫来回走”的任务,学生 A 可能让小猫每次移动10步,学生 B 觉得5步更优雅。从教学目标和最终视觉效果看,两者都正确。但 Whisker 的断言是基于某个参考实现(比如移动10步)的精确状态生成的。当学生 B 的程序运行时,小猫的坐标变化与断言不符,就会被判为错误。这种“错杀”严重打击了学生的创造积极性,也违背了 Scratch 鼓励探索的初衷。
2.1.2 视觉化正确性无法评估许多 Scratch 作业的核心要求是视觉呈现,而非内部状态。例如,“创作一个海底世界,不能出现陆地或空中生物”。这个要求根本无法用“精灵类型==‘鱼’”这样的断言来完全描述,因为学生可能使用了自定义绘制的精灵,其“类别”信息并未编码在变量中。再比如“烟花爆炸效果”,评判标准是肉眼看到的色彩、形状和动画流畅度。传统工具对此束手无策,因为它们“看不见”舞台。
2.1.3 对人机交互的支持孱弱Scratch 的询问积木是实现复杂交互的关键。例如在一个“数学豌豆射手”游戏中,程序会提问“3+5=?”,玩家输入答案后,豌豆射手才会发射。Whisker 这类工具在模拟输入时,通常采用随机或简单启发式策略,很难“智能”地给出正确答案以触发后续分支逻辑。这就导致自动化测试无法完整覆盖程序的交互路径,评估自然不准确。
2.1.4 面对灵活配置时异常脆弱在实际课堂中,老师通常会鼓励学生个性化他们的作品。这意味着精灵的名字(“Cat” vs “Kitty”)、造型(默认小猫 vs 恐龙皮肤)、甚至数量都可以不同。Whisker 的测试脚本往往硬编码了参考程序中的精灵标识符。当学生作品中的精灵名称为“Dino”时,测试脚本找不到名为“Cat”的精灵,整个测试就会失败,尽管程序功能完全正确。
2.2 Raven 的破局之道:任务级视频生成与多模态分析
Raven 的设计哲学是“结果导向”和“视觉优先”。它不再试图深入程序内部去验证每一个中间状态,而是退后一步,观察程序的最终输出——也就是运行视频。其核心架构是一个双轨评估管道,结合了逻辑静态分析和动态视频分析。
2.2.1 任务配置的抽象化教师在使用 Raven 时,需要定义的不再是针对特定代码的测试用例,而是三组“规则”:
- 任务描述:用自然语言描述作业要求(如“创建一个游戏,玩家用键盘控制小狗接住天上掉落的苹果”)。
- 逻辑评分规则:描述代码层面需要实现的功能(如“小狗精灵应能通过左右方向键控制移动”)。这部分由逻辑检查器(Logic Checker)基于LLM分析代码结构来评估。
- 视频评分规则:描述在运行视频中需要观察到的行为(如“苹果碰到小狗后会消失,并且分数增加”)。这是评估的核心。
- 视频生成规则:定义为了“触发”出这些可视行为,自动化系统需要执行哪些交互序列(如“按下空格键开始,等待2秒,然后按三次右箭头键”)。这相当于导演脚本,告诉系统如何“操作”这个程序。
这种设计将“评估标准”(评分规则)与“评估方法”(视频生成规则)解耦。评分规则是任务层面的、通用的;视频生成规则是操作层面的、相对固定的。无论学生如何实现,只要用同一套“导演脚本”操作后,产生的视频能满足同一套“观影标准”,就可以得分。
2.2.2 双轨评估流程当一个学生项目提交后,Raven 会启动如下流程:
- 预处理:解析 Scratch 的 .sb3 项目文件,提取出JSON结构的代码、精灵列表、初始状态等信息,为后续分析提供结构化数据。
- 逻辑评估轨道:将预处理后的项目信息、任务描述和逻辑评分规则,输入给一个大型语言模型(论文中使用的是 Qwen2.5-Max)。LLM 扮演一位代码评审专家,分析项目代码是否包含了所需的功能块和逻辑结构。例如,它会检查是否有“当按下右移键”的事件处理器,以及其中是否包含改变x坐标的移动积木。
- 视频评估轨道(核心):这是 Raven 的创新心脏。系统首先根据“视频生成规则”,像一个自动化测试员一样运行学生的 Scratch 程序,并录制下完整的执行视频。这里特别关键的一步是处理
询问块:Raven 集成了一个轻量级视觉模型(如 Qwen-VL),在程序弹出输入框时,实时“看懂”屏幕上的问题(例如“3+5=?”),并生成正确答案(“8”)进行输入,从而能顺利触发后续交互逻辑。接着,系统从视频中按一定帧率(如10fps)采样关键帧,连同视频评分规则和项目预处理信息,一并提交给一个多模态视频分析模型(如 Qwen2.5-VL)。这个模型就像一位严格的“观影评委”,逐条检查视频内容是否满足每一条评分规则。为了减少大模型可能产生的“幻觉”或误判,Raven 会对同一段视频进行多次分析,只有某条规则在多次分析中都被判定为满足,才给予满分。 - 结果校验与合并:最后,系统会对比逻辑评估和视频评估的结果。如果两者出现冲突(例如逻辑分析说“有移动代码”,但视频分析显示“精灵没动”),Raven 会优先采信视频评估的结果,因为视频直接反映了程序运行时的真实行为。最终,合并两项得分,生成完整的评估报告。
这个流程的精妙之处在于,它用“视频”这一天然媒介,统一了对所有开放性、视觉化、交互性需求的评估。无论代码怎么写,最终都要在屏幕上“见真章”。
3. 实操要点:如何为你的 Scratch 课堂部署 Raven 式评估
理解了 Raven 的原理,我们来看看如何将其思想应用到实际教学或课程开发中。虽然直接部署原版 Raven 涉及复杂的模型调用和系统集成,但其核心工作流完全可以被借鉴和简化。下面,我将以一个具体的 Scratch 作业——“接苹果游戏”为例,拆解实现自动化评估的关键步骤。
3.1 定义清晰、可观测的评分规则
这是整个评估体系成败的基石。规则必须从“教师主观判断”转化为“机器可验证”的描述。
传统模糊规则(需避免):
- “游戏有趣,动画流畅。”(主观,不可测量)
- “小狗能接到苹果。”(不够精确,接到后发生什么?)
Raven 式视频评分规则(推荐):
- 初始化规则:游戏开始时,小狗精灵位于舞台底部中央,苹果精灵位于舞台顶部随机水平位置,分数变量显示为0。
- 交互响应规则:当按下键盘左箭头键时,小狗精灵应向左连续移动;当按下右箭头键时,应向右连续移动。
- 核心功能规则:当苹果精灵在掉落过程中,其造型边界与小狗精灵的造型边界发生重叠(视觉上的“碰撞”)时,苹果精灵应消失,同时分数变量显示的值应增加1。
- 游戏循环规则:在一个苹果被接住或掉落到底部消失后,应在短时间内(如1-2秒)在舞台顶部随机位置生成一个新的苹果精灵并开始掉落。
逻辑评分规则(辅助):
- 项目中应包含用于控制小狗移动的“当按下左移键”和“当按下右移键”事件处理器。
- 项目中应使用“如果…那么”条件判断积木,并与“碰到颜色”或“碰到角色”积木结合,来检测苹果与小狗的碰撞。
- 项目中应使用“变量”积木来记录和显示分数。
注意:视频规则是黄金标准,它描述的是最终效果。逻辑规则是辅助检查,确保学生使用了必要的编程概念。当两者冲突时,以视频为准。例如,学生可能用了一个非常巧妙的、不使用标准“碰撞”检测积木的方法来实现接住效果,只要视频中表现正确,就应得分。
3.2 设计稳健的视频生成规则(交互脚本)
视频生成规则就是自动化测试的“操作手册”。它需要足够健壮,能在学生程序的各种变体上触发关键行为。
针对“接苹果游戏”的示例规则:
[ {"action": "key_press", "key": "space", "duration_ms": 500}, // 按空格开始游戏 {"action": "wait", "duration_ms": 1000}, // 等待1秒,让苹果开始下落 {"action": "key_down", "key": "right"}, // 持续按下右箭头键2秒 {"action": "wait", "duration_ms": 2000}, {"action": "key_up", "key": "right"}, {"action": "key_down", "key": "left"}, // 持续按下左箭头键1.5秒 {"action": "wait", "duration_ms": 1500}, {"action": "key_up", "key": "left"}, {"action": "wait", "duration_ms": 3000} // 等待3秒,观察碰撞和得分 ]设计心得:
- 包含关键路径:脚本应覆盖评分规则中提到的所有关键交互(如左右移动)。
- 预留观察时间:在关键操作(如移动)后,要留出足够的等待时间,让程序效果完全呈现,便于视频分析。
- 处理随机性:对于初始位置随机的情况,单一脚本可能漏检。可以考虑生成2-3套略有不同的脚本(例如,配合苹果不同的掉落位置进行移动),分别录制视频进行评估,取最差结果或综合判断,以提高评估的鲁棒性。
3.3 实现简化的视频分析与判分逻辑
完全依赖多模态大模型(VLMs)对于许多教育者来说成本过高。我们可以设计一种轻量化的、基于计算机视觉(CV)和规则引擎的替代方案。
核心思路:将视频评分规则转化为一系列可编程的视觉检测任务。
目标检测与跟踪:使用开源的CV库(如OpenCV配合YOLO或基于颜色/形状的模板匹配),在视频帧中定位关键精灵(如“小狗”、“苹果”)。
- 实操技巧:在预处理阶段,可以让学生在上传项目时,同时提交关键精灵的截图作为“模板”。或者,系统在首次运行程序时,自动截取舞台上的精灵作为后续跟踪的参照物。
属性状态分析:
- 位置与移动:通过跟踪精灵的边界框中心坐标,可以判断其是否响应了按键事件(按下右键后,x坐标持续增加)。可以设定一个阈值,如“在按键事件后的N帧内,x坐标变化量超过M像素”,即判定为移动有效。
- 可见性:检测苹果精灵在某一帧后是否从画面中消失(边界框无法再匹配)。这对应“被接住后消失”的规则。
- 文本识别(OCR):使用Tesseract等OCR引擎,识别舞台上分数变量显示区域的数字变化。当苹果消失的帧附近,识别到的数字增加,则判定得分有效。
规则引擎判断:将上述检测到的时序数据(位置序列、可见性序列、分数序列)输入一个规则引擎。
# 伪代码示例:判断“接住苹果得分”规则 def check_catch_score(video_data): apple_visible = video_data['apple_visibility'] # 列表,True/False表示每帧是否存在 score_values = video_data['score_values'] # 列表,每帧识别到的分数 dog_bbox = video_data['dog_bbox'] # 列表,每帧小狗的边界框 apple_bbox = video_data['apple_bbox'] # 列表,每帧苹果的边界框 for i in range(1, len(apple_visible)): # 如果当前帧苹果消失,且上一帧苹果存在 if not apple_visible[i] and apple_visible[i-1]: # 检查消失前一刻,苹果与小狗是否碰撞(边界框重叠) if bbox_overlap(apple_bbox[i-1], dog_bbox[i-1]): # 检查当前帧或后续帧分数是否比碰撞前增加 if any(score_values[j] > score_values[i-1] for j in range(i, min(i+10, len(score_values)))): return True # 规则满足 return False # 规则不满足
这种方案虽然不如大模型通用和智能,但对于规则明确、视觉元素相对固定的作业,其准确率可以非常高,且计算成本可控,更适合集成到在线学习平台中。
4. 核心环节实现:构建一个轻量级视频评估原型
为了让大家更具体地感受 Raven 理念的实现,我将勾勒一个使用 Python 主流库构建的简化版“视频评估模块”的工作流程。这个原型专注于“视频生成”和“基于CV的规则验证”这两个核心环节。
4.1 环境准备与依赖安装
首先,我们需要一个能无头运行(Headless)并控制 Scratch 程序、录制屏幕的工具链。这里我们选用 Selenium 控制浏览器运行 Scratch 在线编辑器或本地项目,并用 OpenCV 进行视频处理和图像分析。
# 创建虚拟环境(可选但推荐) python -m venv raven_env source raven_env/bin/activate # Linux/Mac # raven_env\Scripts\activate # Windows # 安装核心依赖 pip install selenium opencv-python pillow numpy # 安装WebDriver,例如ChromeDriver,需确保与本地Chrome版本匹配 # 可以从 https://chromedriver.chromium.org/ 下载,或使用webdriver-manager自动管理 pip install webdriver-manager4.2 视频生成模块实现
这个模块负责加载 Scratch 项目,并按照预定义的“视频生成规则”自动化操作和录制。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import cv2 import numpy as np import time from PIL import ImageGrab import json class ScratchVideoRecorder: def __init__(self, scratch_project_url): """初始化,打开Scratch项目页面。""" from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager service = Service(ChromeDriverManager().install()) options = webdriver.ChromeOptions() options.add_argument('--start-maximized') # 最大化窗口确保舞台可见 self.driver = webdriver.Chrome(service=service, options=options) self.driver.get(scratch_project_url) time.sleep(5) # 等待项目完全加载 self.stage_element = self.driver.find_element(By.CSS_SELECTOR, '[class*="stage-wrapper"]') # 定位舞台区域 self.video_writer = None self.recording = False def start_recording(self, output_path='output.avi', fps=10): """开始录制屏幕指定区域(舞台)。""" stage_loc = self.stage_element.location stage_size = self.stage_element.size self.recording_area = (stage_loc['x'], stage_loc['y'], stage_loc['x'] + stage_size['width'], stage_loc['y'] + stage_size['height']) fourcc = cv2.VideoWriter_fourcc(*'XVID') self.video_writer = cv2.VideoWriter(output_path, fourcc, fps, (stage_size['width'], stage_size['height'])) self.recording = True print(f"开始录制视频至 {output_path}") def stop_recording(self): """停止录制并释放资源。""" if self.video_writer: self.recording = False self.video_writer.release() print("录制已停止。") self.driver.quit() def capture_frame(self): """捕获当前帧并写入视频。""" if not self.recording: return # 截取全屏 screenshot = ImageGrab.grab() # 裁剪出舞台区域 frame = screenshot.crop(self.recording_area) frame_cv = cv2.cvtColor(np.array(frame), cv2.COLOR_RGB2BGR) self.video_writer.write(frame_cv) def execute_interaction_sequence(self, sequence): """执行交互序列,并在过程中持续录屏。""" self.start_recording() actions = ActionChains(self.driver) for step in sequence: action_type = step.get('action') if action_type == 'key_press': key = step.get('key') duration = step.get('duration_ms', 500) / 1000.0 actions.key_down(key).pause(duration).key_up(key).perform() elif action_type == 'key_down': key = step.get('key') actions.key_down(key).perform() elif action_type == 'key_up': key = step.get('key') actions.key_up(key).perform() elif action_type == 'wait': duration = step.get('duration_ms', 1000) / 1000.0 time.sleep(duration) # 这里可以添加 mouse_click, mouse_move 等更多操作 # 每次操作后捕获一帧,模拟实时录制 self.capture_frame() time.sleep(0.05) # 短暂间隔,避免操作过快 self.stop_recording() # 使用示例 if __name__ == "__main__": # 假设有一个在线的Scratch项目URL,或者本地通过服务器托管的HTML文件 project_url = "https://scratch.mit.edu/projects/123456789/" recorder = ScratchVideoRecorder(project_url) # 定义交互序列(视频生成规则) interaction_script = [ {"action": "key_press", "key": Keys.SPACE, "duration_ms": 500}, # 按空格开始 {"action": "wait", "duration_ms": 1000}, {"action": "key_down", "key": Keys.RIGHT}, {"action": "wait", "duration_ms": 2000}, {"action": "key_up", "key": Keys.RIGHT}, {"action": "wait", "duration_ms": 3000} ] recorder.execute_interaction_sequence(interaction_script)实操心得:在实际部署中,直接操作在线版 Scratch 可能受网络和网站更新影响。更稳定的方案是使用 Scratch 的本地运行环境(如
scratch-vm)或通过其无头渲染库来运行 .sb3 文件,这样可以获得更稳定、纯净的视频输出,也便于批量处理。
4.3 视频分析模块实现(基于OpenCV的简化版)
录制好视频后,我们需要分析它是否满足“视频评分规则”。这里以实现“检测苹果是否被接住并得分”为例。
import cv2 import numpy as np class VideoAnalyzer: def __init__(self, video_path, dog_template_path, apple_template_path): self.video_path = video_path self.dog_template = cv2.imread(dog_template_path, cv2.IMREAD_GRAYSCALE) self.apple_template = cv2.imread(apple_template_path, cv2.IMREAD_GRAYSCALE) self.score_region = (100, 50, 200, 100) # 假设分数显示区域的坐标 (x1, y1, x2, y2) self.ocr_engine = None # 可在此处初始化Pytesseract def analyze_catch_rule(self): """分析视频,判断‘接住苹果得分’规则是否满足。""" cap = cv2.VideoCapture(self.video_path) prev_score = None apple_was_visible = False rule_satisfied = False while cap.isOpened(): ret, frame = cap.read() if not ret: break gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 1. 检测苹果是否存在(使用模板匹配) apple_result = cv2.matchTemplate(gray_frame, self.apple_template, cv2.TM_CCOEFF_NORMED) _, apple_max_val, _, apple_max_loc = cv2.minMaxLoc(apple_result) apple_present = apple_max_val > 0.8 # 设定匹配阈值 # 2. 检测小狗位置(用于后续碰撞检测,此处简化) dog_result = cv2.matchTemplate(gray_frame, self.dog_template, cv2.TM_CCOEFF_NORMED) _, dog_max_val, _, dog_max_loc = cv2.minMaxLoc(dog_result) # 3. 识别分数区域(简化:假设分数区域是纯色背景上的数字,使用OCR或颜色阈值) score_roi = frame[self.score_region[1]:self.score_region[3], self.score_region[0]:self.score_region[2]] # 此处应接入OCR识别具体数字,例如使用 pytesseract # current_score = self.extract_score_from_roi(score_roi) # 为简化演示,我们假设通过检测分数区域的颜色突变来模拟“得分” mean_intensity = np.mean(score_roi) # 假设得分时该区域会闪烁白色(强度变高) score_increased = (prev_score is not None and mean_intensity > prev_score + 30) prev_score = mean_intensity # 4. 规则逻辑判断 # 如果上一帧有苹果,当前帧苹果消失,且分数增加,则判定规则满足一次 if apple_was_visible and not apple_present and score_increased: # (可选)进一步检查苹果消失前是否与小狗位置接近(简单碰撞检测) # 这里需要记录上一帧苹果和小狗的位置进行计算,代码略 print(f"在帧 {int(cap.get(cv2.CAP_PROP_POS_FRAMES))} 检测到可能接住并得分。") rule_satisfied = True # 可以break,也可以继续检查整个视频中是否多次满足 apple_was_visible = apple_present cap.release() return rule_satisfied # 使用示例 if __name__ == "__main__": analyzer = VideoAnalyzer('output.avi', 'dog_template.png', 'apple_template.png') if analyzer.analyze_catch_rule(): print("评估结果:'接住苹果得分'规则满足。") else: print("评估结果:'接住苹果得分'规则不满足。")实现要点与局限:
- 模板匹配的局限:上述代码使用简单的模板匹配来定位精灵,这在精灵造型固定时有效。如果学生自定义了造型,则需要更鲁棒的特征匹配方法(如 SIFT、ORB)或目标检测模型。
- OCR集成:要准确识别分数,需要集成 Tesseract OCR。需要先对分数显示区域进行预处理(二值化、去噪),并训练或配置 Tesseract 识别数字字体。
- 碰撞检测:真实的碰撞检测需要计算精灵轮廓或边界框的重叠。Scratch 内部使用轴对齐包围盒(AABB)或像素级碰撞。在视频分析中,我们可以用模板匹配得到的矩形框进行简单的矩形重叠检测,但这只是近似。
- 性能:逐帧进行模板匹配和OCR在长视频中可能较慢。可以通过降低分析帧率、只在关键时间段分析或使用更高效的检测器来优化。
尽管这个原型简化了许多,但它清晰地展示了 Raven 核心思想的技术实现路径:自动化交互 -> 录制行为 -> 视觉分析 -> 规则判定。
5. 常见问题与优化策略实录
在实际尝试应用 Raven 或类似视频评估方法时,你会遇到一系列预料之中和预料之外的挑战。下面是我根据经验总结的常见问题及其解决思路。
5.1 视频生成与交互模拟中的“坑”
问题1:交互时序的同步问题。自动化脚本按固定时序执行操作,但学生程序可能有随机延迟(如“等待1到3秒”积木)或基于复杂条件的触发。脚本执行完毕时,程序的关键动画可能还没开始或已经结束。
- 解决方案:采用“事件驱动”的等待策略,而非固定时长等待。在关键操作后,不是简单
sleep,而是持续检测屏幕状态。例如,在点击“开始”按钮后,持续检测舞台直到某个特定精灵出现或某个颜色区域变化,再执行下一步。这需要视频分析模块提供实时反馈。
问题2:处理“询问”块等模态交互。程序弹出输入框时,会阻塞执行流。Selenium 等工具无法直接“看到”和“理解”这个图形化输入框的内容。
- 解决方案(Raven 方案):集成轻量级视觉语言模型(VLM)。在录制视频的同一进程中,实时截屏并送入 VLM,提问:“屏幕中央对话框显示的文字是什么?” 获取答案后,再通过自动化工具将答案文本输入到活动输入框中。
- 简化方案:对于固定答案的作业,可以在视频生成规则中预定义答案。或者,在任务要求中引导学生使用非模态的交互方式(如通过按键选择答案)。
问题3:学生程序崩溃或无响应。自动化操作可能触发学生程序中的 bug,导致程序卡死或闪退,使得整个评估流程中断。
- 解决方案:在自动化控制器外层添加超时和异常处理机制。为每个交互步骤设置最大等待时间,超时后记录“无响应”并尝试恢复(如刷新页面重新开始),或直接判定该条评分规则不满足。评估系统应具备容错性,部分失败不应导致全局崩溃。
5.2 视频分析与规则判定中的挑战
问题4:视觉检测的稳定性。光照变化、背景复杂、精灵造型多变(尤其是学生手绘的造型)都会严重影响模板匹配等传统CV方法的准确性。
- 解决方案:
- 特征强化:鼓励或要求学生在关键精灵上使用高对比度、颜色鲜明的造型,或在评估前提交精灵截图作为“标准模板”。
- 采用更先进的检测器:使用基于深度学习的目标检测模型(如 YOLO),用少量标注数据(不同学生作品中的精灵)进行微调,可以极大提升检测鲁棒性。
- 多特征融合:不依赖单一检测方法。结合颜色直方图、形状轮廓、甚至精灵在代码中的名称(可从.sb3文件解析)进行综合判断。
问题5:判定规则的模糊边界。“精灵移动到指定区域”,这个“区域”多大算到达?“动画流畅”,多少帧率算流畅?这些都需要量化。
- 解决方案:在定义视频评分规则时,必须将其量化为可测量的指标。
- 位置规则:“小狗精灵的边界框中心点需进入舞台底部中央一个宽200像素、高50像素的矩形区域内,并停留超过1秒。”
- 动画规则:“烟花爆炸效果需在0.5秒内,由中心点扩散出至少5个不同颜色的粒子,且粒子运动轨迹连续无跳跃(相邻帧位移差小于10像素)。”
- 状态规则:“苹果精灵在视觉上消失后,在其原位置周围50像素区域内,持续10帧内不应再出现。”
问题6:评估性能与成本。运行程序、录制视频、再用大模型或复杂CV模型逐帧分析,耗时可能很长,无法满足课堂即时反馈的需求。
- 优化策略:
- 采样分析:无需分析每秒30帧的全视频。对于大多数行为,每秒采样2-5帧足以做出判断。
- 关键片段定位:根据视频生成规则,可以预知关键行为发生的大致时间窗口。只对这几个窗口期的视频片段进行详细分析。
- 离线评估与异步反馈:在学生提交作业后,系统在后台排队进行评估,稍后将结果反馈给学生和老师。对于练习,这通常是可接受的。
- 规则优先级:将评分规则分为“核心规则”和“附加规则”。优先评估核心规则,快速给出基础分数。附加规则可用于更精细的评分或提供改进建议。
5.3 教学整合与公平性考量
问题7:如何防止学生“欺骗”系统?例如,学生可能写一个程序,直接检测到评估脚本的特定操作序列(如“连续按右箭头2秒”),然后直接显示一个完美的动画,而绕过真正的游戏逻辑。
- 应对策略:引入随机性和多样性到视频生成规则中。不要只用一套固定的交互脚本。可以生成多套脚本,随机选择一套进行评估,或者要求程序必须通过多套脚本的测试。这增加了“欺骗”的成本,迫使学生实现真正通用的逻辑。
问题8:评估标准的一致性 vs. 鼓励创新。Raven 方法通过视频统一了评估标准,但会不会反过来扼杀那些“效果相同但实现方式极其新颖”的创意?比如,一个不用“移动”积木,而用“重复切换造型”来模拟移动的作品,可能无法被基于坐标移动的检测规则识别。
- 平衡之道:这正是“任务级”抽象的优势。评分规则应专注于描述最终的视觉和行为效果,而非实现方式。在“小狗移动”的例子中,规则应描述为“小狗精灵应能从屏幕左侧平滑移动到右侧”,而不是“小狗的x坐标应增加”。评估系统需要采用更高级的视觉跟踪技术(如光流法、特征点跟踪)来判断“平滑移动”是否发生,而不是死磕坐标值。同时,保留一部分分数给“代码创意”或“逻辑实现”,由逻辑评估轨道或教师手动复核来完成。
将 Raven 的理念融入教学实践,其意义远不止于自动打分。它促使教师更深入地思考:我们到底希望学生掌握什么?是背诵特定的代码模式,还是获得实现特定效果的能力?它也将学生的注意力从“我的代码和答案一样吗”转移到“我的程序运行起来能达到要求吗”,这更接近真实世界软件开发的思维模式。当然,没有任何自动化工具能完全替代教师的专业判断和富有同理心的反馈。Raven 的价值在于,它接管了那些重复、机械的检查工作,让教师得以腾出精力,去关注那些更本质的东西——学生的设计思维、问题解决策略和创造过程中的闪光点。