--- title: "01-平台智能化" created: 2025-12-02 tags: - 项目 aliases: - 平台智能化 --- # 平台智能化 ## 本节重点 **平台智能化** - 接入 AI 模块 - - 智谱 AI 介绍 - 使用智谱 AI SDK - 封装 AI 模块 - AI 生成题目 - - 需求分析 - 方案设计(实现原理),包括使用智谱页面调试 Prompt - 后端开发 - 前端开发 - AI 智能评分 - - 需求分析 - 方案设计(实现原理),包括使用智谱页面调试 Prompt - 后端开发 - 前端开发 - 扩展知识 - - Spring AI - 智谱 AI + Spring AI 整合应用 ## 一、接入 AI 模块 在智谱 AI 开放平台页面 进行题目生成的演示,然后后端 sdk 引入 ### 1、智谱 AI 介绍 智谱 AI 开放平台: 大模型介绍 AI 的应用场景 知识库管理 创建应用:应用 = 预定义了一些规则的大模型 在线体验:可用来测试不同大模型和参数的效果,支持 AI 绘画 ![[BWPSmrEYtmbf8Pvr-ed1e5fbe.webp]] ### 2、使用智谱 AI SDK 需要阅读官方文档 使用指南: 可以看到很多能力,比如知识库、网络搜索等 接口文档: 有 3 种调用方式,SDK、HTTP 和第三方框架。 比较推荐 SDK,方便,不用自己构造 HTTP 请求并构造响应对象。 跟着官方文档去学习使用即可: #### Java 中使用 SDK 1)引入 maven: ```xml cn.bigmodel.openapi oapi-java-sdk release-V4-2.0.2 ``` 2)创建单元测试来跑通 Demo 注意配置 apiKey,在智谱开放平台查看: ```java package com.yupi.yudada; import com.zhipu.oapi.ClientV4; import com.zhipu.oapi.Constants; import com.zhipu.oapi.service.v4.model.ChatCompletionRequest; import com.zhipu.oapi.service.v4.model.ChatMessage; import com.zhipu.oapi.service.v4.model.ChatMessageRole; import com.zhipu.oapi.service.v4.model.ModelApiResponse; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.List; @SpringBootTest public class ZhiPuAiTest { @Test public void test() { String apiKey = ""; // 创建客户端 ClientV4 client = new ClientV4.Builder(apiKey).build(); // 构造请求 List messages = new ArrayList<>(); ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), "作为一名营销专家,请为智谱开放平台创作一个吸引人的slogan"); messages.add(chatMessage); String requestId = String.valueOf(System.currentTimeMillis()); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model(Constants.ModelChatGLM4) .stream(Boolean.FALSE) .invokeMethod(Constants.invokeMethod) .messages(messages) .requestId(requestId) .build(); // 调用 ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest); System.out.println("model output:" + invokeModelApiResp.getMsg()); } } ``` 每个参数的含义可以参考官方文档: 3)Debug 程序,如果无法 Debug,开启如下配置 ![[UYDNioSbamwr973n-27cba69b.webp]] 查看到 AI 返回的结果如图: ![[JTHBGA5JxLz3gGXN-87cdb924.webp]] #### 其他用法 异步调用:相当于提交任务,可以之后查询任务状态并获取结果。 SSE 调用:流式、实时地获取到结果直到结束,可以优化用户体验。 ### 3、封装 AI 模块 目的是更快速灵活地调用 AI 的能力,各项目都可以复用。 1)在 application.yml 中定义 AI 配置 ```yaml ai: apiKey: xxx ``` 2)定义 AI 配置类,加载配置文件,初始化调用智谱的 Client 并将其注册为 bean。 ```java @Configuration @ConfigurationProperties(prefix = "ai") @Data public class AiConfig { private String apiKey; @Bean public ClientV4 getClientV4() { return new ClientV4.Builder(apiKey).build(); } } ``` 可以自己定制客户端的一些配置,后续 service 即可注入使用,不用再重复创建 Client 了。 ![[jAUhrSgYifFKt1qd-0a495761.webp]] 3)智谱 SDK 提供的客户端已经很方便了,但我们仍然可以根据实际业务需求,封装本项目内通用的 AI 请求构建模块。 比如将复杂的消息、请求构建、从返回值中获取结果的过程进行封装。 一般建议先封装通用的方法,然后提供不同参数默认值的简化调用方法,层层简化。 最通用的方法,可自定义消息、是否流式、随机数: ```java public String doRequest(List messages, Boolean stream, Float temperature) { // 构造请求 ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model(Constants.ModelChatGLM4) .stream(stream) .invokeMethod(Constants.invokeMethod) .temperature(temperature) .messages(messages) .build(); ModelApiResponse invokeModelApiResp = clientV4.invokeModelApi(chatCompletionRequest); ChatMessage result = invokeModelApiResp.getData().getChoices().get(0).getMessage(); return result.getContent().toString(); } ``` 通用请求,简化了消息传递: ```java public String doRequest(String systemMessage, String userMessage, Boolean stream, Float temperature) { // 构造请求 List messages = new ArrayList<>(); ChatMessage systemChatMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), systemMessage); ChatMessage userChatMessage = new ChatMessage(ChatMessageRole.USER.value(), userMessage); messages.add(systemChatMessage); messages.add(userChatMessage); return doRequest(messages, stream, temperature); } ``` 通用同步请求: ```java public String doSyncRequest(String systemMessage, String userMessage, Float temperature) { return doRequest(systemMessage, userMessage, Boolean.FALSE, temperature); } ``` 预置两种不同稳定性的方法,以满足我们之后的需求。 - AI 生成题目不应该稳定(需提高随机性),让思维发散 - AI 评分需要稳定(降低随机性)避免相同的答案每次得到不一样的分析结果 ```java // 较稳定的随机数 private static final float STABLE_TEMPERATURE = 0.05f; // 不稳定的随机数 private static final float UNSTABLE_TEMPERATURE = 0.99f; /** * 同步调用(答案较稳定) * * @param systemMessage * @param userMessage * @return */ public String doSyncStableRequest(String systemMessage, String userMessage) { return doSyncRequest(systemMessage, userMessage, STABLE_TEMPERATURE); } /** * 同步调用(答案较随机) * * @param systemMessage * @param userMessage * @return */ public String doSyncUnstableRequest(String systemMessage, String userMessage) { return doSyncRequest(systemMessage, userMessage, UNSTABLE_TEMPERATURE); } ``` 这样做之后,不仅满足了本项目的需求,其他项目也可以复用部分方法。 --- 整个项目可以引入 AI 的地方有很多,核心使用场景是 “AI 生成题目” 和 “AI 智能评分”。 ## 二、AI 生成题目 ### 需求分析 原本创建题目需要人工一个个添加标题和选项,比较麻烦。 可以使用 AI,根据已经填写的应用信息,自动生成题目,然后再由人工进行编辑确认,提高创建题目的效率。 ### 方案设计 AI 生成内容的核心是编写 Prompt,好的、精准的 Prompt 才能帮助我们得到预期的结果。 首先明确我们能提供或者需要输入给 AI 的参数,然后构建 Prompt 并输入给 AI,让 AI 生成题目并处理成我们需要的格式。 #### 1、明确输入参数 明确需要提供给 AI 的参数列表: 1. 应用信息,包括应用名称、描述、类别(得分 / 测评) 2. 题目信息,包括要生成的题目数、每题选项数 当然,还可以有其他信息,比如限定单个选项的得分范围、选项对应的属性集合等。 不过因为 AI 给出的结果存在随机性,建议大家先一切从简,只提供核心参数,保证 AI 输出的结果尽可能地稳定。 #### 2、明确返回结果 需要 JSON 格式的题目列表,比如: ```json [ { "options": [ { "result": "I", "value": "独自工作", "key": "A" }, { "result": "E", "value": "与他人合作", "key": "B" } ], "title": "你通常更喜欢" } ] ``` #### 3、编写和调试 Prompt 推荐阅读智谱 AI 官方提供的 Prompt 工程指南: ![[6dTw42G0oDVaZBGD-9ae54021.webp]] 对于精准度要求不高的生成需求,可以先通过智谱 AI 体验中心进行简单调试。但如果要追求更准确的结果,最好使用 SDK 调用来调试,因为 web 端和通过 SDK 调用的效果可能有细微差别。 遵循 Prompt 工程指南中的技巧,编写出系统 Prompt 和用户 Prompt。 系统 Prompt 如下: ```text 你是一位严谨的出题专家,我会给你如下信息: ``` 应用名称, 【【【应用描述】】】, 应用类别, 要生成的题目数, 每个题目的选项数 ```text 请你根据上述信息,按照以下步骤来出题: 1. 要求:题目和选项尽可能地短,题目不要包含序号,每题的选项数以我提供的为主,题目不能重复 2. 严格按照下面的 json 格式输出题目和选项 ``` [{"options":[{"value":"选项内容","key":"A"},{"value":"","key":"B"}],"title":"题目标题"}] ```text title 是题目,options 是选项,每个选项的 key 按照英文字母序(比如 A、B、C、D)以此类推,value 是选项内容 3. 检查题目是否包含序号,若包含序号则去除序号 4. 返回的题目列表格式必须为 JSON 数组 ``` 用户 Prompt 按照顺序提供信息即可,示例 Prompt 如下。 测评类应用: ```text MBTI 性格测试, 【【【快来测测你的 MBTI 性格】】】, 测评类, 10, 3 ``` 得分类应用: ```text 小学数学测验, 【【【小学三年级的数学题】】】, 得分类, 10, 3 ``` 用到的技巧: 1. 定义 System Prompt 2. 让 GLM 进行角色扮演 3. 使用分隔符标示不同的输入部分 4. 少样本学习 5. 指定输出长度的示例 6. 将复杂任务分解为简单的子任务 7. 指定固定的输出格式 8. 通过按顺序输入参数来节约空间。 9. 对于描述这种多行内容,可以通过特殊字符括起来,防止用户的输入干扰生成结果。 先利用界面进行初步调试,分别调试测评类和得分类应用: ![[fNHNZa3JpzFVAyCl-c661c5e6.webp]] ![[WNkTiYDIvaaQ1hiG-2d49faa0.webp]] 然后编写单元测试来进一步调试,得到的结果可能会包含额外的开头和结尾字符串。 ![[8hQH7FRCtuIxwXMD-301b8973.webp]] 对应的解决方案是,利用字符串查找,找到开头的 '[' 和结尾的 ']',进行截取。 最后,将 JSON 字符串转换为题目对象,返回给前端即可。 ![[lu8aT9Z8uKZtATEE-c6934e3a.webp]] #### 4、注意事项 任何大模型都有单次提问 token 限制,注意题目和选项数不能太多,太多的话可以分批生成。 经过尝试,建议最多每 20 道题生成调用一次 AI 接口。 Token:是模型用来表示自然语言文本的基本单位,可以直观的理解为“字”或“词”;通常1个中文词语、1个英文单词、1个数字或1个符号计为 1 个token。 ChatGLM 的最大单次调用的 token 量和对应的汉字数是多少?大概单次消耗多少 token? 一般情况下 ChatGLM 模型中 token 和字数的换算比例约为 1:1.6,但因为不同模型的分词不同,所以换算比例也存在差异,每一次实际处理 token 数量以模型返回为准,可以从返回结果的 usage 中查看。 经过测试,生成 10 道题目导致需要消耗 1700 左右的 token,10 道题的智能评分大致 600 左右的 token。 上下文最大 tokens 量是 128k(不同的模型不一样,要以官方文档为准),输出 token 数量还受到请求参数 max\_tokens 的限制,默认1024,最大 8192,不建议超过 4096,超 4096 会显著降低接口响应速度。 ### 后端开发 按照上述方案,进行编码实现。 本节先使用同步的方式调用 AI,后续会进行优化。 1)AI 生成题目请求类: ```java @Data public class AiGenerateQuestionRequest implements Serializable { /** * id */ private Long appId; /** * 题目数 */ int questionNumber = 10; /** * 选项数 */ int optionNumber = 2; private static final long serialVersionUID = 1L; } ``` 2)定义模板常量和构造用户模板的方法: ```java private static final String GENERATE_QUESTION_SYSTEM_MESSAGE = "你是一位严谨的出题专家,我会给你如下信息:\n" + "```\n" + "应用名称,\n" + "【【【应用描述】】】,\n" + "应用类别,\n" + "要生成的题目数,\n" + "每个题目的选项数\n" + "```\n" + "\n" + "请你根据上述信息,按照以下步骤来出题:\n" + "1. 要求:题目和选项尽可能地短,题目不要包含序号,每题的选项数以我提供的为主,题目不能重复\n" + "2. 严格按照下面的 json 格式输出题目和选项\n" + "```\n" + "[{\"options\":[{\"value\":\"选项内容\",\"key\":\"A\"},{\"value\":\"\",\"key\":\"B\"}],\"title\":\"题目标题\"}]\n" + "```\n" + "title 是题目,options 是选项,每个选项的 key 按照英文字母序(比如 A、B、C、D)以此类推,value 是选项内容\n" + "3. 检查题目是否包含序号,若包含序号则去除序号\n" + "4. 返回的题目列表格式必须为 JSON 数组"; private String getGenerateQuestionUserMessage(App app, int questionNumber, int optionNumber) { StringBuilder userMessage = new StringBuilder(); userMessage.append(app.getAppName()).append("\n"); userMessage.append(app.getAppDesc()).append("\n"); userMessage.append(AppTypeEnum.getEnumByValue(app.getAppType()).getText() + "类").append("\n"); userMessage.append(questionNumber).append("\n"); userMessage.append(optionNumber); return userMessage.toString(); } ``` 3)AI 生成接口: ```java @PostMapping("/ai_generate") public BaseResponse> aiGenerateQuestion(@RequestBody AiGenerateQuestionRequest aiGenerateQuestionRequest) { ThrowUtils.throwIf(aiGenerateQuestionRequest == null, ErrorCode.PARAMS_ERROR); // 获取参数 Long appId = aiGenerateQuestionRequest.getAppId(); int questionNumber = aiGenerateQuestionRequest.getQuestionNumber(); int optionNumber = aiGenerateQuestionRequest.getOptionNumber(); App app = appService.getById(appId); ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR); // 封装 Prompt String userMessage = getGenerateQuestionUserMessage(app, questionNumber, optionNumber); // AI 生成 String result = aiManager.doSyncUnstableRequest(GENERATE_QUESTION_SYSTEM_MESSAGE, userMessage); // 结果处理 int start = result.indexOf("["); int end = result.lastIndexOf("]"); String json = result.substring(start, end + 1); List questionContentDTOList = JSONUtil.toList(json, QuestionContentDTO.class); return ResultUtils.success(questionContentDTOList); } ``` ### 前端开发 效果如图: ![[XpRL8m7lfx8adx00-181f18b4.webp]] #### 抽屉组件 允许用户填写生成参数并执行,生成成功后回调题目页面(父组件)的函数,插入题目。 代码如下: ```typescript ``` #### 引入组件 设置题目页面引入抽屉组件: ```html 底部添加题目 ``` 编写 AI 生成题目成功的处理,插入题目: ```javascript const onAiGenerateSuccess = (result: API.QuestionContentDTO[]) => { questionContent.value = [...questionContent.value, ...result]; message.success(`AI 生成题目成功,已新增 ${result.length} 道题目`); }; ``` ### 验证测试 1)AddAppPage 创建应用成功后无法正确跳转到详情页 Bug 因为 id 的默认值为空字符串导致,需将 "??" 改为 "||",代码如下: ```java if (res.data.code === 0) { message.success("操作成功,即将跳转到应用详情页"); setTimeout(() => { router.push(`/app/detail/${props.id || res.data.data}`); }, 3000); } ``` 2)AI 生成中断,需要调整请求配置中的超时时间 ```javascript const myAxios = axios.create({ baseURL: "http://localhost:8101", timeout: 60000, withCredentials: true, }); ``` 3)实际测试的生成结果有点太飘(随机)了,如图: ![[PZrB7Ny4cnWHbeVe-8075373c.webp]] 还是将随机性调整为默认值: ```java // AI 生成 String result = aiManager.doSyncRequest(GENERATE_QUESTION_SYSTEM_MESSAGE, userMessage, null); ``` 调整参数后,生成的结果正常多了: ![[pRNw2OMQ1eXwTK9L-9ac5431e.webp]] ### 扩展思路 1)可以将历史生成的题目标题关联到上下文中,让 AI 排除掉重复题目的生成。建议做一个通用的支持上下文自动关联并调用的组件。 示例代码仅供参考: ```java private String AICreateTitle(int number) { String appAiSysMessageConfig = "系统提示词" String appAiUserMessageConfig = "用户提示词"; //经过测试,需要每 20 道题一组,ChatGLM 拒绝一次性输出大量题目 List assistantChatMessageList = new ArrayList<>(); while (number >= 10) { invokeAiLoop(number, appAiSysMessageConfig, appAiUserMessageConfig, assistantChatMessageList); number = number - 10; } if (number > 0) { invokeAiLoop(number, appAiSysMessageConfig, appAiUserMessageConfig, assistantChatMessageList); } //将结果合并成一个 List 返回 JSONArray result = new JSONArray(); for (ChatMessage message : assistantChatMessageList) { JSONArray jsonArray = JSONArray.parseArray(String.valueOf(message.getContent())); result.addAll(jsonArray); } return JSON.toJSONString(result); } private void invokeAiLoop(int number, String appAiSysMessageConfig, String appAiUserMessageConfig, List assistantChatMessages) { //每次需要重建request,因为一次调用后sokcet通道已经被关闭,复用老的 request 会复用老链接会报错 ChatCompletionRequest chatCompletionRequest = ChatGLMUtil.buildSyncUnStableRequest(appAiSysMessageConfig, String.format(appAiUserMessageConfig, Math.min(number, 10), 2)); chatCompletionRequest.getMessages().addAll(assistantChatMessages); ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest); String s = invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString(); int start = s.indexOf("["); int end = s.lastIndexOf("]"); String content = s.substring(start, end + 1); //保存上下文 assistantChatMessages.add(new ChatMessage(ChatMessageRole.ASSISTANT.value(), content)); } ``` 2)对于测评类应用,给定属性集,生成题目选项对应的属性。 3)对于得分类应用,给定得分范围,生成题目选项对应的得分。 4)思考如何进一步优化 Prompt,比如通过简化 JSON key 的长度来节约 token 数。 ## 三、AI 智能评分 ### 需求分析 原本题目评分需要让应用创建者自己创建评分结果,并且给题目选项设置得分和对应的属性,比较麻烦。 可以使用 AI,根据应用信息、题目和用户的答案进行评分,直接返回评分结果。 这种评分策略更适用于测评类应用,提高创建应用效率的同时,给结果更多的可能性。 所以下面我们主要实现测评类应用的 AI 评分策略,暂时不关注得分类应用的 AI 评分结果, 也可以在前端做一些控制,如果是得分类应用,不支持选择 AI 评分策略等。 ### 方案设计 #### 1、明确输入参数 明确需要提供给 AI 的参数列表: 1. 应用信息,包括应用名称、描述 2. 题目信息 3. 用户答案 但是需要注意,题目数量可能会很多,如果将完整的题目结构(包括选项列表)输入给 AI,可能会超出最大 token 限制,所以可以进行优化。**只存储用户答案对应的选项。** 示例结构如下: ```json { "appName": "MBTI 性格测试", "appDesc": "测试你的 MBTI 性格", "question": [ { "title": "你喜欢和人交流", "answer": "喜欢" } ] } ``` #### 2、明确返回结果 需要 JSON 格式的评分结果对象,比如: ```json { "resultName": "INTJ", "resultDesc": "INTJ被称为'策略家'或'建筑师',是一个高度独立和具有战略思考能力的性格类型" } ``` #### 3、编写和调试 Prompt 遵循 Prompt 工程指南中的技巧,编写出系统 Prompt 和用户 Prompt。 系统 Prompt 如下: ```text 你是一位严谨的判题专家,我会给你如下信息: ``` 应用名称, 【【【应用描述】】】, 题目和用户回答的列表:格式为 [{"title": "题目","answer": "用户回答"}] ```text 请你根据上述信息,按照以下步骤来对用户进行评价: 1. 要求:需要给出一个明确的评价结果,包括评价名称(尽量简短)和评价描述(尽量详细,大于 200 字) 2. 严格按照下面的 json 格式输出评价名称和评价描述 ``` {"resultName": "评价名称", "resultDesc": "评价描述"} ```text 3. 返回格式必须为 JSON 对象 ``` 用户 Prompt 按照顺序提供信息即可,示例 Prompt 如下。 测评类应用: ```text MBTI 性格测试, 【【【快来测测你的 MBTI 性格】】】, [{"title": "你通常更喜欢","answer": "独自工作"}, {"title": "当安排活动时","answer": "更愿意随机应变"}] ``` 用到的技巧: 1. 定义 System Prompt 2. 让 GLM 进行角色扮演 3. 使用分隔符标示不同的输入部分 4. 少样本学习 5. 指定输出长度的示例 6. 将复杂任务分解为简单的子任务 7. 指定固定的输出格式 8. 通过按顺序输入参数来节约空间。 9. 对于描述这种多行内容,可以通过特殊字符括起来,防止用户的输入干扰生成结果。 利用界面进行初步调试,可以尝试修改随机性: ![[GLGzfK8XpeX23rLn-3efec567.webp]] 然后可以通过编写单元测试来调试。 得到结果后,仍然需要利用字符串查找,找到开头的 '{' 和结尾的 '}',截取到实际内容。 ### 后端开发 1)编写题目答案封装类: ```java public class QuestionAnswerDTO { /** * 题目 */ private String title; /** * 用户答案 */ private String userAnswer; } ``` 2)编写 AI 测评类应用评分策略类,需要指定对应的注解: ```java @ScoringStrategyConfig(appType = 1, scoringStrategy = 1) ``` 定义模板常量和构造用户模板的方法: ```java private static final String AI_TEST_SCORING_SYSTEM_MESSAGE = "你是一位严谨的判题专家,我会给你如下信息:\n" + "```\n" + "应用名称,\n" + "【【【应用描述】】】,\n" + "题目和用户回答的列表:格式为 [{\"title\": \"题目\",\"answer\": \"用户回答\"}]\n" + "```\n" + "\n" + "请你根据上述信息,按照以下步骤来对用户进行评价:\n" + "1. 要求:需要给出一个明确的评价结果,包括评价名称(尽量简短)和评价描述(尽量详细,大于 200 字)\n" + "2. 严格按照下面的 json 格式输出评价名称和评价描述\n" + "```\n" + "{\"resultName\": \"评价名称\", \"resultDesc\": \"评价描述\"}\n" + "```\n" + "3. 返回格式必须为 JSON 对象"; private String getAiTestScoringUserMessage(App app, List questionContentDTOList, List choices) { StringBuilder userMessage = new StringBuilder(); userMessage.append(app.getAppName()).append("\n"); userMessage.append(app.getAppDesc()).append("\n"); List questionAnswerDTOList = new ArrayList<>(); for (int i = 0; i < questionContentDTOList.size(); i++) { QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO(); questionAnswerDTO.setTitle(questionContentDTOList.get(i).getTitle()); questionAnswerDTO.setUserAnswer(choices.get(i)); questionAnswerDTOList.add(questionAnswerDTO); } userMessage.append(JSONUtil.toJsonStr(questionAnswerDTOList)); return userMessage.toString(); } ``` 实现应用评分策略: ```java @Override public UserAnswer doScore(List choices, App app) throws Exception { Long appId = app.getId(); // 1. 根据 id 查询到题目 Question question = questionService.getOne( Wrappers.lambdaQuery(Question.class).eq(Question::getAppId, appId) ); QuestionVO questionVO = QuestionVO.objToVo(question); List questionContent = questionVO.getQuestionContent(); // 2. 调用 AI 获取结果 // 封装 Prompt String userMessage = getAiTestScoringUserMessage(app, questionContent, choices); // AI 生成 String result = aiManager.doSyncStableRequest(AI_TEST_SCORING_SYSTEM_MESSAGE, userMessage); // 结果处理 int start = result.indexOf("{"); int end = result.lastIndexOf("}"); String json = result.substring(start, end + 1); // 3. 构造返回值,填充答案对象的属性 UserAnswer userAnswer = JSONUtil.toBean(json, UserAnswer.class); userAnswer.setAppId(appId); userAnswer.setAppType(app.getAppType()); userAnswer.setScoringStrategy(app.getScoringStrategy()); userAnswer.setChoices(JSONUtil.toJsonStr(choices)); return userAnswer; } ``` ### 前端开发 前端不需要开发新的页面,给做题页面的“查看结果”按钮补充一个提交等待的 loading 效果即可。 ### 验证测试 效果如图: ![[LSMqWk4SXtISU5Qv-bbca0887.webp]] 可以多次测试,调试 Prompt 和模型参数,以便获得更好的结果。 ### 扩展思路 1)实现得分类应用的 AI 评分,可以给 AI 多传递每道题目正确的得分参数。 2)支持用户额外定义结果集,将 AI 生成的结果限定在一个范围内,更精确。 ## 四、扩展知识 ### Spring AI 简化 AI 应用程序开发的工具库。 官方文档地址: 主要功能如下: ![[q8HcuBssj7DSZT0E-ea09d6b1.webp]] 简单来说就是适配了市面上主流的 AI 模型,提供统一接口便于我们的开发。 注意,整个 Spring AI 是基于 jdk 17 构建的。 ![[X0zmLa9Ncv7lepH0-147c7756.webp]] 默认支持国外主流的 AI 大模型,也支持自己定制。 ### 智谱 AI + Spring AI 整合应用 Spring AI 官方也整合了智谱 AI: 现在有两个版本可以选择: ![[QIe6jWNWMcSzqV2b-dfa810c0.webp]] 引入依赖: ```xml io.springboot.ai spring-ai-zhipu-ai-spring-boot-starter 1.0.3 ``` 使用起来仅需在配置文件中加下对应模型的配置: ```yaml spring: ai: zhipuai: api-key: xxxx chat: enabled: true options: model: glm-4 ``` 然后引入对应模型的 client,即可直接使用: ```java @Resource private ZhipuAiChatClient chatClient; //简单调用 chatClient.call("给我讲一个笑话"); //也可以配置一些参数 ChatResponse response = chatClient.call( new Prompt( "帮我随机生成五个名字", ZhipuAiChatOptions.builder() .withModel("glm-4") .withTemperature(0.8) .build() )); ``` 相比起来其实代码并没有简化很多,只不过项目同时接入多个 AI 平台,调用方式上会得到统一。 --- **项目分区导航**:⬅️ [[06-用户模块RBAC模型搭建|06-用户模块RBAC模型搭建]] | 01-平台智能化 | ➡️ [[02-性能优化|02-性能优化]]