diff --git a/bootstrap/src/main/resources/application.yaml b/bootstrap/src/main/resources/application.yaml index 8942048f6..bd78b26bb 100644 --- a/bootstrap/src/main/resources/application.yaml +++ b/bootstrap/src/main/resources/application.yaml @@ -202,6 +202,11 @@ ai: endpoints: chat: /v1/chat/completions embedding: /v1/embeddings + atlascloud: + url: ${ATLASCLOUD_BASE_URL:${ATLAS_CLOUD_BASE_URL:https://api.atlascloud.ai}} + api-key: ${ATLASCLOUD_API_KEY:${ATLAS_CLOUD_API_KEY:}} + endpoints: + chat: /v1/chat/completions selection: failure-threshold: 2 @@ -232,6 +237,12 @@ ai: - id: gpt-5.4 provider: aihubmix model: gpt-5.4 + - id: atlas-deepseek-v4-pro + provider: atlascloud + model: deepseek-ai/deepseek-v4-pro + - id: atlas-qwen3.5-flash + provider: atlascloud + model: qwen/qwen3.5-flash default-tier: standard deep-thinking-tier: deep diff --git a/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClientTest.java b/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClientTest.java new file mode 100644 index 000000000..361cc6388 --- /dev/null +++ b/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClientTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nageoffer.ai.ragent.infra.chat; + +import com.nageoffer.ai.ragent.infra.enums.ModelProvider; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AtlasCloudChatClientTest { + + @Test + void exposesAtlasCloudProviderId() { + AtlasCloudChatClient client = new AtlasCloudChatClient(); + + assertEquals("atlascloud", client.provider()); + assertTrue(ModelProvider.ATLAS_CLOUD.matches(client.provider())); + } +} diff --git a/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/model/ModelSelectorTest.java b/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/model/ModelSelectorTest.java index 6bf61f287..7c183fbb8 100644 --- a/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/model/ModelSelectorTest.java +++ b/bootstrap/src/test/java/com/nageoffer/ai/ragent/infra/model/ModelSelectorTest.java @@ -73,7 +73,7 @@ private static AIModelProperties buildProperties() { AIModelProperties props = new AIModelProperties(); Map providers = new HashMap<>(); - for (String p : List.of("bailian", "ollama", "siliconflow", "aihubmix")) { + for (String p : List.of("bailian", "ollama", "siliconflow", "aihubmix", "atlascloud")) { providers.put(p, new AIModelProperties.ProviderConfig()); } props.setProviders(providers); @@ -85,7 +85,9 @@ private static AIModelProperties buildProperties() { cand("qwen3-local", "ollama", "qwen3:8b", false), cand("qwen3-max", "bailian", "qwen3-max", true), cand("glm-4.7", "siliconflow", "GLM-4.7", true), - cand("gpt-5.4", "aihubmix", "gpt-5.4", false) + cand("gpt-5.4", "aihubmix", "gpt-5.4", false), + cand("atlas-deepseek-v4-pro", "atlascloud", "deepseek-ai/deepseek-v4-pro", false), + cand("atlas-qwen3.5-flash", "atlascloud", "qwen/qwen3.5-flash", false) )); Map tiers = new HashMap<>(); tiers.put("fast", tier(List.of("qwen-flash", "qwen-plus", "qwen3-local"), 5000L)); @@ -161,4 +163,11 @@ private static AIModelProperties buildProperties() { List targets = selector.selectChatCandidates(false); assertEquals(List.of("qwen3-local", "gpt-5.4"), ids(targets)); } + + @Test + void atlasCloud模型可作为preferred候选() { + List targets = selector.selectChatCandidates(false, Tier.STANDARD, "atlas-deepseek-v4-pro"); + assertEquals(List.of("atlas-deepseek-v4-pro", "qwen-plus", "qwen3-local", "gpt-5.4"), ids(targets)); + assertEquals("atlascloud", targets.get(0).candidate().getProvider()); + } } diff --git a/frontend/src/pages/admin/traces/traceUtils.ts b/frontend/src/pages/admin/traces/traceUtils.ts index 14786b399..bb826df4a 100644 --- a/frontend/src/pages/admin/traces/traceUtils.ts +++ b/frontend/src/pages/admin/traces/traceUtils.ts @@ -120,6 +120,8 @@ const NODE_NAME_DISPLAY: Record = { "siliconflow-stream-chat": "硅基流动 · 流式", "aihubmix-chat": "AIHubMix · 同步", "aihubmix-stream-chat": "AIHubMix · 流式", + "atlascloud-chat": "Atlas Cloud · 同步", + "atlascloud-stream-chat": "Atlas Cloud · 流式", "query-rewrite-and-split": "问题改写与拆分", "intent-resolve": "意图识别", "guidance-detect": "歧义引导", diff --git a/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClient.java b/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClient.java new file mode 100644 index 000000000..6bc3e077c --- /dev/null +++ b/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/chat/AtlasCloudChatClient.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nageoffer.ai.ragent.infra.chat; + +import com.nageoffer.ai.ragent.framework.convention.ChatRequest; +import com.nageoffer.ai.ragent.framework.trace.RagTraceNode; +import com.nageoffer.ai.ragent.infra.enums.ModelProvider; +import com.nageoffer.ai.ragent.infra.model.ModelTarget; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class AtlasCloudChatClient extends AbstractOpenAIStyleChatClient { + + @Override + public String provider() { + return ModelProvider.ATLAS_CLOUD.getId(); + } + + @Override + @RagTraceNode(name = "atlascloud-chat", type = "LLM_PROVIDER") + public String chat(ChatRequest request, ModelTarget target) { + return doChat(request, target); + } + + @Override + public StreamCancellationHandle streamChat(ChatRequest request, StreamCallback callback, ModelTarget target) { + return doStreamChat(request, callback, target); + } +} diff --git a/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/enums/ModelProvider.java b/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/enums/ModelProvider.java index db5704a8e..428db46f3 100644 --- a/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/enums/ModelProvider.java +++ b/infra-ai/src/main/java/com/nageoffer/ai/ragent/infra/enums/ModelProvider.java @@ -48,6 +48,11 @@ public enum ModelProvider { */ AI_HUB_MIX("aihubmix"), + /** + * Atlas Cloud OpenAI-compatible model service + */ + ATLAS_CLOUD("atlascloud"), + /** * 空实现,用于测试或占位 */