基于Spring Boot与Spring AI的AI作业批改系统设计与实现
2026/8/31 12:41:05 网站建设 项目流程

AI 作业批改系统并不是简单地把作业文本发给大模型,然后把模型返回的文字展示给教师。真正能用于教学场景的系统,必须处理作业提交、文本解析、评分规则、结果结构化、教师复核、班级学情汇总这一整条链路。很多团队在做这个功能时会发现,最花时间的往往不是调用模型,而是如何让模型输出稳定、如何保存批改痕迹、如何在模型出错时兜底。这篇文章以一个普通中学数学作业批改场景为背景,使用 Spring Boot 和 Spring AI 对接 OpenAI 兼容接口,从零搭建一个最小可运行的 AI 作业批改系统,覆盖数据库设计、文件上传、大模型调用、结构化输出解析、结果落库和人工确认,并给出生产环境上线前需要重点检查的问题。

1. 先理解 AI 作业批改系统的核心闭环

1.1 教学闭环为什么需要 AI 批改

传统教学流程大致是:教师布置作业,学生完成并提交,教师批改后发回,学生根据反馈订正,最后教师根据整体情况调整后续教学。这个循环里真正消耗教师精力的是批改和统计,尤其是数学、物理这类有计算步骤的学科,批改不仅要看最终答案,还要看过程是否完整、公式是否规范、逻辑是否跳跃。

AI 作业批改系统要解决的是这个循环中最耗时的“批改反馈”环节。系统先调用大模型生成一版初评,给出分数、评语、逐题结果和可能的错误原因;教师不需要从零开始批改,只需要复核初评、修改不合理的部分、补充教学意见,然后提交最终结果。这样反馈时间从原来的隔天缩短到当天,教师也能从批量批改中抽身出来,把时间花在教学设计上。

这里说的“教学闭环”不是一句口号,而是一条完整的数据链路:布置作业、学生提交、自动初评、教师复核、结果反馈、学情统计、教学调整。AI 批改系统能沉淀的是“批改环节”产生的数据,包括每道题的对错、得分、错误类型、评语和教师修正记录。这些数据如果留在纸质作业本上,很难被继续利用;一旦进入数据库,就可以按班级、知识点、学生维度做分析,为教学调整提供依据。

1.2 AI 批改与传统批改软件的差异

传统作业批改软件大多基于标准答案做匹配,擅长处理选择题、填空题、判断题,或者通过 OCR 识别后与标准答案比对。这类系统对主观题、步骤题、开放题几乎没有处理能力。大模型驱动的 AI 批改则不同,它可以根据题目文本、参考答案和学生作答生成自然语言反馈,也能对“过程正确但答案错误”这类情况做出相对合理的判断。

两者的对比如下:

对比维度传统批改软件AI 大模型批改
适用题型选择题、填空题、判断题选择题、填空题、计算题、开放题
批改依据标准答案比对题目、参考答案、评分规则、模型理解
反馈内容对错和分数分数、评语、错因分析、订正建议
处理能力依赖题库和模板能处理未见过的表达方式
稳定性规则固定,误差小存在幻觉和格式不稳定风险
人工介入基本不需要需要教师复核,保留最终决定权

从表中能看出,AI 批改并不是要替代规则系统,而是补足传统系统处理不了的开放性内容。实际落地时,比较稳妥的做法是选择擅长文本理解的模型,同时保留人工复核环节。教师不是被替换,而是从“手工批改者”变成“AI 初评的审核者”。

1.3 系统的核心模块

一个最小可运行的 AI 作业批改系统至少包含五个模块:

  • 作业中心:维护作业题目、参考答案、总分、学科和年级。
  • 提交中心:接收学生或教师上传的作业文件,保存文件并生成提交记录。
  • 批改引擎:从作业中心读取题目和参考答案,从提交中心读取学生作答,调用大模型生成初评。
  • 反馈中心:保存模型输出、解析后的结构化结果、教师反馈和最终状态。
  • 学情汇总:按班级、知识点、学生统计得分率、错误类型和进步趋势。

在最小闭环里,前四个模块必须完整,学情汇总可以先用一个简单的 SQL 查询代替。很多项目失败不是因为模型不够强,而是把注意力全放在“调用模型”上,忽略了作业、提交、批改结果这三张核心表之间的关系。数据模型没有设计好,后面做统计和追溯就会非常痛苦。

2. 技术选型与项目环境准备

2.1 整体技术栈

这个系统适合用单体应用起步,不需要一上来就拆微服务。对于普通中学的作业量,单机应用配合关系型数据库就足够支撑日常使用。技术栈选型可以参考下表:

模块选型说明
后端框架Spring Boot 3.x生态成熟,适合快速构建 REST API 和定时任务
AI 接入层Spring AI统一封装多个大模型接口,减少重复代码
大模型接口OpenAI 兼容接口方便切换不同供应商或本地模型服务
数据库MySQL 8.x作业和批改结果需要强一致性和事务支持
文件存储本地目录学习环境使用,生产环境建议替换为对象存储
前端简单 HTML 或 Vue演示用,不在本文重点范围
测试工具curl、Postman验证上传和批改接口

选择 Spring AI 的原因是它把“调模型”封装成了统一的 ChatClient 接口。如果今天用 OpenAI,明天换成部署在内部的 vLLM 服务,只要服务端兼容 OpenAI 协议,应用层代码基本不需要大改。如果团队之前没有接触过 Spring AI,也可以直接用 Java HttpClient 写一个简单的调用封装,但那样就要自己处理请求拼接、重试和异常解析,工程成本更高。

2.2 环境要求

本地开发环境建议满足以下条件:

  • JDK 17 或更高版本,Spring Boot 3 要求 JDK 17 起。
  • Maven 3.9+,用于依赖管理和构建。
  • MySQL 8.x,用于保存作业和批改数据。
  • 一个可用的 OpenAI 兼容模型接口,需要提前准备 API Key。
  • 如果没有外部 API,也可以用 Ollama 或 vLLM 在本地启动兼容接口。

先在命令行确认基础环境:

java -version mvn -v mysql --version

如果某个命令不存在,先安装对应工具。JDK 版本过低会导致 Spring Boot 3 启动失败,这是第一个需要提前确认的点。大模型接口方面,如果还没有 API Key,可以先用公开的模型服务商申请一个测试 Key,或在本地启动一个基于 Ollama 的模型,把base-url指向本地地址。示例代码里用${OPENAI_API_KEY}环境变量,避免把密钥硬编码在配置文件中。

2.3 项目结构规划

项目取名为ai-homework-review,包名统一为com.example.aihomework。层级按 Controller、Service、Repository、Entity、DTO 划分,简单清晰:

ai-homework-review/ ├── pom.xml └── src/main/java/com/example/aihomework/ ├── AiHomeworkApplication.java ├── controller/ │ ├── SubmissionController.java │ └── ReviewController.java ├── service/ │ ├── HomeworkService.java │ └── AiReviewService.java ├── repository/ │ ├── HomeworkRepository.java │ ├── SubmissionRepository.java │ └── ReviewRepository.java ├── entity/ │ ├── Homework.java │ ├── HomeworkSubmission.java │ └── SubmissionReview.java └── dto/ ├── ReviewResult.java └── ReviewItem.java

这种结构对初学者足够清晰。不要把业务逻辑堆在 Controller 里,否则后续加缓存、加消息队列时很难拆。文件上传使用本地目录,代码里设置一个uploads根目录,按 homeworkId 分文件夹存放,避免所有文件堆在一层。

2.4 配置 Spring AI 与模型参数

application.yml是启动时最关键的配置文件。除了数据源和文件上传大小限制,还要配置模型供应商信息:

spring: application: name: ai-homework-review servlet: multipart: max-file-size: 5MB max-request-size: 10MB datasource: url: jdbc:mysql://localhost:3306/ai_homework?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: ${MYSQL_PASSWORD} ai: openai: api-key: ${OPENAI_API_KEY} base-url: ${OPENAI_BASE_URL:https://api.openai.com} chat: options: model: gpt-4o-mini temperature: 0.2 max-tokens: 2048

这里有几个关键点要注意。

${MYSQL_PASSWORD}${OPENAI_API_KEY}是环境变量,实际启动前必须在系统环境或 IDE 配置中注入,不能把真实密钥提交到 Git。base-url默认指向 OpenAI,也可以改成内网兼容服务的地址,例如http://localhost:8000/v1temperature: 0.2是评分任务需要用低随机性,温度太高会让同样一份作业每次批改结果差异很大。max-tokens: 2048是为了限制模型输出长度,既能防止单次请求成本过高,也能减少解析超时。

3. 数据库设计与核心表结构

3.1 表结构设计前先想清楚数据流

批改系统的数据流可以描述为:教师创建作业,学生提交文件,系统生成一条提交记录,调用模型后生成一条批改记录,教师再对批改记录进行确认或修改。这个流程决定了表结构不能只设计一张“作业表”和一张“成绩表”,至少需要三张核心表。

homework表保存作业本身;homework_submission表保存每次提交;submission_review表保存批改结果。把提交记录和批改结果分开,是因为一次提交可能被重新批改多次。比如模型第一次调用失败,或者教师认为初评不准确要求重新生成,批改记录可以保留多份,便于回溯和对比。

3.2 建表 SQL

下面是 MySQL 8 的建表语句,可以作为起步版本:

CREATE TABLE homework ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, subject VARCHAR(50) NOT NULL, grade VARCHAR(50) NOT NULL, content TEXT, answer_key TEXT, max_score INT DEFAULT 100, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE homework_submission ( id BIGINT PRIMARY KEY AUTO_INCREMENT, homework_id BIGINT NOT NULL, student_no VARCHAR(50) NOT NULL, file_path VARCHAR(500), submit_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_homework_id (homework_id) ); CREATE TABLE submission_review ( id BIGINT PRIMARY KEY AUTO_INCREMENT, submission_id BIGINT NOT NULL, score DECIMAL(5,2), max_score INT, ai_feedback TEXT, model_output TEXT, review_status VARCHAR(20) DEFAULT 'PENDING', teacher_feedback TEXT, reviewer VARCHAR(100), reviewed_at DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_submission_id (submission_id) );

homework表中的content保存题目文本,answer_key保存参考答案。homework_submission表把文件放在file_path字段,而不是直接把二进制内容存进数据库。文件走文件系统或对象存储,数据库只保存路径,这样数据库体积不会快速膨胀。

submission_review表中的model_output字段非常关键。它保存模型返回的原始 JSON 字符串,即使解析失败,也可以通过这个字段看到模型到底输出了什么。生产环境排查问题的时候,model_output就是第一手证据。

3.3 为什么需要批改流水表而不是只存最终分数

如果只想做一个“自动打分”功能,可能一张成绩表就够了。但真实教学场景需要回答很多问题:这次批改是模型生成的还是老师确认过的?老师改了哪些内容?模型初评的分数和最终分数差了多少?这些信息都依赖批改流水表。

所以submission_review里的review_status字段会保持三个状态:

状态值含义
PENDING模型初评完成,等待教师确认
CONFIRMED教师确认通过,结果可发给学生
REJECTED教师驳回初评,可能需要重新批改或人工批改

teacher_feedback字段保存教师的修改或补充意见。即使 AI 初评已经很好,教师仍可以附加一句“第 3 题需要重做”,这个信息应该保留下来,作为最终发给学生的反馈的一部分。

4. 实现最小可运行的作业批改接口

4.1 作业提交接口

先实现根据homeworkId接收学生作业文件并生成提交记录的接口。Controller 层的职责只是接收参数、调用 Service、返回结果:

@RestController @RequestMapping("/api/submission") public class SubmissionController { private final HomeworkService homeworkService; public SubmissionController(HomeworkService homeworkService) { this.homeworkService = homeworkService; } @PostMapping public ResponseEntity<Long> submit(@RequestParam Long homeworkId, @RequestParam String studentNo, @RequestParam("file") MultipartFile file) { Long submissionId = homeworkService.saveSubmission(homeworkId, studentNo, file); return ResponseEntity.ok(submissionId); } }

Service 里做文件保存和数据库写入:

public Long saveSubmission(Long homeworkId, String studentNo, MultipartFile file) { String dir = "uploads/" + homeworkId; Files.createDirectories(Paths.get(dir)); String filePath = dir + "/" + studentNo + "_" + System.currentTimeMillis() + ".txt"; file.transferTo(Paths.get(filePath)); HomeworkSubmission submission = new HomeworkSubmission(); submission.setHomeworkId(homeworkId); submission.setStudentNo(studentNo); submission.setFilePath(filePath); return submissionRepository.save(submission).getId(); }

这里要先判断文件是否为空、文件大小是否超限、文件名是否包含非法路径。学习环境可以简化,但生产环境必须做白名单校验。文件类型只允许常见的.txt.pdf.png.jpg,不能允许上传.jsp.exe等可执行文件。文件名如果直接使用用户输入,还可能拼接出路径穿越问题,所以要使用服务端生成的文件名,或者对原始文件名做严格过滤。

4.2 使用 Spring AI 调用大模型

批改接口的核心是AiReviewService。在 Spring AI 中,最常用的入口是ChatClient,它封装了模型调用的细节:

@Service public class AiReviewService { private final ChatClient chatClient; public AiReviewService(ChatClient.Builder builder) { this.chatClient = builder.build(); } public String reviewText(String homeworkContent, String answerKey, String studentAnswer) { String prompt = buildPrompt(homeworkContent, answerKey, studentAnswer); return chatClient.prompt(prompt).call().content(); } }

这里的ChatClient.Builder是 Spring AI 提供的构造器,Spring 容器会自动注入。具体 API 在不同版本里可能有细微调整,但整体思路不变:构建 prompt 文本,传给模型,拿到返回字符串。

实际开发时,建议把 prompt 模板放到外部文件里,而不是拼在 Java 代码中。这样可以随时修改提示词而不需要重新编译和发布服务。项目结构中预留的prompts/review-prompt.txt就是用来干这个的。

4.3 设计批改 Prompt 并约束输出格式

大模型批改能否成功,很大程度取决于 Prompt 设计和输出格式约束。下面是一份用于中学数学作业批改的 Prompt 模板:

你是初中数学老师。请根据作业题目和参考答案,批改学生提交的答案。 要求: 1. 先按参考答案判断每道题的对错。 2. 如果学生答案不完整,不能直接判错,标记为“待教师确认”。 3. 返回 JSON,不要返回任何解释性文字。 4. JSON 格式严格按下面的结构: { "score": 85, "maxScore": 100, "comments": "总体不错,但计算题第2题有步骤缺失。", "items": [ {"questionNo": 1, "result": "CORRECT", "score": 10, "comment": "正确"}, {"questionNo": 2, "result": "PARTIAL", "score": 5, "comment": "过程正确,最后一步计算有误"} ] } 作业题目: {homeworkContent} 参考答案: {answerKey} 学生答案: {studentAnswer}

这份模板有几个设计点值得注意。

第一,明确告诉模型“返回 JSON,不要返回其他文字”。如果没有这句,模型经常会在 JSON 前后加上“好的,这是批改结果:”之类的废话,导致解析失败。

第二,把参考答案和学生答案都放进去。大模型并不知道你布置了什么题,必须把上下文完整给它。只给“请批改”三个字,模型就会自由发挥。

第三,限制了枚举值,比如result只允许CORRECTPARTIALWRONG待教师确认。枚举值越明确,后续代码越容易处理。

4.4 解析模型返回并落库

模型返回的是一个 JSON 字符串,需要把它解析成 Java 对象。可以定义一个ReviewResultDTO:

public class ReviewResult { private BigDecimal score; private Integer maxScore; private String comments; private List<ReviewItem> items; public static class ReviewItem { private Integer questionNo; private String result; private BigDecimal score; private String comment; } }

解析和落库的流程如下:

public SubmissionReview createReview(Long submissionId) { HomeworkSubmission submission = submissionRepository.findById(submissionId).orElseThrow(); Homework homework = homeworkRepository.findById(submission.getHomeworkId()).orElseThrow(); String modelContent = aiReviewService.reviewText( homework.getContent(), homework.getAnswerKey(), readFile(submission.getFilePath()) ); ReviewResult result = objectMapper.readValue(modelContent, ReviewResult.class); SubmissionReview review = new SubmissionReview(); review.setSubmissionId(submissionId); review.setScore(result.getScore()); review.setMaxScore(result.getMaxScore()); review.setAiFeedback(result.getComments()); review.setModelOutput(modelContent); review.setReviewStatus("PENDING"); return reviewRepository.save(review); }

objectMapper.readValue可能抛出JsonProcessingException。一旦模型没有按约定返回 JSON,这里会直接报错。生产环境不能因为一次模型解析失败就让整个接口 500,应该返回明确的错误码,并把原始modelContent保存到日志或备用表中,方便人工处理。

注意:无论模型输出是否合法,都应该把原始字符串先保存下来。这样就算解析失败,也能人工查看模型到底输出了什么,避免用户抱怨时无从排查。

4.5 教师复核接口

AI 初评结果不能直接视为最终成绩。系统必须提供教师复核接口,让教师确认或修改初评结果。最简单的接口如下:

@PostMapping("/review/{reviewId}/confirm") public ResponseEntity<Void> confirm(@PathVariable Long reviewId, @RequestParam String teacherFeedback) { reviewService.confirmReview(reviewId, teacherFeedback); return ResponseEntity.ok().build(); }

Service 中更新状态:

public void confirmReview(Long reviewId, String teacherFeedback) { SubmissionReview review = reviewRepository.findById(reviewId).orElseThrow(); review.setReviewStatus("CONFIRMED"); review.setTeacherFeedback(teacherFeedback); review.setReviewedAt(LocalDateTime.now()); reviewRepository.save(review); }

这里的关键是状态流转。只有CONFIRMED的结果才能进入学生端或学情统计。如果模型初评质量差,教师可以驳回并重新调用模型,也可以直接在系统里手写最终批改内容。教师复核是 AI 批改系统能进入真实教学的安全底线。

5. 运行验证:用 curl 跑通整个闭环

5.1 启动前准备

如果本地没有 MySQL,可以用 Docker 快速启动一个开发实例:

docker run -d \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=root \ -e MYSQL_DATABASE=ai_homework \ mysql:8

然后启动 Spring Boot 应用:

export MYSQL_PASSWORD=root export OPENAI_API_KEY=your-api-key mvn spring-boot:run

启动后先检查日志,确认数据库连接成功和端口被正确监听。没有异常后,再开始请求接口。

5.2 模拟一次作业提交与批改

先在数据库中插入一份作业:

INSERT INTO homework (title, subject, grade, content, answer_key, max_score) VALUES ('一次函数练习题', '数学', '八年级', '1. 已知 y=2x+1,当 x=3 时,求 y。', 'x=3 时 y=7', 100);

创建一个学生答案文本answer.txt,内容为y=7。然后通过 curl 上传:

curl -X POST http://localhost:8080/api/submission \ -F "homeworkId=1" \ -F "studentNo=2025001" \ -F "file=@answer.txt"

正常返回一个提交记录的 ID,比如12。拿到 ID 后触发批改:

curl -X POST http://localhost:8080/api/submission/12/review

批改接口内部调用大模型,返回结果并写入submission_review表。返回内容可以是提交的reviewId,也可以直接返回解析后的评分结果。

5.3 验证点与预期日志

验证是否成功,不能只看接口返回 200,还要查数据库:

SELECT s.student_no, r.score, r.max_score, r.review_status, r.ai_feedback, r.model_output FROM submission_review r JOIN homework_submission s ON r.submission_id = s.id;

预期结果应满足以下几点:

  • model_output字段保存的是合法的 JSON 字符串。
  • scoremax_score不为空。
  • review_statusPENDING,表示等待教师确认。
  • ai_feedback能对应到本次作业内容。

如果model_output为空,说明模型调用根本没有执行成功。如果model_output有值但解析后score为空,说明 JSON 结构有问题。这个时候应该先打开原始输出,看模型到底返回了什么,而不是急着改 Java 代码。

6. 常见问题排查:从现象倒推根因

6.1 API Key 或 Endpoint 配置导致鉴权失败

问题现象常见原因检查方式处理建议
调用模型报 401 UnauthorizedAPI Key 错误或未传入检查环境变量是否注入重新设置OPENAI_API_KEY,不要硬编码
调用模型报 404base-url 配错或路径不支持检查配置文件中的 Endpoint确认模型服务商要求的完整地址
本地模型服务报模型不存在模型名称与服务端不一致查看模型服务日志和模型列表修改model字段为实际部署模型名

6.2 模型返回格式不稳定导致 JSON 解析失败

这是最常见的坑。现象是ObjectMapper.readValue抛出JsonProcessingException,日志里能看到模型返回了多行解释文字,或者 JSON 末尾多了逗号。

原因通常是 Prompt 没有把“只返回 JSON”的约束写清楚,或者模型版本对指令理解不够稳定。解决方案有几个方向:

  • 在 Prompt 中给出完整示例,比如把一段“错误 JSON”也展示出来并告诉模型不要这么做。
  • 使用支持结构化输出的模型 API,直接把响应格式声明为 JSON Schema。
  • 解析失败时不要立即报错,先保存原始输出,再触发一次重试。
  • 如果连续多次解析失败,把记录标记为REJECTED,转人工批改。

注意:不要把“解析失败”当成偶发问题忽略。只要出现过一次,就说明 Prompt 或模型选择还不够稳定,需要在测试阶段持续收集失败样本。

6.3 超时、限流与并发问题

模型接口响应速度通常在几秒到几十秒之间。如果作业内容很长,单次请求可能超过默认超时时间。现象是接口一直转圈,最终超时或返回 504。

排查时需要关注三件事:

  1. 调用模型是否设置了足够长的读超时。文本批改和聊天不一样,可能需要等待 60 秒以上。
  2. 是否做了并发控制。如果教师批量提交 100 份作业,同时发起 100 个大模型请求,很容易触发供应商限流。
  3. 是否做了重试。限流返回429时,简单重试往往有效,但需要带退避策略。

生产环境建议使用带重试和退避的调用封装。示例:

@Bean public RetryTemplate retryTemplate() { return RetryTemplate.builder() .maxAttempts(3) .fixedBackoff(2000) .retryOn(IOException.class) .build(); }

这里只演示思路,实际项目中要结合 Spring AI 的具体异常类型和供应商限流规则调整重试次数。同时应该用消息队列或异步任务处理批改请求,避免 HTTP 请求长时间占用线程。

6.4 批改不准确或产生幻觉

大模型不是数据库,它并不真正“知道”题目答案,只能根据 Prompt 中提供的信息推理。如果 Prompt 里没有参考答案,模型很可能根据自己的猜测给出错误评分。

最典型的幻觉表现是:题目里根本没有“相似三角形”这个知识点,学生答案也没提,但模型在评语里写“你对相似三角形的判定掌握得不够好”。这类问题无法完全消除,但可以大幅降低。

降低幻觉的做法包括:

  • 必须提供参考答案和评分标准。
  • 要求模型“如果无法从学生答案中判断,就标记为待教师确认”。
  • 限定评语范围:只评学生答案中出现的内容,不要凭想象补充知识点。
  • 设置较低温度,例如 0 到 0.3。
  • 在结果中保留教师复核入口,不允许 AI 直接下达最终结论。

6.5 文件上传大小和类型校验问题

Spring Boot 默认上传文件大小只有 1MB。如果学生上传的是高分辨率拍照作业,很可能会看到MaxUploadSizeExceededException或前端直接报失败。

解决方法是修改spring.servlet.multipart.max-file-sizemax-request-size。但不要盲目调大,生产环境要根据真实作业文件大小设定合理阈值,比如普通作业答案文档限制 5MB,拍照作业限制 10MB。同时要在代码里做文件内容校验,不能只看文件名后缀。恶意用户可能把一个脚本伪装成.png上传,如果系统后续有文件预览功能,就可能产生安全风险。

7. 从“能跑”到“能上线”的工程化最佳实践

7.1 学习环境与生产环境的差异

很多系统在本地跑通后,直接照搬到生产环境,结果一上线就出问题。主要原因是本地环境和生产环境对稳定性的要求完全不同。差异点如下:

维度学习环境生产环境
API Key写环境变量即可使用密钥管理服务,定期轮换
文件存储本地磁盘对象存储,支持 CDN 和备份
数据库单机 MySQL主从、自动备份、连接池
模型调用同步请求异步任务 + 消息队列 + 重试
人工复核手动改数据库或调用接口提供完整的复核工作台
日志控制台输出日志采集、链路追踪、告警
并发限制基本没有按 API 限额设置限流和熔断
学生数据测试数据脱敏、权限隔离、审计

生产环境的核心诉求不是功能多,而是可控。AI 接口再智能,也可能抖动或超时,所以生产环境必须把“AI 调用失败”当成一个正常分支来设计,而不是异常分支。

7.2 AI 作业批改系统上线检查清单

这里整理一份可以直接用于验收的检查清单:

  • [ ] 作业文件是否做了类型白名单和大小限制?
  • [ ] 上传的文件名是否由服务端重新生成?
  • [ ] API Key 是否只存在于环境变量或密钥管理服务中?
  • [ ] 是否在配置文件里隐藏了数据库密码?
  • [ ] 模型调用是否设置了超时和重试?
  • [ ] 是否保存了模型原始输出model_output
  • [ ] 批改结果是否都有PENDINGCONFIRMEDREJECTED状态?
  • [ ] 教师提交最终反馈后,接口是否校验了权限?
  • [ ] 学情统计是否区分“AI 初评分”和“教师确认分”?
  • [ ] 是否有针对学生隐私数据的访问审计?
  • [ ] 是否对单日调用量、单次 Token 数做了成本限额?
  • [ ] 是否准备了模型接口故障时的兜底方案?

这份清单不是一次性做完就结束。每次升级模型、调整 Prompt、修改数据库结构后,都应该重新过一遍。

7.3 成本、安全与数据合规

AI 作业批改系统的成本主要来自模型调用。作业内容越长、批改次数越多,Token 消耗越大。控制成本可以采取几种策略:

  • 选择适合初评的模型,不需要所有题目都用最强模型。简单计算题可以用便宜模型,开放题再用更强模型。
  • 同一份作业不要重复批量调用。如果教师认为初评不合理,可以重新生成,但要记录次数,防止误操作造成费用暴涨。
  • 对单次请求设置max-tokens上限。作业批改不需要生成一篇论文,限制输出长度能显著降低成本。
  • 在系统中增加每日调用量统计和告警,超过阈值自动暂停批量批改。

安全方面,学生姓名、学号、作业内容都属于个人敏感信息。接口不能匿名调用,至少要加登录态校验。上传接口需要限制请求频率,避免被刷。数据库中的学生姓名和学号可以加密存储,或者在前端展示时做脱敏。

数据合规方面,AI 批改系统要明确一个原则:AI 提供的是初评建议,不是最终

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询