调用智谱AI异步请求流式方法回复
官方代码可以去查看https://github.com/MetaGLM/zhipuai-sdk-java-v4/blob/main/src/test/java/com/zhipu/oapi/AllToolsTest.java
效果展示
提问效果:
回答效果:
1、Maven配置
<dependency><groupId>cn.bigmodel.openapi</groupId><artifactId>oapi-java-sdk</artifactId><version>release-V4-2.3.0</version></dependency>
2、yml配置
zm:zhipu:api-key: "申请一个key"
3、工具实体
package com.zm.naviTech.config;import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;/** @Author 落梨* @Date 2024-09-14 13:42* @Description:**/
@Configuration
@Data
public class ZhiPuKey {@Value("${zm.zhipu.api-key}")private String ApiKey;
}
4、controller层
注意这里的callWithMessage里的方法可以自己设置自定义参数。
流式方法这里我做了内容的组合,方便插入数据库,后面插入的mapper可以不用看了,按照你自己的业务逻辑去处理,主要看异步流式方式。
package com.zm.naviTech.AIController;import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.Constants;
import com.zhipu.oapi.service.v4.model.*;
import com.zm.naviTech.config.ZhiPuKey;
import com.zm.naviTech.constants.MessageDirectionConstant;
import com.zm.naviTech.entity.po.ChatgptMessage;
import com.zm.naviTech.mapper.ConversationMapper;
import com.zm.naviTech.utils.ThreadLocalUtil;
import io.reactivex.Flowable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.angus.mail.imap.MessageCache;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;/** @Author 落梨* @Date 2024-09-14 13:39* @Description: 质谱AI**/
@Component
@Slf4j
public class ZhiPuAiChatController {@Resourceprivate ZhiPuKey zhiPuKey;@Resourceprivate ConversationMapper conversationMapper;private static final ObjectMapper mapper = new ObjectMapper();/*** @author 落梨* @description 调用接口**/public ModelApiResponse callWithMessage(String conversationId, String prompt) throws JsonProcessingException {log.info("==============质谱AI准备回答===================");//获取keyString key = zhiPuKey.getApiKey();//生成客户端ClientV4 client = new ClientV4.Builder(key).build();//业务idString requestIdTemplate = conversationId;String requestId = String.format(requestIdTemplate, System.currentTimeMillis());//参数工具List<ChatTool> chatToolList = new ArrayList<>();ChatTool chatTool = new ChatTool();chatTool.setType("code_interpreter");chatToolList.add(chatTool);//携带消息体,这个实例 是 官方提供List<ChatMessage> messages = new ArrayList<>();ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), prompt);messages.add(chatMessage);ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder().model(Constants.ModelChatGLM4).stream(Boolean.TRUE).invokeMethod(Constants.invokeMethod).messages(messages).tools(chatToolList).toolChoice("auto").requestId(requestId).build();//使用流式ModelApiResponse sseModelApiResp = client.invokeModelApi(chatCompletionRequest);if (sseModelApiResp.isSuccess()) {AtomicBoolean isFirst = new AtomicBoolean(true);List<Choice> choices = new ArrayList<>();AtomicReference<ChatMessageAccumulator> lastAccumulator = new AtomicReference<>();mapStreamToAccumulator(sseModelApiResp.getFlowable()).doOnNext(accumulator -> {{if (isFirst.getAndSet(false)) {log.info("Response: ");}if (accumulator.getDelta() != null && accumulator.getDelta().getTool_calls() != null) {String jsonString = mapper.writeValueAsString(accumulator.getDelta().getTool_calls());log.info("tool_calls: {}", jsonString);}if (accumulator.getDelta() != null && accumulator.getDelta().getContent() != null) {log.info(accumulator.getDelta().getContent());}choices.add(accumulator.getChoice());lastAccumulator.set(accumulator);}}).doOnComplete(System.out::println).lastElement().blockingGet();ChatMessageAccumulator chatMessageAccumulator = lastAccumulator.get();ModelData data = new ModelData();data.setChoices(choices);if (chatMessageAccumulator != null) {data.setUsage(chatMessageAccumulator.getUsage());data.setId(chatMessageAccumulator.getId());data.setCreated(chatMessageAccumulator.getCreated());}data.setRequestId(chatCompletionRequest.getRequestId());sseModelApiResp.setFlowable(null);// 打印前置空sseModelApiResp.setData(data);}//组合内容StringBuilder stringBuilder = new StringBuilder();List<Choice> choices = sseModelApiResp.getData().getChoices();for (Choice choice : choices) {stringBuilder.append(choice.getDelta().getContent());}log.info(stringBuilder.toString());String content = stringBuilder.toString();log.info("质谱ai的回答是:{}",content);//插入询问语句到数据库ChatgptMessage chatgptMessage = ChatgptMessage.builder().userId(ThreadLocalUtil.getCurrentId()).messageDirection(MessageDirectionConstant.USER).createTime(LocalDateTime.now()).conversationId(Long.valueOf(conversationId)).content(prompt).build();conversationMapper.insert(chatgptMessage);//插入回答语句到数据库ChatgptMessage chatgptMessage2 = ChatgptMessage.builder().userId(ThreadLocalUtil.getCurrentId()).messageDirection(MessageDirectionConstant.AI).createTime(LocalDateTime.now()).content(content).conversationId(Long.valueOf(conversationId)).build();conversationMapper.insert(chatgptMessage2);log.info("==============回答完毕===================");return sseModelApiResp;}//流式操作public static Flowable<ChatMessageAccumulator> mapStreamToAccumulator(Flowable<ModelData> flowable) {return flowable.map(chunk -> {return new ChatMessageAccumulator(chunk.getChoices().get(0).getDelta(), null, chunk.getChoices().get(0), chunk.getUsage(), chunk.getCreated(), chunk.getId());});}
}