# -*- coding: utf-8 -*- """Part B: chapters 3, 4, 5.""" from docx.shared import Pt, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH from docx_helpers import (make_table, para, rich, bullet, bullet_rich, heading, caption, note, quote, link_para) GH = "https://github.com/" def chapter3(doc): heading(doc, "第三章 三个研究点的开源现状", 1) para(doc, "本章按方案 B 的三个研究点分别展开。每一节的结构一致:先给出检索过程与命中情况,再评估既有系统的实际能力,然后列出可复用资产,最后给出空白判定。判定标准有两条:其一,检索范围内是否存在以该问题为核心特性的开源项目;其二,既有系统的实现是否停留在工程惯例层面而缺少方法层面的设计与度量。只有两条同时成立,才可称为「空白」。") # ---------------- 3.1 ---------------- heading(doc, "3.1 问题一:多约束组卷", 2) heading(doc, "3.1.1 开源现状", 3) para(doc, "自动组卷在开源生态中的存在形式有三种。第一种是考试系统内置的「随机抽题」功能,按题型、难度、分值等条件从题库过滤后随机选取,学之思与砚考都属此类;这种方式实现简单,但本质是筛选而非求解,约束一多就会出现候选不足或凑不齐总分,且系统只能提示「候选不足」,无法给出最优或次优方案。第二种是学术型自动组卷项目,多采用遗传算法或模拟退火,代码量小、技术栈老旧,代表性的是 cppcpp/exam-system(南京晓庄学院自动组卷系统,遗传算法生成试卷,SSM 技术栈,最后提交于 2022 年 12 月)。第三种是通用约束求解器,本身不是考试系统,但提供了完整的建模与求解能力。") para(doc, "值得注意的是,第三种才是工业界真正在用的路径。Google 的 or-tools 提供 CP-SAT 求解器,可把「知识点覆盖、难度分布、题型配比、总分、去重避重」直接表达为约束与目标;Timefold(原 OptaPlanner 团队)提供 Java/Kotlin 原生的启发式与局部搜索框架,其领域建模方式与排课、排班问题同源。二者都被大量生产系统使用,但对考试组卷这一具体场景没有现成模型,需要研究者自行完成变量定义、约束表达与目标函数设计。这恰恰说明:组卷的难点不在求解器本身,而在问题建模。") heading(doc, "3.1.2 可复用资产", 3) caption(doc, "表 3-1 组卷方向可复用仓库") make_table(doc, ["项目(点击进入仓库)", "语言", "星标 / 许可", "在本研究中的用途"], [[("cppcpp/exam-system", GH + "cppcpp/exam-system"), "Java(SSM)", "87 / 无", "遗传算法组卷的基线实现:编码方式、适应度函数、约束惩罚项可直接对照,用于验证本研究遗传求解器的合理性"], [("google/or-tools", GH + "google/or-tools"), "C++(Java 绑定)", "14348 / Apache-2.0", "CP-SAT 建模多约束组卷,作为「精确求解 vs 启发式」的对照方法;论文中可论证其建模成本与求解质量的权衡"], [("TimefoldAI/timefold-solver", GH + "TimefoldAI/timefold-solver"), "Java / Kotlin", "1859 / Apache-2.0", "局部搜索框架,与本研究「贪心 + 局部修补」求解器同源,可引用其评分函数与邻域算子设计"], [("mindskip/xzs-mysql", GH + "mindskip/xzs-mysql"), "Java", "3604 / AGPL-3.0", "paper_rule 表的字段设计可参考其组卷规则的持久化方式(仅借鉴结构)"]], [4.0, 2.4, 2.6, 6.4], link_col=0) note(doc, "注:or-tools 的 Java 绑定虽可用,但官方文档以 Python/C++ 为主,建模示例需要自行转写;若时间紧张,建议仅在论文中作为对照方法讨论,不作为主力实现。") heading(doc, "3.1.3 空白判定与立项依据", 3) para(doc, "按前述两条判定标准逐项检验。第一,检索范围内不存在以「多约束组卷求解」为核心特性的开源考试系统:所有被检视的系统都把组卷实现为一个带随机性的筛选函数,没有把约束集形式化为可配置模型,也没有提供求解器抽象。第二,既有实现停留在工程惯例层面:没有成功率度量,没有约束强度分级,没有退化曲线,也没有对难度分布偏差或知识点覆盖偏差的量化。两条同时成立,可以判定该方向存在方法层面的空白。") para(doc, "因此本研究把组卷表述为「题库、约束集、目标」三元组,约束集以可配置 JSON 落入 paper_rule 表,并实现随机回溯、贪心加局部修补、遗传算法三个求解器、统一接口、三档约束强度,测度成功率、单次耗时、难度分布偏差(KL 散度或卡方值)、知识点覆盖偏差与总分误差。这一设计的价值不在于「用了遗传算法」,而在于给出了约束强度与求解质量之间的定量关系,使「什么时候该用哪个求解器」成为一个可回答的问题。") heading(doc, "3.1.4 实验基线建议", 3) para(doc, "实验设计建议采用三级对照。基线级为「随机抽题加重试」,即既有系统的做法,用于说明朴素方法的失效边界;中间级为 cppcpp/exam-system 的遗传算法实现,用于说明同类学术工作的水平;对照级为 or-tools CP-SAT 的精确求解,用于给出质量上界(在小规模题库上可求得最优解,从而计算本研究启发式解的最优性差距)。这样组织,实验既能自证改进,又能说明与工业级方法的距离。") # ---------------- 3.2 ---------------- heading(doc, "3.2 问题二:断网续考的答案一致性", 2) heading(doc, "3.2.1 检索过程与结果", 3) para(doc, "本方向的检索最为彻底,也最令人意外。检索沿 topic 标签展开,逐一检视了三个标签下的仓库列表,并按关键词过滤离线、同步、续答、冲突等语义。检索记录如表 3-2。") caption(doc, "表 3-2 断网续考方向的检索记录") make_table(doc, ["检索式", "命中规模", "检视方式", "结果"], [["topic:online-exam", "119 个仓库", "全部检视仓库名与简介", "无任何以离线答题或断网续答为核心特性的项目"], ["topic:exam", "1744 个仓库", "按关键词过滤后检视", "含大量非考试业务仓库,过滤后无相关项目"], ["topic:proctoring", "155 个仓库", "全部检视仓库名与简介", "集中于人脸、视线、屏幕共享等监考能力,与续考无关"], ["offline first / local-first sync", "少量", "检视通用同步引擎", "存在成熟引擎(如 rxdb、pouchdb),但无考试场景应用"], ["commercial systems(功能对照)", "—", "查阅产品说明与帮助文档", "普遍宣传「逐题自动保存 + 断点续答」,未提及冲突裁决规则"]], [4.4, 2.6, 4.0, 5.4]) para(doc, "结论很明确:在本次检索覆盖的范围内,没有任何一个开源考试系统把「客户端与服务端答案的并发修改」作为需要解决的问题。既有系统的断点续答建立在一个隐含假设之上——网络恢复后以服务端数据为准,客户端本地内容只是尚未送达的暂存。这个假设在「断网期间考生继续作答、同时服务端因超时收卷或另一终端登录而产生写入」的情形下并不成立,而方案 B 的问题二正是针对这一情形。") heading(doc, "3.2.2 既有系统的实际能力", 3) para(doc, "把三个代表性系统的续考能力拆开看,可以更清楚地定位差距。") bullet_rich(doc, [("学之思(xzs-mysql):", True), ("答题过程逐题提交,服务端保存作答记录,考生中途退出后可恢复。其前提是每次作答都能即时联网送达,因此本质是「在线保存 + 断点恢复」,不含离线缓存。", False)]) bullet_rich(doc, [("砚考(exam-platform):", True), ("逐题自动保存、中途退出可断点续答、倒计时归零自动交卷(前端主动提交 + 后端定时兜底双保险)、重复交卷幂等。这是目前能力最完整的一组,但同样没有客户端离线缓存与版本合并。", False)]) bullet_rich(doc, [("Moodle(mod_quiz):", True), ("以 question_attempts 状态机记录每一次作答步骤,支持分步保存与草稿态恢复,是理论上最接近「可恢复」的模型。但它是服务端状态机,不涉及客户端离线副本的冲突合并。", False)]) para(doc, "三者的共同点是:把「断网」处理为传输层问题(重发、重试、恢复),而不是数据处理问题(多副本、版本、收敛)。这正是本研究可以切入的缝隙。") heading(doc, "3.2.3 可复用的同步与一致性组件", 3) para(doc, "虽然没有考试场景的实现可参照,但「本地优先 + 增量同步 + 冲突解决」在其他领域已有成熟工程方案。这些方案不直接可用,但其数据模型与协议设计可作为本研究的理论来源。") caption(doc, "表 3-3 断网续考方向可复用仓库") make_table(doc, ["项目(点击进入仓库)", "语言", "星标 / 许可", "可借鉴的机制"], [[("pubkey/rxdb", GH + "pubkey/rxdb"), "TypeScript", "23421 / Apache-2.0", "本地优先数据库的冲突解决策略族(主从、最后写入胜出、自定义合并),其策略枚举可直接映射到本研究「版本大者胜出 + 服务端仲裁」的设计"], [("pouchdb/pouchdb", GH + "pouchdb/pouchdb"), "JavaScript", "17627 / Apache-2.0", "CouchDB 复制协议:以修订号(rev)链表达版本,冲突时保留多个叶子节点供上层裁决,是「不丢写」的经典做法"], [("dexie/Dexie.js", GH + "dexie/Dexie.js"), "TypeScript", "14673 / Apache-2.0", "IndexedDB 的封装库,方案 B 已选定为客户端存储层;其事务与索引 API 适合按 (examId, questionId) 建草稿表"], [("lukas-krecan/ShedLock", GH + "lukas-krecan/ShedLock"), "Java", "4235 / Apache-2.0", "基于 Redis 的分布式定时任务锁,保证 30 秒快照任务在多实例下不重复执行"], [("testcontainers/testcontainers-java", GH + "testcontainers/testcontainers-java"), "Java", "8758 / MIT", "故障注入的工程基础:可在测试中真实重启 MySQL/Redis、断开连接,用于验证恢复语义"]], [4.0, 2.4, 2.6, 6.4], link_col=0) note(doc, "注:rxdb 与 pouchdb 的冲突模型建立在对等副本(peer-to-peer)假设上,而考试场景是「一个考生对应一个会话」的中心化结构,因此不能照搬;本研究的做法是保留其版本比较思想,但把裁决权收敛到服务端,从而避免复杂的多副本协商。") heading(doc, "3.2.4 空白判定与本研究定位", 3) para(doc, "两条判定标准中,第一条成立得很彻底:检索范围内无任何以该问题为核心的开源项目。第二条同样成立:既有实现没有任何显式的冲突裁决规则,也没有对丢答案、重复提交、恢复时长等指标的度量。因此可以判定为空白。") para(doc, "本研究据此提出的五项设计构成一套完整协议:客户端 IndexedDB 即时写入并维护 last_seq 游标;服务端以 (session_id, question_id, version) 唯一索引保证同一版本的重复写入只生效一次;重连后携带 last_seq 拉取差异并按版本号合并,版本大者胜出、服务端拒绝过期版本;服务端每 30 秒落一次会话快照,重启后按快照加增量日志恢复;交卷以 (session_id, submit_token) 幂等。五项设计分别对应「写不丢、写不重、能收敛、能恢复、交不重」,指标的选取(答案完整率、重复提交次数、断网恢复时长、草稿丢失条数、重启后会话语义正确率)也一一对应。") para(doc, "在论文写作上,这一节的价值不仅是「别人没做」,更在于可以论证「为什么别人没做」:考试系统的答题负载是低频小数据,多数实现者认为重试足够;只有把断网、重启、多端登录三种故障叠加,才会暴露一致性缺口。这一论证可以显著提升第 1 章问题陈述的说服力。") # ---------------- 3.3 ---------------- heading(doc, "3.3 问题三:作弊行为识别", 2) heading(doc, "3.3.1 两条技术路线", 3) para(doc, "开源监考项目的数量明显多于前两个方向,但路线高度集中,可归为两类。") para(doc, "第一类是视觉 AI 路线,以摄像头画面为输入,检测人脸数量、视线方向、是否出现手机、是否离开画面。这是开源生态的主流,代表项目见表 3-4。") caption(doc, "表 3-4 视觉 AI 路线代表项目") make_table(doc, ["项目(点击进入仓库)", "技术栈", "星标 / 许可", "检测能力"], [[("vardanagarwal/Proctoring-AI", GH + "vardanagarwal/Proctoring-AI"), "Python,OpenCV + dlib", "633 / MIT", "视线估计、人脸识别、手机检测、多人检测、离开检测,五类信号齐全,是本路线最经典的起点"], [("narender-rk10/MyProctor.ai", GH + "narender-rk10/MyProctor.ai-AI-BASED-SMART-ONLINE-EXAMINATION-PROCTORING-SYSYTEM"), "Flask + MySQL + YOLOv4", "236 / 无", "目标检测为核心的全栈示例,含考生端与监考端界面"], [("tusharnankani/Aankh", GH + "tusharnankani/Aankh"), "JavaScript", "86 / GPL-3.0", "浏览器端实时监考:标签页切换、离开屏幕、多人脸检测,代码短、易读"], [("meefik/ITMOproctor", GH + "meefik/ITMOproctor"), "WebRTC", "40 / GPL-3.0", "远程人工监考:多路视频 + 监考端坐席,已在 2023 年归档"], [("eLearning-BS23/moodle-quizaccess_proctoring", GH + "eLearning-BS23/moodle-quizaccess_proctoring"), "PHP(Moodle 插件)", "30 / 未声明 SPDX", "在 LMS 考试过程中嵌入浏览器侧检测,可参考其与宿主系统的集成边界"]], [4.0, 3.0, 2.6, 5.8], link_col=0) para(doc, "第二类是客户端锁机路线,不以检测为目标,而是直接限制考试期间的设备行为。代表是 Safe Exam Browser 生态:客户端把机器锁定为考试专用环境,服务端负责会话编排与实时监控。") caption(doc, "表 3-5 客户端锁机路线代表项目") make_table(doc, ["项目(点击进入仓库)", "语言", "星标 / 许可", "定位"], [[("SafeExamBrowser/seb-win-refactoring", GH + "SafeExamBrowser/seb-win-refactoring"), "C#", "366 / MPL-2.0", "Windows 客户端,锁机、禁用切换、限制外设"], [("SafeExamBrowser/seb-server", GH + "SafeExamBrowser/seb-server"), "Java", "97 / MPL-2.0", "服务端,管理考试会话与在线的 SEB 客户端,欧洲高校事实标准"], [("aesophor/hacklympics", GH + "aesophor/hacklympics"), "Java", "69 / MPL-2.0", "竞赛场景原型:键盘记录、进程检测,思路偏机器侧管控"]], [5.0, 2.4, 2.6, 5.4], link_col=0) heading(doc, "3.3.2 可借鉴的信号清单", 3) para(doc, "本研究不做深度模型,因此表 3-4 中的视觉能力不直接采用,但其中的信号划分极有参考价值。把开源项目实际检测的维度与方案 B 的五类信号对照,可以得到表 3-6。") caption(doc, "表 3-6 开源检测维度与本研究信号的对应关系") make_table(doc, ["开源项目检测的行为", "典型来源", "本研究对应信号", "采集方式"], [["标签页切换、窗口失焦", "Aankh、砚考(13 类行为)", "切屏与失焦次数、累计时长", "visibilitychange、blur/focus 事件"], ["多人脸、无人脸、离开画面", "Proctoring-AI、MyProctor.ai", "(不采用,改为)多端登录与会话并发", "会话表与登录日志"], ["手机出现、外设接入", "Proctoring-AI", "(不采用)", "—"], ["复制、剪切、粘贴、右键、开发者工具", "砚考", "答题节奏异常(修改频次、停留时间)", "前端事件埋点"], ["多标签页、退出全屏", "砚考", "切屏与失焦", "全屏状态监听"], ["IP 与设备聚集", "SEB Server 会话编排", "IP 与设备指纹聚集", "登录与心跳元数据"], ["答案雷同", "(开源中普遍缺失)", "相邻考生答案相似度", "交卷后批量比对"]], [3.6, 3.6, 4.6, 3.6]) note(doc, "注:表中「不采用」的两行并非否定其有效性,而是出于成本与合规考虑——摄像头方案需要终端设备、算力与隐私授权,与本研究「仅依赖浏览器事件与日志」的定位冲突。论文中应把这一取舍写成显式的方法边界,而非能力缺失。") heading(doc, "3.3.3 与本研究定位的差异", 3) para(doc, "本研究的做法是规则引擎输出连续风险分(加权求和加阈值分级),超阈值进入人工复核队列。与既有方案相比,差异有三点,每一点都可以写成论文中的设计理由。") bullet_rich(doc, [("从二值判定到连续度量。", True), ("砚考的 13 类行为采用计数加阈值的方式,达到上限即由服务端强制交卷。这种设计对明显违规有效,但无法表达「轻度可疑、需要人工看一眼」的中间状态。连续风险分把判定推迟到复核环节,降低了误伤成本。", False)]) bullet_rich(doc, [("从单一强信号到多信号融合。", True), ("视觉方案依赖摄像头这一强信号,一旦设备缺失或考生遮挡即失效;本研究采用五个弱信号加权,单个信号失效不影响整体可用性,代价是必须在标注样本上验证各信号的区分度(AUC)。", False)]) bullet_rich(doc, [("从追求准确率到验证信号有效性。", True), ("本研究的定位是信号有效性验证,而不是追求绝对准确率。这一定位既符合本科论文的可行性,也避开了与商业 AI 监考产品在模型能力上的正面比较。", False)]) para(doc, "在论文表述上,建议明确写出:本研究的贡献不是更高的识别准确率,而是给出一套低成本、可解释、可复核的风险度量方法,并用 200 条标注样本量化各信号的单变量区分度。这样的表述既诚实又有边界,评审难以从「效果不如商业产品」的角度发难。") # ---------------- 3.4 ---------------- heading(doc, "3.4 支撑研究点:交卷—判分—成绩的一致性", 2) para(doc, "方案 B 把「交卷、客观题判分、成绩发布」三步的一致性作为支撑研究点,采用本地消息表 outbox 加定时对账,主观题采用双评加仲裁。这一设计在开源生态中同样有对应物:砚考的统计汇总表采用预计算加每 10 分钟定时重算兜底,本质上就是「先算后校」的对账思想;其主观题按「考试、答卷、逐题」三级人工阅卷并记录改分日志,与双评仲裁的审计需求同构。") para(doc, "这一研究点的价值在于实验成本低、指标硬:注入异常后的不一致记录检出率、对账修复率、端到端时延都是可直接测量的量,且 Testcontainers 能在测试中真实重启数据库,构造出「消息已发、下游未处理」的经典故障。建议在论文第 6 章保留这组实验,它与问题二共享同一套故障注入设施,边际成本很低。") def chapter4(doc): heading(doc, "第四章 平台、标准与学术检索", 1) heading(doc, "4.1 国际测评平台", 2) para(doc, "国际平台的价值不在于代码复用(体量与栈差异过大),而在于概念模型与标准实践。Moodle 的 question_attempts 状态机是「可恢复答题过程」最成熟的公开设计;Open edX 的 ProctoringProvider 接口把监考能力抽象为可替换的服务提供者,对本研究「作弊识别模块对外只暴露 api 包」的设计有直接启发;TAO 则以 QTI 标准为核心,试卷结构与判分模型最为规范。") caption(doc, "表 4-1 国际测评平台") make_table(doc, ["平台(点击进入仓库)", "语言", "星标 / 许可", "可借鉴之处"], [[("moodle/moodle", GH + "moodle/moodle"), "PHP", "7594 / GPL-3.0", "mod_quiz 的 question_attempts 状态机与分步保存,是断网续考最好的理论参照;题库分类与随机题机制可对照 paper_rule 设计"], [("openedx/edx-platform", GH + "openedx/edx-platform"), "Python", "8220 / AGPL-3.0", "ProctoringProvider 抽象:把监考做成可插拔提供者,对应本研究 monitor 模块的边界设计"], [("oat-sa/tao-core", GH + "oat-sa/tao-core"), "PHP", "64 / GPL-2.0", "基于 QTI 的测评引擎,试题与试卷的数据结构最规范,适合引用其模型"], [("mawoka-myblock/ClassQuiz", GH + "mawoka-myblock/ClassQuiz"), "Svelte + FastAPI", "737 / MPL-2.0", "Kahoot 式实时答题,可参考开考瞬间的高并发广播(Socket.IO)与房间模型"], [("tomwalker/django_quiz", GH + "tomwalker/django_quiz"), "Python", "628 / 无", "题型与计分规则的简洁设计,适合作为需求分析阶段的题型枚举参照"]], [4.4, 2.6, 2.6, 5.8], link_col=0) heading(doc, "4.2 标准", 2) para(doc, "若论文打算讨论「题库与试卷的可迁移性」或「试题格式的标准化」,1EdTech 的 QTI(Question and Test Interoperability)是必须提及的标准,当前版本为 QTI 3。该标准定义了试题(Item)、测试(Test)、结果(Result)三类文档的 XML 结构,Moodle 与 TAO 均有部分实现。对本研究而言,引入 QTI 的实际意义有限(系统内部用关系表存储即可),但在第 2 章相关技术部分用一小段说明「为什么选择自定义模型而非直接采用 QTI」,可以体现对领域的了解。") link_para(doc, [("1EdTech QTI 标准首页:", "https://www.1edtech.org/standards/qti")]) heading(doc, "4.3 学术检索方向", 2) para(doc, "方案 B 第十一章已给出文献策略,本节在其基础上补充与开源调研对应的英文检索方向。建议每个研究点至少精读三篇核心期刊论文,把方法、指标与数据集记入笔记,研究点的表述即从中提炼。") caption(doc, "表 4-2 按研究点补充的检索方向") make_table(doc, ["研究点", "建议检索词", "关注要点"], [["问题一 组卷", "automatic test paper generation;constrained combinatorial optimization;genetic algorithm examination timetabling", "约束表达方式、适应度函数设计、与排课问题的同构性、评价指标(覆盖率、偏差)"], ["问题二 一致性", "local-first software;optimistic replication;idempotent write;conflict resolution CRDT", "版本向量与修订号语义、幂等键设计、最终一致性的可测指标"], ["问题三 作弊识别", "online proctoring detection;anomaly detection in e-assessment;behavioral biometrics keystroke", "信号清单、标注样本构造方式、召回率与误报率的权衡表述"], ["支撑点", "transactional outbox pattern;reconciliation job;eventual consistency measurement", "对账任务设计、不一致检出率度量"]], [3.4, 6.4, 5.6]) heading(doc, "4.4 许可证风险与合规建议", 2) para(doc, "开源调研的一个实务问题是许可证。本研究所涉项目覆盖 AGPL-3.0、GPL-2.0/3.0、MPL-2.0、Apache-2.0、MIT 与未声明六种情形,处置方式差别很大。") caption(doc, "表 4-3 许可证类型与处置建议") make_table(doc, ["许可证", "涉及项目", "约束强度", "建议"], [["AGPL-3.0", "学之思 xzs-mysql / xzs,Open edX", "最强,网络服务亦触发开源义务", "仅借鉴设计与表结构,不复制代码;论文中作为对比对象引用"], ["GPL-2.0 / 3.0", "Moodle、TAO、Aankh、ITMOproctor", "强,衍生作品须同许可", "同上;若确需复用片段,单独隔离并注明来源"], ["MPL-2.0", "Safe Exam Browser 系列、ClassQuiz、hacklympics", "中等,文件级传染", "可复用单个文件并保留声明,适合参考具体算法实现"], ["Apache-2.0", "or-tools、Timefold、rxdb、pouchdb、Dexie.js、ShedLock", "宽松,需保留声明与变更说明", "可作为依赖直接引入,注意 NOTICE 文件"], ["MIT", "砚考、lsgwr 版、Proctoring-AI、Testcontainers、Django 系", "宽松,保留版权声明即可", "最适合作为代码级参考与依赖"], ["未声明", "YXJ2018 版、shuzhao11/quiz、cppcpp/exam-system、wulivictor/ExamOnline", "法律状态不明", "只读不抄;引用时注明「未声明许可证」"]], [2.6, 6.2, 4.0, 5.2]) note(doc, "建议:论文与源码仓库中统一采用 MIT 或 Apache-2.0 声明自身代码;对 AGPL/GPL 项目仅作设计参考,并在参考文献或脚注中标注「设计参考,未使用其代码」,以避免答辩时的合规质疑。") def chapter5(doc): heading(doc, "第五章 论文写作与实验落地建议", 1) heading(doc, "5.1 与论文章节的对应关系", 2) para(doc, "本文档的素材可直接落入方案 B 已规划的七章结构中,对应关系如表 5-1。") caption(doc, "表 5-1 调研素材与论文章节的对应") make_table(doc, ["论文章节", "可用的调研素材", "使用方式"], [["第 1 章 绪论", "本文档第 1.4 节五条结论、表 2-2 能力对照、3.2.1 检索记录", "改写为国内外研究现状;空白结论作为研究意义的论据"], ["第 2 章 相关技术", "表 2-1 技术栈落地证据、第 4.2 节 QTI、表 3-1/3-3 求解器与同步引擎", "技术选型依据,说明每一项均有成熟实践"], ["第 3 章 需求分析", "表 2-2 中「无」的维度、3.3.2 信号对照表", "把差距转化为功能需求与非功能需求"], ["第 4 章 系统设计", "砚考的微服务形态(反例)、其模块划分与表结构", "架构取舍论证:为什么模块化单体优于微服务"], ["第 5 章 关键方法", "3.1.4 实验基线、3.2.4 协议设计、3.3.3 方法边界", "三个方法的立论与对照设计"], ["第 6 章 实现与测试", "表 3-3 中 Testcontainers、ShedLock;3.4 节对账实验", "故障注入与一致性实验的工程依据"], ["第 7 章 总结与展望", "2.4.2 的差距、第 4.1 节平台的能力边界", "局限说明与演进路径"]], [3.4, 7.0, 5.0]) heading(doc, "5.2 可直接改写的研究现状段落", 2) para(doc, "以下三段为按学术语体撰写的研究现状素材,分别对应三个研究点,可按需裁剪、补充文献编号后直接使用。") para(doc, "(一)关于组卷。", bold=True, first_indent=True) quote(doc, ["现有开源在线考试系统普遍将组卷实现为「按题型、难度、分值等条件从题库过滤后随机抽取」的筛选过程。学之思开源考试系统与「砚考」在线考试系统均采用此类规则驱动的组卷方式,规则可保存复用,候选不足时向用户提示,但系统本身不保证约束的可满足性,也未对求解质量给出度量。学术研究中虽有基于遗传算法的自动组卷实现,但多停留在算法演示层面,缺少对约束强度与求解成功率之间关系的系统考察。相比之下,通用约束求解器(如 Google OR-Tools 的 CP-SAT、Timefold Solver)已具备成熟的建模与求解能力,但尚未被适配到考试组卷这一具体场景。本文因此将组卷形式化为「题库—约束集—目标」三元组,并在统一接口下比较三类求解策略在不同约束强度下的表现。"]) para(doc, "(二)关于断网续考。", bold=True, first_indent=True) quote(doc, ["断网续考是考试系统可靠性的核心诉求,但现有开源实现的处理方式高度一致:答题过程逐题提交并持久化,考生重新进入后可恢复此前作答,即所谓「断点续答」。Moodle 的 question_attempts 状态机以分步记录的方式保存作答过程,是该类设计中最为完备的公开实现;国内学之思与「砚考」亦提供中途退出续答与倒计时归零自动交卷能力。然而上述实现的共同前提是「网络恢复后以服务端数据为准」,客户端本地内容仅被视为尚未送达的暂存,系统并未定义同一作答在客户端与服务端被并发修改时的裁决规则,也未对断网期间的作答数据完整性给出度量。本文因此引入客户端本地草稿、服务端唯一索引幂等写入与基于游标的增量同步三者配合的一致性协议,并通过故障注入验证其在网络中断、服务重启与多端登录三种情形下的收敛性。"]) para(doc, "(三)关于作弊识别。", bold=True, first_indent=True) quote(doc, ["在线考试的作弊识别在开源生态中呈现明显的路线集中:主流方案以摄像头画面为输入,通过人脸检测、视线估计、目标检测等技术识别异常行为,代表性实现包括 Proctoring-AI、MyProctor.ai 等;另一条路线是客户端锁机,以 Safe Exam Browser 生态为代表,通过限制终端行为而非识别行为来达成目的。国内系统则多采用浏览器事件计数的方式,对切屏、失焦、复制粘贴等行为累计次数并在达到阈值时强制交卷。上述方案各有其成本结构:视觉方案依赖终端设备、算力与隐私授权,锁机方案依赖专用客户端,计数方案则以二值判定牺牲了对中间可疑状态的刻画能力。本文采用多信号加权风险分的方式,在不引入深度模型的前提下融合五类低成本行为信号,并以标注样本上的召回率、误报率与单信号 AUC 度量其有效性。"]) heading(doc, "5.3 实验与基线设置建议", 2) para(doc, "综合前文分析,三个研究点的实验可按表 5-2 组织。其中「对照物」一列是本轮调研最直接的产出:没有对照的实验只能自证,有对照的实验才能说明水平。") caption(doc, "表 5-2 三个研究点的实验组织建议") make_table(doc, ["研究点", "基线(必须做)", "对照物(体现水平)", "核心指标"], [["问题一 组卷", "随机抽题加重试(既有系统做法)", "cppcpp/exam-system 的遗传算法;or-tools CP-SAT 的精确解作为质量上界", "成功率、单次耗时、难度分布 KL 散度、知识点覆盖偏差、总分误差"], ["问题二 续考", "仅服务端保存(无本地草稿)", "rxdb 式「最后写入胜出」的朴素合并", "答案完整率、重复提交次数、恢复时长、草稿丢失条数、语义正确率"], ["问题三 作弊", "单信号阈值判定", "等权求和(无权重优化的朴素融合)", "召回率、误报率(200 条标注)、单信号 AUC、风险分分布"], ["支撑点 一致性", "同步调用判分(无 outbox)", "仅有重试、无对账", "不一致检出率、对账修复率、端到端时延"]], [2.8, 4.4, 5.6, 4.8]) heading(doc, "5.4 答辩可能追问的问题", 2) para(doc, "调研过程中反复出现的几个对比点,很可能成为答辩提问的起点。提前准备应答素材,比临场解释更可靠。") caption(doc, "表 5-3 预设追问与应答要点") make_table(doc, ["可能的追问", "应答要点"], [["学之思、砚考已经做得很完整,你的系统有什么价值?", "它们解决的是功能覆盖,本文解决的是方法质量:组卷从筛选到求解、续考从保存到一致性协议、防作弊从计数到风险度量。表 2-2 可逐项说明。"], ["为什么不用微服务?别人都用微服务。", "三个研究点都在单业务边界内闭环;断网续考的一致性本质是唯一索引,单库成本最低;拆分带来的跨库幂等与运维成本会挤占实验时间。砚考的微服务形态可作为对照,说明其代价。"], ["为什么不直接用现成的组卷算法?", "现成实现多为规则筛选,无约束求解保证;学术型遗传算法实现缺少约束强度与退化曲线的度量。本文的增量在于定量关系,而非算法本身。"], ["断网续考是不是已经有成熟方案?", "开源生态中未见以冲突裁决为核心的系统,既有实现停留在逐题保存与断点续答,隐含假设是「恢复后以服务端为准」。本文的协议显式定义了并发修改的裁决规则。"], ["为什么不做摄像头监考?", "成本与合规:摄像头方案需要终端设备、算力与隐私授权。本文定位是低成本信号的有效性验证,已在 3.3.3 明确方法边界。"], ["200 条标注样本会不会太少?", "样本量为可行性所限,但指标设计上采用单信号 AUC 与风险分分布,避免只报一个总体准确率;结论表述为信号有效性的初步验证,而非最终精度。"], ["引用这些开源项目,是否存在抄袭风险?", "全部为设计层面参考,未复制代码;AGPL/GPL 项目仅作对比对象,许可证处置见表 4-3。"]], [6.4, 9.0]) heading(doc, "5.5 仍需补充的工作", 2) bullet_rich(doc, [("精读两个主参考仓库的源码。", True), ("本文档的能力对照基于 README 与文档描述,建议在动工前用半天时间通读学之思的答卷表结构与砚考的防作弊事件表,把字段级细节记入笔记,这对第 4 章的数据模型设计帮助极大。", False)]) bullet_rich(doc, [("补充核心期刊文献。", True), ("表 4-2 的检索方向需要落到具体论文,每个研究点至少三篇,并在第 2 章形成综述段落。这一步无法由开源调研替代。", False)]) bullet_rich(doc, [("验证 or-tools 的 Java 绑定可用性。", True), ("若计划把 CP-SAT 作为对照组,需提前验证 JDK 17 下的依赖引入与求解器调用,避免实验阶段才发现环境问题。", False)]) bullet_rich(doc, [("确认许可证声明的时效性。", True), ("星标数与提交时间随仓库变化,论文定稿前应重新查询一次并更新表 2-1 的数据与查询日期。", False)])