这是一个轻量化的 Online Judge 系统,用于大学本科 coding 作业的自动化评分。支持各种作业类型,包括:传统算法题、理论推导题、开放性工程问题。
传统 OJ(Codeforces、LeetCode)只能判定"唯一正确答案"的算法题。随着 AI 发展,简单的算法题作为作业已经没有什么价值,学生全都用 AI 生成代码直接提交,学不到任何知识;而 ACM 中 hard 级别的算法题不适合作为作业。作为老师与助教,我们需要重新思考:什么样的 coding 作业,才能锻炼学生在 AI 时代下的 coding 能力?
我们的答案是:让学生做开放性工程问题。这类问题没有标准答案,只有谁更优,而且通常需要结合各类 AI 工具去迭代调优。但是这类问题难以用传统 OJ 去评分。Kaggle 风格的打榜平台契合此趋势,但闭源、无法部署到校内轻量服务器,也不支持 MATLAB 等教学语言与手写作业批改。
于是我们做了一个轻量化的系统:把 Kaggle 风格打榜赛首次带进开源、可单机部署的教学 OJ。同时也支持传统算法题、手写和 TeX 理论作业题。支持 MATLAB/C/C++/Python 四语言判题,附带班级管理、作业管理、代码查重、书面作业 AI 批改等教学功能。内嵌了多种 AI 功能,包括:
- 支持自定义任务、自动解题和自动造数据,并且会自己测试和反复尝试的通用 Agent
- 帮学生找代码 bug、划出错误代码的 AI 助教
- 支持图片批改、Promptly、Agent-as-Judge、反向评测等多种模式的自动化评分系统
目前已应用于"数据结构与算法"、"数值分析"、"计算方法"、"数学软件"、"数学软件与人工智能"等多门本科课程,注册用户 900+,累计提交 4 万+ 份。
- 用户与班级管理:注册、邮箱验证、班级创建与管理、按班级布置作业、成绩导出、提交次数限制。
- 编程题:
- 支持标准输入输出和 checker 评测,可以按题目限制禁用函数。
- 支持让程序生成图片,再由多模态模型按要求评分。
- 支持 Promptly:学生只提交解题思路,由 AI 审查、生成代码,再进入正常评测。
- 学生可以在提交详情中询问 AI 助教,直接查看错误代码和改进建议。
- 通用 Agent 会话:支持 Claude Code 与 Pi。管理员可以选择模型与 user/admin 执行身份,发起自定义任务并上传附件;每个会话的 workspace 持久保留在服务器,可以只读浏览、预览和下载文件,任务结束后还可恢复已有工作区继续会话。会话会冻结所选节点版本,避免排队或续聊时静默切换模型配置。原有解题 / 造数据 Agent 入口仍然保留,并统一纳入这套会话管理。运行过程可以实时查看,也可以使用 Web 搜索。
- 书面作业题:支持手写 PDF 的 OCR 与 LaTeX 转写、直接图片批改、TeX 作业自动评分和纯人工批改。
- 代码查重与 AI 生成代码检测:既可以检查代码相似度,也可以结合大模型与提交行为识别疑似 AI 生成的代码。老师可以按班级、题目、学生等条件批量筛选和复核。
- 全站 AI 配置:管理员可以集中管理模型、测试连接,并给不同功能选择不同模型。通用 Agent 任务(包括解题 / 造数据兼容入口)和 AI 检测也可以在每次运行时单独选择。
- 个人代码仓库:每个用户都可以在线管理自己的代码文件和目录,支持批量上传、在线编辑、代码结构浏览和自然语言检索,提交和 Agent 运行时可以直接复用。
- 打榜赛:
- 支持标准答案评分、ELO 对战、Agent-as-Judge 和反向评测四种模式。
- Agent-as-Judge 会阅读并实际运行完整项目,再按照老师设置的规则评分。学生可以查看每条规则的结论、评分证据和完整运行过程,并对结果发起申诉。
- 反向评测由学生出题挑战 AI。AI 解得越差,出题者得分越高;整个解题过程可以实时查看,也可以下载 AI 的最终答案。
- 支持上传项目、提交 Git 仓库、按班级批量评测和批量重测。
- 论坛:题目讨论、回复、置顶等。
- VibeHub 作品:支持创建或更新时预构建并自动送审、审核发布,以及隔离按需启动围住小猫、ARC-AGI-3、黑盒数据结构猜测等互动作品。edu 作品可直接布置为班级作业,独立保存作答和成绩,并纳入作业成绩导出;内置动态平衡术 C++ 双堆可视化作业。
NumericalOJ 采用前后端分离的代码结构,同时由 Flask 在生产环境同源分发构建后的 SPA,避免额外的 跨域认证与部署复杂度:
backend/
├── oj.py # Flask / Celery 组合根
├── oj_modules/ # API、路由、任务与领域逻辑
├── database/ # 初始化 schema
└── requirements/ # Python 精确依赖
frontend/
├── src/ # React + React Router + TanStack Query SPA
├── public/static/ # 原页面视觉资产与兼容浏览器运行时
├── scripts/ # 前端构建和预压缩脚本
└── tests/ # 前端测试
SPA 直接使用 /problems、/submissions、/rankings 等无统一前缀的业务路径;已退役的 /app 与
/app/* 不提供兼容跳转并直接返回 404。主导航切换不会重新加载页面;路由模块会在鼠标悬停、键盘聚焦和浏览器闲时预取,
读接口由 Query 缓存复用。生产构建使用内容指纹文件名并生成 Brotli/Gzip 旁路文件,指纹资源可长期
immutable 缓存,index.html 保持重新验证,从而兼顾快速切换与版本更新安全。页面继续复用迁移前的
DOM/CSS 视觉合同,技术栈迁移不改变既有视觉设计。
Python 基线为 3.12,Node.js 版本见 .node-version。安装依赖后分别启动两个开发服务:
python3 -m venv .venv
.venv/bin/pip install -r backend/requirements/production.txt -r backend/requirements/test.txt
cd frontend
npm ci
npm run dev另一个终端在项目根目录启动后端:
.venv/bin/python -m backend.ojVite 默认运行在 127.0.0.1:5173,并把 API 和认证请求代理到 127.0.0.1:2025。生产发布仍只使用
项目根目录的 bash deploy.sh;该脚本会在候选环境中构建 React 产物并预压缩静态资源。