diff --git a/src/main/java/cn/van/business/util/ds/SocialMediaLlmClient.java b/src/main/java/cn/van/business/util/ds/SocialMediaLlmClient.java
index 75810bc..d9ac8fb 100644
--- a/src/main/java/cn/van/business/util/ds/SocialMediaLlmClient.java
+++ b/src/main/java/cn/van/business/util/ds/SocialMediaLlmClient.java
@@ -180,8 +180,37 @@ public class SocialMediaLlmClient {
return t.isEmpty() ? null : t;
}
+ /**
+ * 火山方舟「Coding / OpenClaw」文档里的基址常为 {@code .../api/coding/v3},与 OpenAI 兼容对话接口
+ * {@code .../api/v3/chat/completions} 不同,误填会导致 404。此处自动纠正常见误填。
+ *
+ * @see 方舟对话 API
+ */
+ private static String normalizeOpenAiCompatibleUrl(String chatCompletionsUrl) {
+ if (StrUtil.isBlank(chatCompletionsUrl)) {
+ return chatCompletionsUrl;
+ }
+ String u = chatCompletionsUrl.trim().replaceAll("/+$", "");
+ if (!u.contains("volces.com") || u.contains("chat/completions")) {
+ return u;
+ }
+ if (u.contains("/api/coding/")) {
+ String fixed = u.replace("/api/coding/v3", "/api/v3/chat/completions");
+ if (!fixed.equals(u)) {
+ return fixed;
+ }
+ }
+ return u;
+ }
+
private String callOpenAiCompatible(String chatCompletionsUrl, String apiKey, String model, String userText)
throws IOException {
+ String endpoint = normalizeOpenAiCompatibleUrl(chatCompletionsUrl);
+ String originalTrim = chatCompletionsUrl == null ? "" : chatCompletionsUrl.trim().replaceAll("/+$", "");
+ if (!endpoint.equals(originalTrim)) {
+ log.info("OpenAI 兼容 URL 已规范化: {} -> {}", originalTrim, endpoint);
+ }
+
Map requestBody = new HashMap<>();
requestBody.put("model", model);
requestBody.put("messages", new Map[]{
@@ -191,7 +220,7 @@ public class SocialMediaLlmClient {
String jsonBody = objectMapper.writeValueAsString(requestBody);
- HttpRequest request = HttpRequest.of(chatCompletionsUrl.trim())
+ HttpRequest request = HttpRequest.of(endpoint)
.method(Method.POST)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
@@ -202,12 +231,21 @@ public class SocialMediaLlmClient {
request.header("Authorization", "Bearer " + apiKey.trim());
}
- log.info("请求 OpenAI 兼容 API: URL={}, model={}", chatCompletionsUrl, model);
+ log.info("请求 OpenAI 兼容 API: URL={}, model={}", endpoint, model);
HttpResponse response = request.execute();
if (response.getStatus() != 200) {
- log.error("OpenAI 兼容 API 失败: status={}, body={}", response.getStatus(), response.body());
- throw new IOException("API 调用失败,HTTP 状态码: " + response.getStatus());
+ String body = response.body();
+ log.error("OpenAI 兼容 API 失败: status={}, body={}", response.getStatus(), body);
+ String hint = "";
+ if (response.getStatus() == 404) {
+ hint = "(若为火山方舟:请使用 .../api/v3/chat/completions ,不要用 Coding 文档中的 .../api/coding/v3 )";
+ }
+ String snippet = "";
+ if (StrUtil.isNotBlank(body)) {
+ snippet = " — " + (body.length() > 400 ? body.substring(0, 400) + "..." : body);
+ }
+ throw new IOException("API 调用失败,HTTP 状态码: " + response.getStatus() + hint + snippet);
}
JsonNode root = objectMapper.readTree(response.body());