From 166e48cadacbaf7b68bb45a4b3a79fae380b0d09 Mon Sep 17 00:00:00 2001 From: jqb Date: Mon, 10 Aug 2026 10:15:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(backend):=20=E4=B8=BA=E7=99=BE=E7=82=BC?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=B7=BB=E5=8A=A0=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=A8=A1=E5=BC=8FAPI=E8=B0=83=E7=94=A8=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增generateCompatible方法实现OpenAI兼容端点的调用逻辑,适配/compatible-mode路径的百炼/MaaS接口,自动补全chat/completions后缀并处理标准OpenAI格式的请求响应 --- .../generation/client/BailianClient.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/backend/generation-service/src/main/java/com/artedu/generation/client/BailianClient.java b/backend/generation-service/src/main/java/com/artedu/generation/client/BailianClient.java index 1dc304c..5ff02bb 100644 --- a/backend/generation-service/src/main/java/com/artedu/generation/client/BailianClient.java +++ b/backend/generation-service/src/main/java/com/artedu/generation/client/BailianClient.java @@ -8,6 +8,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.client.RestTemplate; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,6 +48,11 @@ public class BailianClient implements LLMClient { url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"; } + // 阿里MaaS/百炼 OpenAI 兼容端点(compatible-mode)走 chat/completions 协议 + if (url.contains("/compatible-mode")) { + return generateCompatible(url, system, prompt, maxTokens, thinkingDisabled); + } + HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + model.getApiKey()); @@ -104,6 +110,64 @@ public class BailianClient implements LLMClient { } } + /** + * 调用 OpenAI 兼容端点(百炼/MaaS compatible-mode) + * URL 形如 https://xxx/compatible-mode/v1,自动补全 /chat/completions + */ + private String generateCompatible(String apiUrl, String system, String prompt, Integer maxTokens, boolean thinkingDisabled) { + String url = apiUrl.endsWith("/") ? apiUrl.substring(0, apiUrl.length() - 1) : apiUrl; + if (!url.endsWith("/chat/completions")) { + url = url + "/chat/completions"; + } + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", "Bearer " + model.getApiKey()); + + List> messages = new ArrayList<>(); + if (system != null && !system.isEmpty()) { + messages.add(Map.of("role", "system", "content", system)); + } + messages.add(Map.of("role", "user", "content", prompt)); + + Map requestBody = new HashMap<>(); + requestBody.put("model", model.getModelCode()); + requestBody.put("messages", messages); + if (maxTokens != null) { + requestBody.put("max_tokens", maxTokens); + } + if (thinkingDisabled) { + requestBody.put("enable_thinking", false); + } + + try { + HttpEntity> entity = new HttpEntity<>(requestBody, headers); + Map response = restTemplate.postForObject(url, entity, Map.class); + + if (response == null) { + log.error("百炼兼容模式API返回空响应"); + return null; + } + + List> choices = (List>) response.get("choices"); + if (choices == null || choices.isEmpty()) { + log.error("百炼兼容模式API返回错误: {}", response.get("error")); + return null; + } + + Map message = (Map) choices.get(0).get("message"); + if (message == null) { + log.error("百炼兼容模式API返回缺少message: {}", response); + return null; + } + + return (String) message.get("content"); + } catch (Exception e) { + log.error("百炼兼容模式API调用失败: {}", e.getMessage(), e); + return null; + } + } + @Override public LlmModel getModel() { return model;