前言

在这个系列教程中,我们将会学习如何利用Java编程语言结合ChatGPT和向量数据库,快速构建一个私有的问答知识库。这种知识库基于检索增强生成模型RAG,可以帮助我们创建个性化的AI机器人。本系列分为三篇文章,本文是系列的最后一篇,重点介绍如何将ChatGPT集成我们的系统中,完成私人AI知识库的搭建。

一、构造事件监听器类

为了与ChatGPT进行对接,我们采用了一位技术专家开发的Java SDK。这个SDK为我们提供了与ChatGPT API交互的便利。如果您对这项技术感兴趣并希望深入了解,可以通过以下链接访问SDK的详细信息和源码: ChatGPT Api的Java SDK 在这个环节,我们将详细介绍如何使用这个SDK来构建事件监听器类,这是实现ChatGPT与我们知识库交互的关键一步。

1
@Getter @Setter // 事件监听器类,用于处理 OpenAI 接口的流式返回,使用 SSE 的方式流式返回给调用方 public class OpenAiStreamListener extends EventSourceListener { // 引入日志组件 private static final Logger log = LoggerFactory.getLogger(ConsoleEventSourceListener.class); // SSE 结构 private SseEmitter sseEmitter; // 用于存储最终返回的结果 private StringBuilder result = new StringBuilder(); public OpenAiStreamListener(SseEmitter sseEmitter) { this.sseEmitter = sseEmitter; } @Override public void onOpen(EventSource eventSource, Response response) { log.info("OpenAI建立sse连接..."); } @Override public void onEvent(EventSource eventSource, String id, String type, String data) { log.info("OpenAI返回数据:{}", data); if (data.equals("[DONE]")) { log.info("OpenAI返回数据结束了"); sseEmitter.complete(); } else { try { sseEmitter.send(data); JSONObject dataJson = JSON.parseObject(data, JSONObject.class); if (dataJson.containsKey("choices")) { JSONObject choice = (JSONObject) dataJson.getJSONArray("choices").get(0); String content = choice.getJSONObject("delta").getString("content"); if (content != null) { result.append(content); } } } catch (IOException e) { e.printStackTrace(); } } } @Override public void onClosed(EventSource eventSource) { log.info("OpenAI关闭sse连接..."); sseEmitter.complete(); } @Override public void onFailure(EventSource eventSource, Throwable t, Response response) { try { if (Objects.isNull(response)) { log.error("OpenAI sse连接异常:{}", t); eventSource.cancel(); } else { ResponseBody body = response.body(); if (Objects.nonNull(body)) { log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t); } else { log.error("OpenAI sse连接异常data:{},异常:{}", response, t); } eventSource.cancel(); } sseEmitter.complete(); } catch (Exception e) { e.printStackTrace(); } } }

二、构造 GPTService 业务逻辑

1、初始化请求client

此处如果想调整下面具体的参数或需要了解参数表达的含义,移步 ChatGPT Api的Java SDK 详细查看

1
@Value("${openai-key}") private String OPENAI_KEY; @PostConstruct public void initStreamClient() { if (streamClient == null) { HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger()); //!!!!千万别再生产或者测试环境打开BODY级别日志!!!! //!!!生产或者测试环境建议设置为这三种级别:NONE,BASIC,HEADERS,!!! httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); OkHttpClient okHttpClient = new OkHttpClient .Builder() .addInterceptor(httpLoggingInterceptor) .connectTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build(); streamClient = OpenAiStreamClient .builder() .apiKey(Collections.singletonList(OPENAI_KEY)) .okHttpClient(okHttpClient) .apiHost(API_HOST) .build(); } }

2、与ChatGPT聊天的代码实现

1
/** * 与 ChatGPT 聊天的代码实现 * @param prompt 发送给 chatGPT 的内容 * @return 返回 SseEmitter */ public SseEmitter chatCompletions(String prompt) { // 构造发送给GPT的Message Message message = Message.builder().role(Message.Role.USER).content(prompt).build(); // 构造请求参数,具体参数含义可以查看 OpenAI官方文档 ChatCompletion chatCompletion = ChatCompletion .builder() .model(ChatCompletion.Model.GPT_3_5_TURBO.getName()) .temperature(0.2) .maxTokens(2048) .messages(Collections.singletonList(message)) .stream(true) .build(); // 设置事件监听器 SseEmitter sseEmitter = new SseEmitter(0L); OpenAiStreamListener listener = new OpenAiStreamListener(sseEmitter); streamClient.streamChatCompletion(chatCompletion, listener); // 当所有内容返回完成后,触发 onCompletion 方法,可以在这里执行打印或保存聊天记录等逻辑 sseEmitter.onCompletion(() -> { System.out.println(" == 完整的Prompt == "); System.out.println(prompt); System.out.println("\n"); System.out.println(" == stream 流输出完成 == "); System.out.println(listener.getResult().toString()); }); return sseEmitter; }

三、构造对外暴露的调用接口

1、普通的GPT聊天调用

1
/** * GPT正常聊天 * @param question 用户的问题 * @return SseEmitter */ @PostMapping("/chat") public SseEmitter chat(@RequestBody Question question) { return gptService.chatCompletions(question.getQuestion()); }

2、依据我们私有的知识与 GPT 进行聊天

1
/** * 依据我们私有的知识与 GPT 进行聊天 * @param question 用户的问题 * @return SseEmitter */ @PostMapping("/chat-with-question") public SseEmitter chatWithQuestion(@RequestBody Question question) { // 先根据向量查询语义相近的语料 List<Question> questionList = dashVectorService.searchQuestion(question.getQuestion()); // 构造 GPT 的输入,拼接相关的资料和用户的问题 StringBuilder promptBuilder = new StringBuilder(); promptBuilder.append("你是一个光伏新能源领域的专家,请根据提供资料为用户解答问题\n"); promptBuilder.append("提供的资料: \n"); for (Question similarQuestion : questionList) { promptBuilder.append(similarQuestion.getQuestion()).append("\n"); promptBuilder.append(similarQuestion.getAnswer()).append("\n"); } promptBuilder.append("用户提问: \n"); promptBuilder.append(question.getQuestion()); return gptService.chatCompletions(promptBuilder.toString()); }

四、实际调用测试

大功告成,又到了我们的测试环节

首先试试普通的 GPT 聊天

Postman调用结果

程序打印内容

然后试试我们的私有知识库聊天

Postman调用结果

程序打印完整内容如下,太长了,我就不截图直接贴上来了

1
== 完整的Prompt == 你是一个光伏新能源领域的专家,请根据提供资料为用户解答问题 提供的资料: 光伏系统逆变器安装应该注意哪些问题? 逆变器作为光伏系统的核心部件,直接影响系统发电量,应该注意以下几点: (1)由于逆变器与电网连接改变了逆变器阻抗特性,易造成逆变器自身谐振,多发生于多台逆变器并联; (2)逆变器安装后一定要有专人复检,并标记及记录; (3)逆变器通风风道与外风道连接处应采用软连接,防止机械震动造成机械噪声; (4)当逆变器噪声增大、有异味时,应引起注意,检查逆变器内部故障,找出原因酌情处理; (5)安装调试时注意对逆变器漏电、接地、相序等的检测; (6)逆变器调试时至少满足2人同时在场,注意操作人员的安全防护。 在彩钢板屋顶安装光伏组件有哪些注意事项? 在彩钢板屋顶安装光伏组件需要考虑以下几个问题: (1)在彩钢板屋顶安装光伏系统要综合考虑彩钢板的自身寿命是否能够满足光伏系统寿命的要求; (2)对已有一定使用年限的屋面的锈蚀情况、防水体系完好情况进行勘察、评估,对存在隐患的结构进行加固或完全修复; (3)光伏组件贴着彩钢板直接平铺安装,需要考虑光伏组件的通风散热,减少彩钢板屋顶温度对光伏组件发电效率以及相关器件、材料的影响; (4)光伏组件安装过程中应该避免对彩钢板的破坏造成漏水。一旦漏水由于彩钢板夹层岩棉(其他填充物)的吸收发生渗水位置的转移,对漏水位置判断难度大; (5)彩钢板的机械强度弱,在光伏系统的安装过程中减少对彩钢板的破坏,避免彩钢板机械变形影响光伏系统的结构稳定性; (6)当组件小角度安装时,在雨后宜及时处理组件边缘积尘,以免灰尘积累造成热斑; (7)安装前制定彩钢板屋顶寿命到期后更换便捷的预案。 光伏阵列的设计与安装要考虑风速的影响吗?安装户用分布式光伏系统时应如何考虑建筑荷载和抗风能力要求? 在建筑物屋顶安装光伏阵列,必须考虑建筑物屋顶的载荷,同时考虑气流在遇到建筑物后产生的紊流和速度变化对光伏阵列的安全性影响。只有充分考虑当地风况、地貌地形以及计划安装光伏阵列的建筑物在周边环境的相对位置,才能确保光伏阵列和周边生命财产的安全。 户用光伏安装是否属于电力建设工程?是否在电力建设工程施工安全监督管理办法规定的范围内? 依据《电力安全生产监督管理办法》(国家发改委令第21号)第三条“国家能源局及其派出机构依照本办法,对电力企业的电力运行安全(不包括核安全)、电力建设施工安全、电力工程质量安全、电力应急、水电站大坝运行安全和电力可靠性工作等方面实施监督管理” 依据《国家能源局综合司关于进一步规范电力安全信息报送和统计工作的通知》(国能综通安全〔2018〕181号)“...以下情况不纳入统计范围:...(三)用户的电力设施生产、建设过程中发生的生产安全事故...”。 综上,户用光伏安装和工商业厂房屋顶光伏安装属于用户的电力设施建设,不属于电力企业的电力建设工程,因此不在《电力建设工程施工安全监督管理办法》(国家发改委令第28号)规定的范围内。 选择安装户用分布式光伏系统的建筑屋顶时,需要特别考虑哪些因素? 在建筑屋顶安装户用分布式光伏系统,增加了屋顶的承重和荷载,需要特别考虑如下因素: (1)建筑屋顶的承重和荷载是否能够满足光伏系统的设计要求,宜由原设计单位进行复核; (2)建筑屋顶的附加物(如排风口、电梯室)、女儿墙等是否遮挡太阳光对光伏组件的照射; (3)建筑物的周围是否有其他高的建筑物、树、电线杆等外部因素的遮挡; (4)光伏系统高出建筑屋顶,且不能影响相邻建筑的采光条件; (5)光伏系统区域应设立明显警示标志,宜杜绝非专业人员单独进入屋顶光伏系统区域; (6)光伏方阵的布置,应考虑留出检修维护通道,同时保证屋面安全疏散通道的畅通; (7)光伏组件支架的基础,不能影响屋面的雨水排放系统,同时不能破坏屋面的保温防水性能; (8)光伏方阵不能跨越建筑的变形缝安装; (9)光伏组件与屋面之间应有一定的通风降温空间,满足组件工作温度的要求; (10)还需兼顾光伏建筑的美观性。 用户提问: 光伏安装注意事项有哪些? == stream 流输出完成 == 光伏安装的注意事项包括以下几点: 1. 选择合适的安装位置:确保安装位置能够充分接收阳光,并且没有阴影遮挡。 2. 安装角度和方向:根据当地的经纬度和太阳高度角确定最佳的安装角度和方向,以获得最大的发电效率。 3. 安全防护:在安装过程中,要注意安全防护措施,如佩戴安全帽、安全带等,确保工作人员的安全。 4. 电气安全:在安装过程中,要注意电气安全,确保正确接地和绝缘,避免触电事故。 5. 材料选择:选择高质量的光伏组件、逆变器和其他配套设备,确保系统的可靠性和耐久性。 6. 安装质量控制:安装过程中要进行质量控制,确保安装的准确性和稳定性。 7. 维护和检修:安装完成后,要定期进行维护和检修,确保系统的正常运行和发电效率。 8. 法律法规遵守:在安装过程中要遵守相关的法律法规,如申请必要的许可证和报告等。

到此,我们所有的工作圆满完成!

点击查看上一篇

项目仓库地址:lifei1102/MyGPT