u+平台

263 阅读3分钟

教育平台自动化答题系统开发日记:从AI交互到HTTP请求的全流程实践

一、背景与目标

近期在开发一个教育平台的自动化答题工具,核心需求是根据不同题型(单选/多选/判断/填空)自动获取AI答案并提交。涉及技术点包括:

  • 火山引擎大模型交互(ArkService)
  • HTTP请求模拟(Java HttpClient)
  • JSON解析与数据处理(Gson)
  • 题型差异化处理逻辑

二、开发过程与关键技术

1. AI交互核心:精准控制答案格式

痛点:

AI返回常包含多余解释或格式错误(如填空题带引号),需严格约束输出。

解决方案:
  • 系统提示强约束:针对不同题型设置专属指令
    switch (qsnType) {
        case 1: // 单选题
            content = "只返回单个选项字母(如:A),无需任何解释";
            break;
        case 6: // 填空题
            content = "直接返回答案内容,禁止添加任何引号、括号或解释性文字";
    }
    
  • 答案清洗层:统一处理多余字符
    private static String processAnswer(String content, int qsnType) {
        if (qsnType == 6) {
            return content.trim().replaceAll("^[\"“”']|['\"“”]$", ""); // 去除首尾引号
        }
        return content;
    }
    

2. HTTP请求陷阱:受限头引发的异常

错误复现:

IllegalArgumentException: restricted header name: "Connection"
Java HttpClient禁止手动设置部分请求头(如Connection、Keep-Alive)。

修复方案:
  • 请求头白名单机制:过滤受限头
    private boolean isRestrictedHeader(String name) {
        String lower = name.toLowerCase();
        return Set.of("connection", "keep-alive", "transfer-encoding").contains(lower);
    }
    
  • 合规头构建:仅保留合法字段(User-Agent、X-Access-Token、Referer等),避免触发客户端限制。

3. 题型差异化处理:从答案提取到提交

单选题/多选题:
  • 正则过滤非字母字符并转大写
    contentStr.replaceAll("[^A-Za-z]", "").toUpperCase();
    
判断题:
  • 映射“正确”/“错误”到布尔值
    userAnswer = aiResult.equalsIgnoreCase("正确") ? "true" : "false";
    
填空题:
  • 保留原始内容并包装HTML标签(平台要求)
    userAnswer = "<p>" + aiResult + "</p>";
    

三、代码架构解析

1. 主流程逻辑(伪代码)

for (题目 : 题目列表) {
    if (已有答案) continue; // 跳过已答题目
    根据qsnType生成AI请求 → 获取rawAnswer → 清洗处理 → 组装userAnswer;
    if (答案有效) {
        构造Http请求头(含X-Access-Token) → 发送POST请求;
        打印提交响应;
    }
}
if (AUTO_SUBMIT) 提交整份作业; // 全局开关控制

2. AI交互核心模块

private static String getAnswerFromAi(...) {
    List<ChatMessage> messages = new ArrayList<>();
    messages.add(系统提示);
    messages.add(用户问题+选项);
    
    ChatCompletionRequest request = ChatCompletionRequest.builder()
        .model("deepseek-r1-250120")
        .messages(messages)
        .build();
    
    return arkService.createChatCompletion(request)
        .getChoices()
        .stream()
        .map(choice -> processAnswer(choice.getMessage().getContent(), qsnType))
        .findFirst()
        .orElse("");
}

3. 鲁棒性设计

  • 空值保护:所有JSON解析处添加has("字段")检查
  • 异常重试:HTTP请求添加重试机制(示例未展示,建议实现)
  • 日志输出:关键节点打印AI答案和提交响应,便于调试

四、踩坑记录与最佳实践

  1. JSON解析陷阱

    • 问题:字段缺失导致JsonSyntaxException
    • 方案:使用has()方法预检查,如if (detailData.has("userAnswer"))
  2. AI响应不可靠性

    • 方案:添加正则兜底处理,如填空题强制去除首尾引号,多选题确保字母大写
  3. HTTP请求头匹配

    • 必须严格与浏览器抓包一致(User-Agent、Referer等),建议使用工具(如Charles)获取真实请求头

五、优化方向

  1. 支持更多题型:扩展解答题、计算题处理逻辑
  2. 性能优化:批量提交题目,减少AI交互次数
  3. 错误处理增强:记录失败题目ID,支持断点续传
  4. 配置化:将题型映射、AI模型参数等移至配置文件

六、总结

本次开发深度实践了“AI交互+网络请求+业务逻辑”的三层架构,核心挑战在于格式控制兼容性处理。通过系统提示强约束、答案清洗层、合规请求头设计,有效解决了自动化流程中的关键问题。后续可进一步结合题库缓存、代理池等技术提升稳定性,适合教育类自动化场景复用。

github链接github.com/journs/U-pl…

#掘金日新计划 #Java开发 #教育科技 #自动化工具 #大模型应用