公司动态
基于Spring Boot与Spring AI的AI作业批改系统设计与实现
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?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/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/v1。temperature: 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 ResponseEntityLong 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只允许CORRECT、PARTIAL、WRONG或待教师确认。枚举值越明确后续代码越容易处理。4.4 解析模型返回并落库模型返回的是一个 JSON 字符串需要把它解析成 Java 对象。可以定义一个ReviewResultDTOpublic class ReviewResult { private BigDecimal score; private Integer maxScore; private String comments; private ListReviewItem 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 ResponseEntityVoid 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_PASSWORDroot \ -e MYSQL_DATABASEai_homework \ mysql:8然后启动 Spring Boot 应用export MYSQL_PASSWORDroot export OPENAI_API_KEYyour-api-key mvn spring-boot:run启动后先检查日志确认数据库连接成功和端口被正确监听。没有异常后再开始请求接口。5.2 模拟一次作业提交与批改先在数据库中插入一份作业INSERT INTO homework (title, subject, grade, content, answer_key, max_score) VALUES (一次函数练习题, 数学, 八年级, 1. 已知 y2x1当 x3 时求 y。, x3 时 y7, 100);创建一个学生答案文本answer.txt内容为y7。然后通过 curl 上传curl -X POST http://localhost:8080/api/submission \ -F homeworkId1 \ -F studentNo2025001 \ -F fileanswer.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 字符串。score和max_score不为空。review_status是PENDING表示等待教师确认。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。排查时需要关注三件事调用模型是否设置了足够长的读超时。文本批改和聊天不一样可能需要等待 60 秒以上。是否做了并发控制。如果教师批量提交 100 份作业同时发起 100 个大模型请求很容易触发供应商限流。是否做了重试。限流返回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-size和max-request-size。但不要盲目调大生产环境要根据真实作业文件大小设定合理阈值比如普通作业答案文档限制 5MB拍照作业限制 10MB。同时要在代码里做文件内容校验不能只看文件名后缀。恶意用户可能把一个脚本伪装成.png上传如果系统后续有文件预览功能就可能产生安全风险。7. 从“能跑”到“能上线”的工程化最佳实践7.1 学习环境与生产环境的差异很多系统在本地跑通后直接照搬到生产环境结果一上线就出问题。主要原因是本地环境和生产环境对稳定性的要求完全不同。差异点如下维度学习环境生产环境API Key写环境变量即可使用密钥管理服务定期轮换文件存储本地磁盘对象存储支持 CDN 和备份数据库单机 MySQL主从、自动备份、连接池模型调用同步请求异步任务 消息队列 重试人工复核手动改数据库或调用接口提供完整的复核工作台日志控制台输出日志采集、链路追踪、告警并发限制基本没有按 API 限额设置限流和熔断学生数据测试数据脱敏、权限隔离、审计生产环境的核心诉求不是功能多而是可控。AI 接口再智能也可能抖动或超时所以生产环境必须把“AI 调用失败”当成一个正常分支来设计而不是异常分支。7.2 AI 作业批改系统上线检查清单这里整理一份可以直接用于验收的检查清单[ ] 作业文件是否做了类型白名单和大小限制[ ] 上传的文件名是否由服务端重新生成[ ] API Key 是否只存在于环境变量或密钥管理服务中[ ] 是否在配置文件里隐藏了数据库密码[ ] 模型调用是否设置了超时和重试[ ] 是否保存了模型原始输出model_output[ ] 批改结果是否都有PENDING、CONFIRMED、REJECTED状态[ ] 教师提交最终反馈后接口是否校验了权限[ ] 学情统计是否区分“AI 初评分”和“教师确认分”[ ] 是否有针对学生隐私数据的访问审计[ ] 是否对单日调用量、单次 Token 数做了成本限额[ ] 是否准备了模型接口故障时的兜底方案这份清单不是一次性做完就结束。每次升级模型、调整 Prompt、修改数据库结构后都应该重新过一遍。7.3 成本、安全与数据合规AI 作业批改系统的成本主要来自模型调用。作业内容越长、批改次数越多Token 消耗越大。控制成本可以采取几种策略选择适合初评的模型不需要所有题目都用最强模型。简单计算题可以用便宜模型开放题再用更强模型。同一份作业不要重复批量调用。如果教师认为初评不合理可以重新生成但要记录次数防止误操作造成费用暴涨。对单次请求设置max-tokens上限。作业批改不需要生成一篇论文限制输出长度能显著降低成本。在系统中增加每日调用量统计和告警超过阈值自动暂停批量批改。安全方面学生姓名、学号、作业内容都属于个人敏感信息。接口不能匿名调用至少要加登录态校验。上传接口需要限制请求频率避免被刷。数据库中的学生姓名和学号可以加密存储或者在前端展示时做脱敏。数据合规方面AI 批改系统要明确一个原则AI 提供的是初评建议不是最终