package cc.mrbird.febs.ai.strategy.Impl; import cc.mrbird.febs.ai.strategy.LlmStrategyService; import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyContextEnum; import cc.mrbird.febs.ai.strategy.param.LlmStrategyDto; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.exception.FebsException; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.volcengine.ark.runtime.model.completion.chat.*; import com.volcengine.ark.runtime.service.ArkService; import okhttp3.ConnectionPool; import okhttp3.Dispatcher; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Component("HsLlmStrategyService") public class HsLlmStrategyServiceImpl implements LlmStrategyService { private ArkService service; private static final String ak = "AKLTZTQxZjMyZTUxMWJmNDEyNDkzNWExOGQ3ODllNzhhNmQ"; private static final String sk = "TmpFeE1qZ3haREExTW1JeE5HRTBZVGc1WlRRNVlqWXpORGd5TWpsak5HWQ=="; private static final String baseUrl = "https://ark.cn-beijing.volces.com/api/v3"; private static final String LinkId = "ep-20250805124033-lhxbf"; private static final Double temperature = 0.7; private static final Double topP = 0.9; private static final Integer maxTokens = 2048; private static final Double frequencyPenalty = 0.0; @PostConstruct public void init() { // 增加连接池大小和存活时间 ConnectionPool connectionPool = new ConnectionPool(32, 60, TimeUnit.SECONDS); Dispatcher dispatcher = new Dispatcher(); // 增加并发请求数量 dispatcher.setMaxRequests(128); dispatcher.setMaxRequestsPerHost(32); this.service = ArkService.builder() .dispatcher(dispatcher) .connectionPool(connectionPool) .baseUrl(baseUrl) .ak(ak) .sk(sk) .build(); } @PreDestroy public void destroy() { if (service != null) { service.shutdownExecutor(); } } private List getMessages(List dto) { List messages = new ArrayList<>(); for (LlmStrategyDto dtoItem : dto){ if (StrUtil.equals(dtoItem.getRole(), ChatMessageRole.SYSTEM.value())){ messages.add(ChatMessage.builder() .role(ChatMessageRole.SYSTEM) .content(dtoItem.getContent()) .build()); } if (StrUtil.equals(dtoItem.getRole(), ChatMessageRole.USER.value())){ messages.add(ChatMessage.builder() .role(ChatMessageRole.USER) .content(dtoItem.getContent()) .build()); } if (StrUtil.equals(dtoItem.getRole(), ChatMessageRole.ASSISTANT.value())){ messages.add(ChatMessage.builder() .role(ChatMessageRole.ASSISTANT) .content(dtoItem.getContent()) .build()); } } return messages; } @Override public FebsResponse llmInvokeNonStreaming(List dto) { if (CollUtil.isEmpty(dto)){ throw new FebsException("火山大模型初始化异常"); } List messages = getMessages(dto); String result = ""; try { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model(LinkId) .messages(messages) .stream(false) .temperature(temperature) // 降低温度参数,提高确定性,可能提升速度 .topP(topP) // 调整topP参数 .maxTokens(maxTokens) // 减少最大token数 .frequencyPenalty(frequencyPenalty) .build(); List choices = service.createChatCompletion(chatCompletionRequest).getChoices(); result = choices.stream() .map(choice -> choice.getMessage().getContent()) .filter(contentObj -> contentObj != null) .map(Object::toString) .collect(Collectors.joining()); } catch (Exception e) { throw new FebsException(StrUtil.format("火山大模型调用异常:{}", e.getMessage())); } return new FebsResponse().success().data(result); } @Override public Flux llmInvokeStreamingWithThink(List dto) { if (CollUtil.isEmpty(dto)){ throw new FebsException("火山大模型初始化异常"); } List messages = getMessages(dto); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model(LinkId) .messages(messages) .stream(true) .thinking(new ChatCompletionRequest.ChatCompletionRequestThinking("enabled")) .temperature(temperature) // 降低温度参数,提高确定性,可能提升速度 .topP(topP) // 调整topP参数 .maxTokens(maxTokens) // 减少最大token数 .frequencyPenalty(frequencyPenalty) .build(); return Flux.from(service.streamChatCompletion(chatCompletionRequest)) .map(response -> { if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) { return new FebsResponse().success().data("未响应,请重试"); } ChatCompletionChoice choice = response.getChoices().get(0); if (choice == null || choice.getMessage() == null) { return new FebsResponse().success().data("END"); } ChatMessage message = choice.getMessage(); HashMap stringStringHashMap = new HashMap<>(); if (ObjectUtil.isNotEmpty(message.getReasoningContent())) { stringStringHashMap.put(LlmStrategyContextEnum.THINK.name(),message.getReasoningContent().toString()); } if (ObjectUtil.isNotEmpty(message.getContent())) { stringStringHashMap.put(LlmStrategyContextEnum.CONTENT.name(),message.getContent().toString()); } return new FebsResponse().success().data(stringStringHashMap); }) .onErrorResume(throwable -> { throw new FebsException(StrUtil.format("火山大模型流式调用AI服务失:{}",throwable)); }); } @Override public Flux llmInvokeStreamingNoThink(List dto) { if (CollUtil.isEmpty(dto)){ throw new FebsException("火山大模型初始化异常"); } List messages = getMessages(dto); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model(LinkId) .messages(messages) .stream(true) .temperature(temperature) // 降低温度参数,提高确定性,可能提升速度 .topP(topP) // 调整topP参数 .maxTokens(maxTokens) // 减少最大token数 .frequencyPenalty(frequencyPenalty) .build(); return Flux.from(service.streamChatCompletion(chatCompletionRequest)) .map(response -> { if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) { return new FebsResponse().success().data("未响应,请重试"); } ChatCompletionChoice choice = response.getChoices().get(0); if (choice == null || choice.getMessage() == null) { return new FebsResponse().success().data("END"); } ChatMessage message = choice.getMessage(); HashMap stringStringHashMap = new HashMap<>(); if (ObjectUtil.isNotEmpty(message.getContent())) { stringStringHashMap.put(LlmStrategyContextEnum.CONTENT.name(),message.getContent().toString()); } return new FebsResponse().success().data(stringStringHashMap); }) .onErrorResume(throwable -> { throw new FebsException(StrUtil.format("火山大模型流式调用AI服务失:{}",throwable)); }); } }