《通义千问AI落地—上》:后端接口

devtools/2024/11/9 17:07:44/

一、前言

本文源于微博客且已获授权,请尊重版权.

     通义,由通义千问更名而来,是阿里云推出的语言模型 ,于2023年9月13日正式向公众开放。 属于(AI Generated Content,AIGC)领域, 是一个MaaS(模型即服务)的底座。为多模态大模型(Multimodal Models)。

     通义意为“通情,达义”,具备全副AI能力,致力于成为人们的工作、学习、生活助手。 功能包括多轮对话、文案创作、逻辑推理、多模态理解、多语言支持,能够跟人类进行多轮的交互,也融入了多模态的知识理解,且有文案创作能力,能够续写小说,编写邮件等。

     虽然通义千问已经开源,但是连最基础的 Qwen2-0.5B ,也需要起码16GB的显存以上才能流程云运行(本人4060 8GB显存的显卡跑起来,等待一个问答结果,需要好几分钟),所以,私有化部署大模型所需要承受的硬件代价,不是一般的玩家所能承受的。此路不通,只得另寻他法了,这里所指的他法,就是购买通义千问的Token接口服务,价格也相当实惠:

image.png

其他信息本文不再赘述,请移步 通义千问官网 进行查看和购买。

二、成果展示

     最终的效果如下所示:

image.png

三、接口正文

3.1、maven依赖

      通义千问maven依赖主要有一下两个:

  <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-ai</artifactId></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --><dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.15.2</version></dependency>

其中,dashscope-sdk-java的版本需要根据你的jdk版本调整。

3.2、接口

  1. interface
public interface IChatGPTService {void chat(ChatMessageRequest content, Principal principal) throws NoApiKeyException, InputRequiredException;
}
  1. impl
/*** 历史对话记录;  sessionId---> 历史记录*/private static final ConcurrentHashMap<String, List<Message>> history = new ConcurrentHashMap<>();@Overridepublic void chat(ChatMessageRequest msg, Principal principal) throws NoApiKeyException, InputRequiredException {String sessionId = msg.getSessionId();//用户发送的消息入库CompletableFuture.runAsync(() -> {saveMsg(msg.getContent(), sessionId, Role.USER, getLocalDate());});Message message = Message.builder().role(Role.USER.getValue()).content(msg.getContent()).build();// 创建QwenParam对象,设置参数GenerationParam param = GenerationParam.builder().model(module) // 模型版本 qwen-max.messages(getHistory(sessionId)) // 消息内容,如果需要启用多伦连续对话的话,就把用户历史消息以及GPT回复的消息一起放进去.resultFormat(GenerationParam.ResultFormat.MESSAGE).topP(0.8).enableSearch(true).apiKey(apiKey)  // 你的apiKey,需要到阿里云百炼官网申请.incrementalOutput(true).build();// 调用生成接口,获取Flowable对象Flux<GenerationResult> result = Flux.from(gen.streamCall(param));StringBuffer builder = new StringBuffer();DateTime finalLocalTime = getLocalDate();Flux.from(result)// 控制发送频率.delayElements(Duration.ofMillis(200)).doOnNext(res -> {String output = res.getOutput().getChoices().get(0).getMessage().getContent();if (output == null || "".equals(output)) {return;}// 将生成的消息通过websocket发送给前端,websocket内容将在下篇文章介绍sendMsg(output, sessionId, principal);builder.append(output);}).doFinally(signalType -> {//消息发送结束,告诉前端sendMsg("!$$---END---$$!", sessionId, principal);//消息入库CompletableFuture.runAsync(() -> {saveMsg(builder.toString(), sessionId, Role.ASSISTANT, finalLocalTime);buildHistory(sessionId,Message.builder().role(Role.ASSISTANT.getValue()).content(builder.toString()));});}).onErrorResume(str -> {if (str instanceof ApiException) {ApiException exception = (ApiException) str;log.error("接口调用出现错误:{}", exception.getMessage());}sendMsg("GPT接口调用出现错误,该功能暂时无法使用,敬请期待.", sessionId, principal);return Mono.empty();}).subscribeOn(Schedulers.boundedElastic()) // 在弹性线程池中执行.subscribe();}/*** 每日凌晨自动清理历史对话缓存,防止缓存过大*/@Scheduled(cron = "0 59 23 * * ?")private void autoCleanHistory() {history.clear();}/*** 构建历史消息*/private void buildHistory(String sessionId, MessageBuilder<?, ?> message) {List<Message> historyMessages = history.computeIfAbsent(sessionId, k -> {List<ChatMessageVO> list = sessionService.getById(sessionId).getMessages();List<Message> getMsgList = new ArrayList<>();if (list.isEmpty()) return getMsgList;MessageBuilder<?, ?> msg = Message.builder();//只取后面60条,历史消息太多,一是过快消耗token,二是压力太大list.subList(Math.max(0, list.size() - 60), list.size()).forEach(item -> {if (!"".equals(item.getContent())) {msg.content(item.getContent()).role(item.getRole()).build();getMsgList.add(msg.build());}});return getMsgList;});// 添加消息到列表historyMessages.add(message.build());history.remove(sessionId);history.put(sessionId, historyMessages);}private List<Message> getHistory(String sessionId) {List<Message> list = history.get(sessionId);if (list == null || list.isEmpty()) {return new ArrayList<>();}list.removeIf(item -> ("".equals(item.getContent())));List<Message> hist = list.subList(Math.max(0, list.size() - 80), list.size());history.remove(sessionId);history.put(sessionId, hist);return hist;}
  1. 接口调用
@Controller
@AllArgsConstructor
@Slf4j
@CrossOrigin
public class WebSocketController {private final IChatGPTService service;private final SocketServiceImpl socketService;// 前端通过websocket发送消息给GPT,调用相关接口生成内容@MessageMapping("/chat/send")public void chat(@Payload ChatMessageRequest message, Principal principal) throws NoApiKeyException,InputRequiredException {service.chat(message, principal);}
}

其中涉及到的一些Java实体如下:

@Data
@Accessors(chain = true)
@RequiredArgsConstructor
public class ChatMessageRequest extends BaseEntity {private String content;private String role;private String sessionId;
}
    //上文提到的getLocalDate函数内容public static DateTime getLocalDate() {ZoneId zoneId = ZoneId.of("Asia/Shanghai");ZonedDateTime now = ZonedDateTime.now(zoneId);DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(zoneId);String formattedDate = now.format(formatter);try {ZonedDateTime parsedDate = ZonedDateTime.parse(formattedDate, formatter);return new DateTime(parsedDate.toInstant().toEpochMilli());}catch (DateTimeParseException e) {e.printStackTrace();return cn.hutool.core.date.DateUtil.parse(cn.hutool.core.date.DateUtil.now());}}

     通义千问主要的接口调用如上所述。在中篇,我将介绍《通义千问AI落地》前端实现。


http://www.ppmy.cn/devtools/98425.html

相关文章

javaweb_10:XML映射文件

一、规范 1、XML映射文件的名称与Mapper接口名称一致&#xff0c;并且将XML映射文件和Mapper接口放在相同的包下&#xff08;同包同名&#xff09;。 2、XML映射文件的namesapce属性为Mapper接口全限定名一致。 3、 XML映射文件中sql语句的id与Mapper接口中的方法名一致&a…

三个AI智能体开源项目:MetaGPT/AutoGPT/DB-GPT

三个AI智能体开源项目&#xff1a;MetaGPT/AutoGPT/DB-GPT (qq.com) MetaGPT以其元学习的能力&#xff0c;展现出自我优化的独特魅力&#xff1b;AutoGPT则以其自动化的特性&#xff0c;为编程领域带来了革命性的变革&#xff1b;而DB-GPT则在数据库管理领域&#xff0c;以其深…

kickstart自动安装脚本制作详解

一、kickstart自动安装脚本制作 此实验中&#xff0c;使用Rhel7.9&#xff0c;并开启图形化系统 1.设置实验环境 1.使用Rhel7.9 2.需要打开图形化系统 [rootpxe ~]# hostnamectl # 查看当前系统是否为图形化Static hostname: pxeIcon name: com…

认识HarmonyOS

HarmonyOS 三大特性 硬件互助&#xff0c;资源共享 把各终端硬件的能力&#xff0c;虚拟为一个共享的能力资源池&#xff0c;让应用通过系统&#xff0c;调用取其硬件能力。在这种架构下&#xff0c;硬件能力就像“活字印刷术”中的单词字母&#xff0c;可以被无限次的重复使用…

Epoll的实现原理

Epoll是Linux IO多路复用的一种IO管理机制。内核的实现代码在Linux内核源码的fs/eventpoll.c中。是比select和poll更高性能的一种IO管理机制。 前期准备 在实现epoll之前&#xff0c;要先了解内核epoll的运行原理。内核的epoll可以从四方面来理解。 Epoll 的数据结构&#xf…

如何应对突发技术故障和危机:开发团队的应急策略

开发团队如何应对突发的技术故障和危机&#xff1f; 在数字化时代&#xff0c;软件服务的稳定性对于企业至关重要。然而&#xff0c;即使是大型平台&#xff0c;如网易云音乐&#xff0c;也可能遇到突发的技术故障。网页端出现502 Bad Gateway 报错&#xff0c;且App也无法正常…

使用html-docx-js + fileSaver实现前端导出word

因为html-docx-js是16年的老库了&#xff0c;它代码里面用到的with语法现在严格模式不允许&#xff0c;用npm直接引入会报错&#xff0c;所以我们需要用其它方式引入 首先要将html-docx-js的代码放到项目中 html-docx-js/dist/html-docx.js at master evidenceprime/html-do…

java 环境安装

1, 下载jdk jdk-8u74-macosx-x64.dmg (jdk-8u20-macosx-x64.dmg) 2,配置环境变量 进入/Users/xxx vi ~/.bash_profile export JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home export PATH$JAVA_HOME/bin:$PATH:. export CLASSPATH$JAVA_HOME/…