前言

目前有一个传统的信息录入系统,新增业务数据存在两大痛点:一是录入模式单一,只能逐字段手动填写,效率低下;二是存量原始数据格式杂乱无章,即便支持批量粘贴至输入框,业务人员仍需耗费大量时间人工规整格式、逐条匹配对应录入项,人力成本高且易出现录入差错。

为解决上述录入难题,引入大模型能力优化全流程:直接上传杂乱原始数据交由大模型统一清洗、规整,再通过预设标准化模板输出结构化规范数据,最终自动入库存储,摆脱人工整理数据的重复工作。

本文将基于若依(RuoYi)框架接入大模型的实操方案,落地自动化智能数据录入需求。

正文

源码分享

我用夸克网盘给你分享了「ruoyi-zxks」,点击链接或复制整段内容,打开「夸克APP」即可获取。
链接:https://pan.quark.cn/s/1ae7a971ba21
gitee地址:https://gitee.com/hongwu-mayin/ruoyi-zxks

在application.yml中配置

# 项目相关配置
ruoyi:
  # 名称
  name: RuoYi
  # 版本
  version: 3.9.0
  # 版权年份
  copyrightYear: 2025
  # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
  profile: D:/ruoyi/uploadPath
  # 获取ip地址开关
  addressEnabled: false
  # 验证码类型 math 数字计算 char 字符验证
  captchaType: math
  # AI 配置(DeepSeek 等 OpenAI 兼容接口)
  ai:
    # 是否启用 AI 功能
    enabled: true
    # DeepSeek 官方接口地址
    base-url: https://api.deepseek.com
    # API Key(请替换为你的 DeepSeek API Key,建议通过环境变量/配置中心注入,勿提交到代码库)
    api-key: sk8888888
    # 模型名称(默认 deepseek-v4-flash / deepseek-v4-pro)
    model: deepseek-v4-flash
    # 请求超时(毫秒)
    timeout: 120000

Aiconfig

这段代码定义了一个名为 AiConfig 的 Java 配置类,它的主要作用是集中管理 AI 服务(本文是 DeepSeek)的相关配置参数

简单来说,它就像一个“中转站”,把写在配置文件里的信息读取出来,让程序的其他部分能够方便地使用。

  1. 读取配置 它会自动读取项目配置文件(如 application.yml)中所有以 ruoyi.ai 开头的设置。例如,当你在配置文件里设置了 API 密钥,这个类就会把它“拿”过来。
  2. 封装参数 它将读取到的零散配置项(如网址、密钥、模型名等)封装成一个完整的 Java 对象。这样,其他代码需要调用 AI 服务时,直接注入这个 AiConfig 对象就能获取所有必要信息,而不用自己去解析配置文件。
  3. 提供默认值 代码中为每个配置项都设置了默认值。这意味着即使你没有在配置文件中做任何设置,程序也能使用这些默认值(如默认的 DeepSeek API 地址和模型)正常运行,避免了因缺少配置而报错。

这个类主要管理以下几个核心参数:

字段名 作用说明 默认值
enabled 一个开关,用于快速启用或禁用整个 AI 功能。 false
baseUrl AI 服务的接口地址。这里默认指向 DeepSeek 的 API。 https://api.deepseek.com
apiKey 访问 AI 服务所需的身份验证密钥。 (空字符串)
model 指定要使用的 AI 模型名称。 deepseek-v4-flash
timeout 网络请求的超时时间,单位是毫秒。 120000 (即120秒)
package com.ruoyi.zxks.ai.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * AI 配置(DeepSeek 等 OpenAI 兼容接口)
 *
 * 配置示例(application.yml -> ruoyi.ai):
 *   ruoyi:
 *     ai:
 *       enabled: true
 *       base-url: https://api.deepseek.com
 *       api-key: sk-xxxx
 *       model: deepseek-chat
 *       timeout: 120000
 */
@Component
@ConfigurationProperties(prefix = "ruoyi.ai")
public class AiConfig
{
    /** 是否启用 AI 功能 */
    private boolean enabled = false;

    /** OpenAI 兼容接口地址(DeepSeek 为 https://api.deepseek.com) */
    private String baseUrl = "https://api.deepseek.com";

    /** API Key */
    private String apiKey = "";

    /** 模型名称(deepseek-v4-pro / deepseek-v4-flash) */
    private String model = "deepseek-v4-flash";

    /** 请求超时时间(毫秒) */
    private int timeout = 120000;

    public boolean isEnabled()
    {
        return enabled;
    }

    public void setEnabled(boolean enabled)
    {
        this.enabled = enabled;
    }

    public String getBaseUrl()
    {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl)
    {
        this.baseUrl = baseUrl;
    }

    public String getApiKey()
    {
        return apiKey;
    }

    public void setApiKey(String apiKey)
    {
        this.apiKey = apiKey;
    }

    public String getModel()
    {
        return model;
    }

    public void setModel(String model)
    {
        this.model = model;
    }

    public int getTimeout()
    {
        return timeout;
    }

    public void setTimeout(int timeout)
    {
        this.timeout = timeout;
    }
}

AiClient

这段代码定义了一个名为 AiClient 的 Java 类,它的核心作用是作为一个与 AI 模型(如 DeepSeek)进行交互的底层客户端工具。它负责封装网络请求、发送对话指令,并解析 AI 返回的复杂数据。

具体来说,它的作用可以分为以下四个方面:

  1. 初始化网络请求工具

在类初始化时(@PostConstruct 方法中),它根据你在配置类(AiConfig)中设置的超时时间,配置并创建了一个 RestTemplate 对象。同时,它还强制指定了 UTF-8 编码,以确保在处理包含中文等字符的 AI 对话时不会出现乱码。

  1. 发起 AI 对话请求 (chat 方法)

这是该类的核心功能。它模拟了标准的 OpenAI 兼容接口调用流程:

  • 安全检查:首先检查 AI 功能是否开启以及 API Key 是否配置,防止无效调用。
  • 构建请求:自动拼接 API 地址(/chat/completions),设置请求头(包含鉴权信息和 JSON 格式声明)。
  • 组装消息体:将“系统提示词(System Prompt)”和“用户提示词(User Prompt)”组装成标准的对话消息格式,并指定了使用的模型。它还强制要求 AI 以 JSON 格式输出(response_format: json_object)。
  • 发送请求:通过 RestTemplate 向 AI 服务器发送 HTTP POST 请求。
  1. 解析 AI 的响应结果

AI 返回的数据通常是一个复杂的 JSON 结构。这个类会自动提取出我们真正需要的内容:

  • 它会从返回的 JSON 树中定位到 choices 数组。
  • 提取出第一个选项(choices[0])中 messagecontent 内容,也就是 AI 实际回复的文本。
  • 如果请求失败或返回格式不对,它会抛出明确的异常提示。
  1. 提供实用的 JSON 处理工具

由于 AI 模型有时可能会“不听话”,即使你要求它输出 JSON,它也可能在前后加上多余的废话或 Markdown 代码块标记(如 ````json`)。为此,该类提供了两个静态工具方法:

  • extractJson:一个“清洗”工具。它能智能地从 AI 的回复文本中剥离掉多余的文字和代码块标记,精准提取出纯粹的 JSON 字符串。
  • parseJson:一个“转换”工具。它能将提取出来的 JSON 字符串直接转换成 Java 对象(POJO),方便你的业务代码直接使用。
package com.ruoyi.zxks.ai.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.zxks.ai.config.AiConfig;

/**
 * OpenAI 兼容的 AI 调用客户端(适配 DeepSeek)
 */
@Component
public class AiClient
{
    @Autowired
    private AiConfig aiConfig;

    private RestTemplate restTemplate;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @PostConstruct
    public void init()
    {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(aiConfig.getTimeout());
        factory.setReadTimeout(aiConfig.getTimeout());
        restTemplate = new RestTemplate(factory);
        // 确保 UTF-8 编码
        restTemplate.getMessageConverters().stream()
                .filter(c -> c instanceof StringHttpMessageConverter)
                .forEach(c -> ((StringHttpMessageConverter) c).setDefaultCharset(java.nio.charset.StandardCharsets.UTF_8));
    }

    /**
     * 发起一次对话请求,返回模型回复文本
     *
     * @param systemPrompt 系统提示词
     * @param userPrompt   用户提示词
     * @return 模型回复内容
     */
    public String chat(String systemPrompt, String userPrompt)
    {
        if (!aiConfig.isEnabled() || StringUtils.isEmpty(aiConfig.getApiKey()))
        {
            throw new RuntimeException("AI 功能未启用或未配置 API Key,请在 application.yml 的 ruoyi.ai 中配置");
        }

        String url = aiConfig.getBaseUrl().replaceAll("/+$", "") + "/chat/completions";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + aiConfig.getApiKey());

        Map<String, Object> systemMsg = new LinkedHashMap<>();
        systemMsg.put("role", "system");
        systemMsg.put("content", systemPrompt);

        Map<String, Object> userMsg = new LinkedHashMap<>();
        userMsg.put("role", "user");
        userMsg.put("content", userPrompt);

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("model", aiConfig.getModel());
        body.put("messages", Arrays.asList(systemMsg, userMsg));
        body.put("temperature", 0.3);
        Map<String, String> responseFormat = new HashMap<>();
        responseFormat.put("type", "json_object");
        body.put("response_format", responseFormat);

        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);

        ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
        if (!response.getStatusCode().is2xxSuccessful() || StringUtils.isEmpty(response.getBody()))
        {
            throw new RuntimeException("AI 接口调用失败,HTTP 状态:" + response.getStatusCode());
        }

        try
        {
            JsonNode root = OBJECT_MAPPER.readTree(response.getBody());
            JsonNode choices = root.path("choices");
            if (choices.isMissingNode() || !choices.isArray() || choices.size() == 0)
            {
                throw new RuntimeException("AI 接口返回格式异常:" + response.getBody());
            }
            return choices.get(0).path("message").path("content").asText();
        }
        catch (Exception e)
        {
            throw new RuntimeException("AI 接口返回解析失败:" + e.getMessage());
        }
    }

    /**
     * 从模型回复中提取 JSON 文本(兼容 ```json 代码块包裹的情况)
     */
    public static String extractJson(String text)
    {
        if (text == null)
        {
            return null;
        }
        text = text.trim();
        if (text.startsWith("```"))
        {
            int firstNewline = text.indexOf('\n');
            int last = text.lastIndexOf("```");
            if (firstNewline != -1 && last > firstNewline)
            {
                text = text.substring(firstNewline + 1, last).trim();
            }
        }
        int start = text.indexOf('{');
        int end = text.lastIndexOf('}');
        if (start != -1 && end != -1 && end > start)
        {
            text = text.substring(start, end + 1);
        }
        return text;
    }

    /**
     * 将 JSON 解析为指定类型
     */
    public static <T> T parseJson(String json, Class<T> clazz)
    {
        try
        {
            return OBJECT_MAPPER.readValue(json, clazz);
        }
        catch (Exception e)
        {
            throw new RuntimeException("AI 返回内容解析失败:" + e.getMessage());
        }
    }
}

controller

package com.ruoyi.zxks.ai.controller;

import java.util.List;
import java.util.Map;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.zxks.ai.domain.AiCleanImportParam;
import com.ruoyi.zxks.ai.service.IQuestionAiService;
import com.ruoyi.zxks.question.domain.ExamQuestion;

/**
 * AI 题目Controller
 */
@RestController
@RequestMapping("/question/ai")
public class QuestionAiController extends BaseController
{
    @Autowired
    private IQuestionAiService questionAiService;

    /**
     * AI 解析原始文本为题目(仅预览,不入库)
     */
    @PreAuthorize("@ss.hasPermi('question:question:add')")
    @PostMapping("/parse")
    public AjaxResult parse(@RequestBody AiCleanImportParam param)
    {
        List<ExamQuestion> list = questionAiService.parseText(param);
        return AjaxResult.success("解析完成,共 " + list.size() + " 题", list);
    }

    /**
     * 确认导入 AI 解析出的题目
     */
    @PreAuthorize("@ss.hasPermi('question:question:add')")
    @PostMapping("/import")
    public AjaxResult importQuestions(@RequestBody List<ExamQuestion> questionList)
    {
        Map<String, Object> result = questionAiService.importQuestions(questionList);
        int successCount = (int) result.get("successCount");
        int failCount = (int) result.get("failCount");
        String errorMsg = (String) result.get("errorMsg");

        String msg = "导入成功 " + successCount + " 条";
        if (failCount > 0)
        {
            msg += ",失败 " + failCount + " 条,错误信息:" + errorMsg;
            return AjaxResult.warn(msg);
        }
        return AjaxResult.success(msg);
    }
}

service

这段代码定义了 QuestionAiServiceImpl 类,它是整个 AI 功能的核心业务层。如果说前面的 AiClient 是负责“打电话”的底层通信工具,那么这个类就是负责“编写剧本、导演排练并处理最终结果”的业务导演。

它的核心作用是:利用 AI 将非结构化的原始文本(如复制粘贴的文档、网页内容)智能解析为结构化的考试题目,并将其安全地导入到数据库中。

具体来说,它实现了以下三大核心功能:

  1. 智能解析文本为题目 (parseText 方法)
    这是该类的“大脑”部分,负责与 AI 进行深度交互:
  • 构建提示词(Prompt Engineering)
    • buildSystemPrompt():定义了 AI 的角色(考试题库助手),并给出了极其严格的规则(如题型编码、选项格式、JSON 输出要求等),确保 AI 返回的数据格式是程序能直接处理的。
    • buildUserPrompt():将用户输入的原始文本与系统设置的默认值(如默认分类、默认难度、默认分值)结合,生成最终的提问。
  • 调用 AI 并清洗数据:调用 AiClient.chat() 获取 AI 回复,然后利用之前提到的 extractJsonparseJson 工具,将 AI 返回的文本精准提取并转换为 Java 对象 AiParseResult
  • 数据转换与兜底:遍历解析出的题目列表,通过 convert 方法将 AI 返回的 DTO 对象转换为数据库实体 ExamQuestion。在这里它还做了很多“兜底”处理,比如 AI 没识别出题型就用默认题型,AI 没识别出分值就默认给 1 分等。
  1. 批量导入题目入库 (importQuestions 方法)
    这是该类的“执行”部分,负责将解析好的题目安全地存入数据库:
  • 逐条校验与入库:遍历题目列表,检查题目内容和分类是否为空。如果有效,则调用现有的 examQuestionService.insertExamQuestion(q) 进行入库。
  • 容错处理:它没有采用“要么全成功,要么全失败”的批量插入,而是采用单条插入。这意味着如果第 5 题插入失败,不会影响前 4 题和第 6 题的成功入库。
  • 结果统计:最后返回一个包含成功数量、失败数量和详细错误信息的 Map,方便前端给用户展示导入结果报告。
  1. 精细化的数据转换逻辑 (convert 及辅助方法)
    为了保证 AI 返回的数据能够完美适配现有的数据库表结构,它做了大量适配工作:
  • 选项处理 (pickOption):兼容 AI 可能返回的大写 A 或小写 a,并去除多余空格。
  • 类型转换 (toBigDecimal):将 AI 返回的分值安全地转换为数据库需要的 BigDecimal 类型,防止格式错误导致崩溃。
package com.ruoyi.zxks.ai.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.zxks.ai.client.AiClient;
import com.ruoyi.zxks.ai.domain.AiCleanImportParam;
import com.ruoyi.zxks.ai.domain.AiParseResult;
import com.ruoyi.zxks.ai.domain.AiQuestionDTO;
import com.ruoyi.zxks.ai.service.IQuestionAiService;
import com.ruoyi.zxks.question.domain.ExamQuestion;
import com.ruoyi.zxks.question.service.IExamQuestionService;

/**
 * AI 题目服务实现
 */
@Service
public class QuestionAiServiceImpl implements IQuestionAiService
{
    @Autowired
    private AiClient aiClient;

    @Autowired
    private IExamQuestionService examQuestionService;

    /** 题型白名单 */
    private static final List<String> VALID_TYPES = Arrays.asList("1", "2", "3", "4");

    @Override
    public List<ExamQuestion> parseText(AiCleanImportParam param)
    {
        if (param == null || StringUtils.isEmpty(param.getRawText()))
        {
            throw new RuntimeException("原始题目文本不能为空");
        }
        if (param.getRawText().length() > 5000)
        {
            throw new RuntimeException("原始题目文本不能超过 5000 个字符");
        }
        if (StringUtils.isEmpty(param.getCategoryId()))
        {
            throw new RuntimeException("请先选择目标分类");
        }

        String content = aiClient.chat(buildSystemPrompt(), buildUserPrompt(param));
        String json = AiClient.extractJson(content);
        AiParseResult result = AiClient.parseJson(json, AiParseResult.class);

        List<ExamQuestion> questions = new ArrayList<>();
        if (result != null && result.getQuestions() != null)
        {
            for (AiQuestionDTO dto : result.getQuestions())
            {
                ExamQuestion q = convert(dto, param);
                if (q != null)
                {
                    questions.add(q);
                }
            }
        }
        return questions;
    }

    @Override
    public Map<String, Object> importQuestions(List<ExamQuestion> questionList)
    {
        Map<String, Object> result = new HashMap<>();
        int successCount = 0;
        int failCount = 0;
        StringBuilder errorMsg = new StringBuilder();

        if (questionList == null || questionList.isEmpty())
        {
            result.put("successCount", 0);
            result.put("failCount", 0);
            result.put("errorMsg", "没有可导入的题目");
            return result;
        }

        for (int i = 0; i < questionList.size(); i++)
        {
            ExamQuestion q = questionList.get(i);
            if (q == null || StringUtils.isEmpty(q.getQuestionContent()))
            {
                failCount++;
                errorMsg.append("第").append(i + 1).append("题:题目内容为空;");
                continue;
            }
            if (StringUtils.isEmpty(q.getCategoryId()))
            {
                failCount++;
                errorMsg.append("第").append(i + 1).append("题:分类为空;");
                continue;
            }
            try
            {
                // 复用现有新增逻辑:自动生成ID、创建人信息、去除选项前缀
                examQuestionService.insertExamQuestion(q);
                successCount++;
            }
            catch (Exception e)
            {
                failCount++;
                errorMsg.append("第").append(i + 1).append("题:插入失败(").append(e.getMessage()).append(");");
            }
        }

        result.put("successCount", successCount);
        result.put("failCount", failCount);
        result.put("errorMsg", errorMsg.toString());
        return result;
    }

    /**
     * 将 AI 单题 DTO 转换为 ExamQuestion
     */
    private ExamQuestion convert(AiQuestionDTO dto, AiCleanImportParam param)
    {
        if (dto == null || StringUtils.isEmpty(dto.getQuestionContent()))
        {
            return null;
        }
        ExamQuestion q = new ExamQuestion();
        q.setCategoryId(param.getCategoryId());
        q.setQuestionContent(dto.getQuestionContent().trim());
        q.setDelFlag("0");

        // 题型:优先使用 AI 识别,其次使用传入默认值,最后兜底单选
        String type = dto.getQuestionType();
        if (!VALID_TYPES.contains(type))
        {
            type = param.getQuestionType();
        }
        if (!VALID_TYPES.contains(type))
        {
            type = "1";
        }
        q.setQuestionType(type);

        // 选项
        if (dto.getOptions() != null)
        {
            q.setOptionA(pickOption(dto.getOptions(), "A"));
            q.setOptionB(pickOption(dto.getOptions(), "B"));
            q.setOptionC(pickOption(dto.getOptions(), "C"));
            q.setOptionD(pickOption(dto.getOptions(), "D"));
        }

        q.setCorrectAnswer(StringUtils.isEmpty(dto.getCorrectAnswer()) ? null : dto.getCorrectAnswer().trim());
        q.setAnalysis(StringUtils.isEmpty(dto.getAnalysis()) ? null : dto.getAnalysis().trim());

        // 难度
        String difficulty = dto.getDifficulty();
        if (StringUtils.isEmpty(difficulty) || (!"1".equals(difficulty) && !"2".equals(difficulty) && !"3".equals(difficulty)))
        {
            difficulty = param.getDifficulty();
        }
        if (StringUtils.isEmpty(difficulty))
        {
            difficulty = "2";
        }
        q.setDifficulty(difficulty);

        // 分值:用户设置的默认分值优先(覆盖 AI 识别值),未设置时才回退到 AI 识别值,最后兜底 1 分
        BigDecimal score = param.getScore();
        if (score == null)
        {
            score = toBigDecimal(dto.getScore());
        }
        if (score == null)
        {
            score = BigDecimal.ONE;
        }
        q.setScore(score);

        return q;
    }

    private String pickOption(Map<String, String> options, String key)
    {
        String val = options.get(key);
        if (StringUtils.isEmpty(val))
        {
            val = options.get(key.toLowerCase());
        }
        return StringUtils.isEmpty(val) ? null : val.trim();
    }

    private BigDecimal toBigDecimal(Object obj)
    {
        if (obj == null)
        {
            return null;
        }
        try
        {
            return new BigDecimal(obj.toString());
        }
        catch (Exception e)
        {
            return null;
        }
    }

    private String buildSystemPrompt()
    {
        return "你是一个考试题库助手。用户会提供一段包含若干题目的原始文本(可能来自教材、文档或网页)。"
                + "请从中提取出每一道题目,并转换为结构化 JSON。\n"
                + "题型编码:1=单选,2=多选,3=判断,4=简答。\n"
                + "规则:\n"
                + "1. 单选题 correctAnswer 为单个选项字母(如 \"A\");多选题 correctAnswer 为逗号分隔的字母(如 \"A,B\");"
                + "判断题 correctAnswer 为 \"正确\" 或 \"错误\",且 options 为空对象;简答题 correctAnswer 为答案要点文本,options 为空对象。\n"
                + "2. 选项统一使用键 A/B/C/D,去掉选项前的 \"A.\" \"B、\" 等前缀,只保留内容本身。\n"
                + "3. 若题目没有明显解析,analysis 填空字符串。\n"
                + "4. 只输出 JSON,不要包含任何解释性文字或 markdown 代码块标记。\n"
                + "输出格式示例:\n"
                + "{\"questions\":[{\"questionContent\":\"...\",\"questionType\":\"1\","
                + "\"options\":{\"A\":\"...\",\"B\":\"...\",\"C\":\"...\",\"D\":\"...\"},"
                + "\"correctAnswer\":\"A\",\"analysis\":\"...\",\"difficulty\":\"2\",\"score\":5}]}";
    }

    private String buildUserPrompt(AiCleanImportParam param)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("请将以下文本解析为题目:\n\n").append(param.getRawText()).append("\n\n");
        sb.append("补充说明:\n");
        sb.append("- 所有题目归入已指定的分类,无需输出分类字段。\n");
        if (StringUtils.isNotEmpty(param.getQuestionType()))
        {
            sb.append("- 若题目本身未明确题型,默认题型为 ").append(param.getQuestionType()).append("。\n");
        }
        if (StringUtils.isNotEmpty(param.getDifficulty()))
        {
            sb.append("- 若题目未标注难度,默认难度为 ").append(param.getDifficulty()).append("。\n");
        }
        if (param.getScore() != null)
        {
            sb.append("- 若题目未标注分值,默认分值为 ").append(param.getScore()).append("。\n");
        }
        sb.append("请尽量依据题目内容判断题型,仅在无法判断时使用上述默认值。");
        return sb.toString();
    }
}

效果图

输入:

在这里插入图片描述

查看清洗出的题目效果:

在这里插入图片描述

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐