spring ai 9일차 / 다중 llm, springai5

2026. 5. 19. 19:17대우개발원 수업 내용/spring기반 ai

반응형

프로젝트 생성


build.gradle에 아래 dependencies  추가

더보기
더보기
// 버전 충돌 방지, IDE 자동완성 안정성 위해 추가
implementation 'org.springframework.ai:spring-ai-client-chat'

application.yaml

더보기
더보기
spring:
  application:
    name: springai5
  thymeleaf:
    cache: false

  ai:
    openai:
      api-key:
    ollama:
      base-url: ${OLLAMA_BASE_URL:http://localhost:11434}

    server:
      port: 8080

    # Spring Boot 의 Actuator 엔드포인트를 웹(HTTP)으로 노출할 범위를 지정
    management:
      endpoints:
        web:
          exposure:
            include: health, info # 서버 상태 확인(헬스 체크), 애플리케이션 정보 확인


    app:
      openai:
        model: gpt-4o-mini
      ollama:
        llama-model: llama3.2
        gemma-model: gemma2

 


llama 3.2 설치


model 패키지 생성 후

ModelResponse record 생성

더보기
더보기
package com.example.springai5.model;

import com.knuddels.jtokkit.api.ModelType;

public record ModelResponse(
        ModelType modelType,
        String content
) {
}

 enum ModelType 생성

더보기
더보기
package com.example.springai5.model;

public enum ModelType {
    OPENAI("OpenAi", "gpt-4o-mini", "☁️"),
    LLAMA("Ollama Llama", "llama3.2", "🦙"),
    GEMMA("Ollama Gemma", "gemma2", "💎");

    private final String displayName;
    private final String modelId;
    private final String icon;

    ModelType(String displayName, String modelId, String icon) {
        this.displayName = displayName;
        this.modelId = modelId;
        this.icon = icon;
    }

    public String getDisplayName() {
        return displayName;
    }
    public String getModelId() {
        return modelId;
    }
    public String getIcon() {
        return icon;
    }


}

advisor 패키지 추가

ModelAuditAdvisor 추가

더보기
더보기
package com.example.springai5.advisor;

import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain;

public class ModelAuditAdvisor implements CallAdvisor {
    private final String modelName;
    private final String roleName;
    private final String icon;

    public ModelAuditAdvisor(String modelName, String roleName, String icon) {
        this.modelName = modelName;
        this.roleName = roleName;
        this.icon = icon;
    }


    //Advisor 이름 반환
    @Override
    public String getName() {return "modleAuditAdvisor";}

    // Advisor 실행 우선순위 // 숫자가 낮을수록 먼저 실행
    @Override
    public int getOrder() {return 0;}

    // 실제 모델 호출 전/후 개입하는 메서드
    @Override
    public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
        // 다음 Advisor 또는 실제 모델 호출 실행
        return chain.nextCall(request);
    }

    public String getModelName() {
        return modelName;
    }

    public String getRoleName() {
        return roleName;
    }

    public String getIcon() {
        return icon;
    }

}

 


 

config 패키지 추가

MultiModelConfig 클래스 추가

더보기
더보기
package com.example.springai5.config;

import com.example.springai5.advisor.ModelAuditAdvisor;
import com.example.springai5.model.ModelType;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaChatOptions;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MultiModelConfig {
    @Value("${spring.ai.openai.api-key:}")
    private String openAiApiKey;

    @Value("${OLLAMA_BASE_URL:http://localhost:11434}")
    private String ollamaBaseUrl;

    @Value("${app.openai.model:gpt-4o-mini}")
    private String openAiModel;

    @Value("${app.ollama.llama-model:llama3.2}")
    private String llamaModel;

    @Value("${app.ollama.gemma-model:gemma2}")
    private String gemmaModel;

    @Bean
    public OpenAiApi openAiApi() {
        return OpenAiApi.builder()
                .apiKey(openAiApiKey)
                .build();
    }

    @Bean("openAiChatModel")
    public OpenAiChatModel openAiChatModel(OpenAiApi openAiApi) {
        return OpenAiChatModel.builder()
                .openAiApi(openAiApi)
                .defaultOptions(OpenAiChatOptions.builder()
                        .model(openAiModel)
                        .temperature(0.7)
                        .build())
                .build();
    }

    @Bean("openAiChatClient")
    @Primary
    public ChatClient openAiChatClient(
            @Qualifier("openAiChatModel") OpenAiChatModel openAiChatModel) {
        return ChatClient.builder(openAiChatModel)
                .defaultSystem("You are a helpful AI assistant. Answer in Korean unless specified otherwise.")
                .defaultAdvisors(new ModelAuditAdvisor(
                        ModelType.OPENAI.getDisplayName(),
                        "기본 어시스턴트",
                        ModelType.OPENAI.getIcon()))
                .build();
    }

    @Bean
    public OllamaApi ollamaApi() {
        return OllamaApi.builder()
                .baseUrl(ollamaBaseUrl).build();
    }


    @Bean("llamaChatModel")
    public OllamaChatModel ollamaChatModel(OllamaApi ollamaApi) {
        return OllamaChatModel.builder()
                .ollamaApi(ollamaApi)
                .defaultOptions(OllamaChatOptions.builder()
                        .model(llamaModel)
                        .temperature(0.7)
                        .build())
                .build();
    }

    @Bean("llamaChatClient")
    public ChatClient llamaChatClient(
            @Qualifier("llamaChatModel") OllamaChatModel llamaChatModel) {
        return ChatClient.builder(llamaChatModel)
                .defaultSystem("You are a helpful AI assistant. Answer in Korean unless specified otherwise.")
                .defaultAdvisors(new ModelAuditAdvisor(
                        ModelType.LLAMA.getDisplayName(),
                        "기본 어시스턴트",
                        ModelType.LLAMA.getIcon()))
                .build();
    }


    @Bean("gemmaChatModel")
    public OllamaChatModel gemmaChatModel(OllamaApi ollamaApi) {
        return OllamaChatModel.builder()
                .ollamaApi(ollamaApi)
                .defaultOptions(OllamaChatOptions.builder()
                        .model(gemmaModel)
                        .temperature(0.7)
                        .build())
                .build();
    }


    @Bean("gemmaChatClient")
    public ChatClient gemmaChatClient(
            @Qualifier("gemmaChatModel") OllamaChatModel gemmaChatModel) {
        return ChatClient.builder(gemmaChatModel)
                .defaultSystem("You are a helpful AI assistant. Answer in Korean unless specified otherwise.")
                .defaultAdvisors(new ModelAuditAdvisor(
                        ModelType.GEMMA.getDisplayName(),
                        "기본 어시스턴트",
                        ModelType.GEMMA.getIcon()))
                .build();
    }
}