From d857069a3c0ab115a3ec7fb3a5826411caeba311 Mon Sep 17 00:00:00 2001 From: jade Date: Fri, 28 Aug 2026 13:55:34 +0900 Subject: [PATCH] feat: Add support for internal LiteLLM models (Qwen3, Gemma-4) - Add dynamic routing in ChatController for Qwen3-Coder and Gemma-4-31B - Update scaffold.html and chat.html model selection dropdowns - Maintain existing OpenRouter fallback via application.yml --- .../dat/mcg/presentation/ChatController.java | 54 +++++++++++++++---- .../src/main/resources/application.yml | 8 +++ .../main/resources/static/admin/scaffold.html | 14 +++-- .../src/main/resources/static/chat.html | 17 +++--- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/dat-gateway/src/main/java/io/shinhanlife/dat/mcg/presentation/ChatController.java b/dat-gateway/src/main/java/io/shinhanlife/dat/mcg/presentation/ChatController.java index e64c3455..c87f9eb4 100644 --- a/dat-gateway/src/main/java/io/shinhanlife/dat/mcg/presentation/ChatController.java +++ b/dat-gateway/src/main/java/io/shinhanlife/dat/mcg/presentation/ChatController.java @@ -81,27 +81,59 @@ public class ChatController { } } - String selectedModel = request.getOrDefault("model", "cohere/north-mini-code:free").trim(); + String selectedModel = request.getOrDefault("model", "Qwen3-Coder").trim(); if (selectedModel.isEmpty()) { - selectedModel = "cohere/north-mini-code:free"; + selectedModel = "Qwen3-Coder"; } - // 1. gemini-flash-latest 선택 시 OpenRouter의 Google Gemma 4 모델로 라우팅 + // LiteLLM 내부망 모델 매핑 if (selectedModel.equals("gemini-flash-latest")) { - selectedModel = "google/gemma-4-31b-it:free"; - log.info("[Real AI Chat] Gemini 직접 API → OpenRouter Google Gemma 4 31B 로 라우팅 전환"); + selectedModel = "Gemma-4-31B"; + log.info("[Real AI Chat] 화면의 Gemini 플래시 선택을 사내 Gemma-4-31B 모델로 라우팅 전환"); } - // 2. OpenRouter 무료 모델 처리 (Spring AI 빌드된 ChatClient 및 MCP 툴 호출 완벽 지원!) - ChatClient activeChatClient = chatClientBuilder - .defaultSystem("You are AX HUB Assistant, a highly capable enterprise AI agent. You must use the provided tools to answer user questions when necessary. Always answer politely in Korean.") - .build(); + ChatClient activeChatClient; + org.springframework.ai.chat.prompt.ChatOptions chatOptions; + + // 2. 모델 분기 처리: 사내 모델(Qwen3/Gemma-4) vs 기존 외부 모델(OpenRouter 등) + if ("Qwen3-Coder".equalsIgnoreCase(selectedModel) || "Gemma-4-31B".equalsIgnoreCase(selectedModel)) { + // 사내 LiteLLM 환경 동적 ChatModel 생성 + String liteLlmBaseUrl = "https://dev-iam-litellm.shinhanlife.co.kr:18020"; + String apiKey = "Gemma-4-31B".equalsIgnoreCase(selectedModel) ? "sk-EH107wYBZuU6RUTqthR17A" : "sk-UJ2IRenvaMPbY3ozQdj6zw"; + + org.springframework.ai.openai.api.OpenAiApi openAiApi = org.springframework.ai.openai.api.OpenAiApi.builder() + .baseUrl(liteLlmBaseUrl) + .apiKey(new org.springframework.ai.model.SimpleApiKey(apiKey)) + .build(); + + org.springframework.ai.openai.OpenAiChatModel dynamicChatModel = org.springframework.ai.openai.OpenAiChatModel.builder() + .openAiApi(openAiApi) + .build(); + + activeChatClient = ChatClient.builder(dynamicChatModel) + .defaultSystem("You are AX HUB Assistant, a highly capable enterprise AI agent. You must use the provided tools to answer user questions when necessary. Always answer politely in Korean.") + .build(); + + chatOptions = org.springframework.ai.openai.OpenAiChatOptions.builder() + .model(selectedModel) + .temperature(0.2) + .maxTokens(16384) + .build(); + } else { + // 기존 방식: application.yml 에 설정된 기본 Bean (OpenRouter 등) 사용 + activeChatClient = chatClientBuilder + .defaultSystem("You are AX HUB Assistant, a highly capable enterprise AI agent. You must use the provided tools to answer user questions when necessary. Always answer politely in Korean.") + .build(); + + chatOptions = org.springframework.ai.openai.OpenAiChatOptions.builder() + .model(selectedModel) + .build(); + } Flux responseStream = activeChatClient.prompt() .user(message) .toolCallbacks(callbacks.toArray(new ToolCallback[0])) - .options(org.springframework.ai.openai.OpenAiChatOptions.builder() - .model(selectedModel).build()) + .options(chatOptions) .stream() .content(); diff --git a/dat-gateway/src/main/resources/application.yml b/dat-gateway/src/main/resources/application.yml index 53501aa1..03409397 100644 --- a/dat-gateway/src/main/resources/application.yml +++ b/dat-gateway/src/main/resources/application.yml @@ -9,6 +9,7 @@ spring: lifecycle: timeout-per-shutdown-phase: 20s ai: + # 기본(외부) 모델로 사용할 OpenRouter 설정입니다. openai: api-key: ${OPENROUTER_API_KEY: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} base-url: https://openrouter.ai/api/v1 @@ -18,6 +19,13 @@ spring: model: cohere/north-mini-code:free temperature: 0.3 +# 신한라이프 다중 모델 동적 라우팅을 위한 커스텀 설정 +shinhan: + ai: + base-url: https://dev-iam-litellm.shinhanlife.co.kr:18020 + qwen-key: sk-UJ2IRenvaMPbY3ozQdj6zw + gemma-key: sk-EH107wYBZuU6RUTqthR17A + server: port: 8081 http2: diff --git a/dat-gateway/src/main/resources/static/admin/scaffold.html b/dat-gateway/src/main/resources/static/admin/scaffold.html index 73ab883c..b986abb5 100644 --- a/dat-gateway/src/main/resources/static/admin/scaffold.html +++ b/dat-gateway/src/main/resources/static/admin/scaffold.html @@ -953,11 +953,15 @@
diff --git a/dat-gateway/src/main/resources/static/chat.html b/dat-gateway/src/main/resources/static/chat.html index 85dd8440..8d9a6e48 100644 --- a/dat-gateway/src/main/resources/static/chat.html +++ b/dat-gateway/src/main/resources/static/chat.html @@ -88,14 +88,15 @@