@Configuration
@Slf4j
@RequiredArgsConstructor
public class AiConfig {
@Bean
OpenAiChatModel openAiChatModel(@Value("${spring.ai.openai.api-key}") String apiKey) {
// API + Option > ChatModel
OpenAiApi api = OpenAiApi.builder().apiKey(apiKey).build();
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("gpt-4o-mini")
.temperature(0.8)
.build();
return OpenAiChatModel.builder().openAiApi(api).defaultOptions(options).build();
}
@Bean
ChatClient openAiChatClient(OpenAiChatModel chatModel) {
// ChatModel > ChatClient
return ChatClient.builder(chatModel).build();
}
// OllamaChatModel 빈을 생성하는 템플릿 메서드
private OllamaChatModel getOllamaChatModel(String baseUrl, String model) {
// 접속 대상 서버 정보
OllamaApi api = OllamaApi.builder().baseUrl(baseUrl).build();
OllamaOptions options = OllamaOptions.builder().model(model).temperature(0.7).build();
return OllamaChatModel.builder().ollamaApi(api).defaultOptions(options).build();
}
@Bean
ChatClient ollamaGemma3nChatClient(@Value("${spring.ai.ollama.base-url}") String baseUrl){
return ChatClient.builder(getOllamaChatModel(baseUrl, "gemma3n:e4b")).build();
}
@Bean
ChatClient ollamaDeepSeekR1ChatClient(@Value("${spring.ai.ollama.base-url}") String baseUrl) {
return ChatClient.builder(getOllamaChatModel(baseUrl, "qwen3:8b")).build();
}
}
@Value("${quietjun.ai.system-prompt}")
private String systemPrompt;
@Value("${spring.ai.ollama.base-url}")
String baseUrl;
private ChatClient getOllamaChatClient(String name) {
// baseUrl 설정을 통해 Ollama 서비스와 연결
OllamaApi api = OllamaApi.builder().baseUrl(baseUrl).build();
// OllamaApi와 연결된 모델 생성
ChatModel model = OllamaChatModel.builder().ollamaApi(api).build();
// 모델을 통해서 생성되는 ChatClient에 기본 속성 적용
return ChatClient.builder(model)
defaultSystem(c -> c.text(systemPrompt)
.param("language", "korean").param("character", "chill"))
.defaultOptions(OllamaOptions.builder().model(name).temperature(0.1).build())
.defaultAdvisors(new SimpleLoggerAdvisor()).build();
}
@Bean
ChatClient ollamaGemma3ChatClient() {
return getOllamaChatClient("gemma3:4b-it-qat");
}
| 메시지 타입 | 설명 |
|---|---|
| SystemMessage (System Role) | 대화를 시작하기 전에 AI에게 지침을 제공하는 역할. AI의 행동, 응답 스타일, 규칙 등을 설정함. 모델이 입력을 해석하고 응답하는 방식에 대한 기준을 정의함. 예) “친절하게 단계별로 질문에 답변하고 표 형식으로 결과를 반환해줘.” |
| UserMessage (User Role) | 사용자가 AI에게 전달하는 질문 또는 요청. 모델이 작업을 수행하거나 응답을 생성하기 위한 핵심 입력 정보. 예) “오늘 날씨 어때?”, “한강 작가의 도서 목록을 알려줘.” |
| AssistantMessage (Assistant Role) | 사용자의 입력에 대한 AI의 응답. 이 응답은 이후 대화의 맥락(context)으로 다시 활용될 수 있음. Tool 호출 요청 정보도 포함될 수 있음. |
| ToolResponseMessage (Tool Role) | Tool 호출 결과로 생성되는 메시지. 외부 API나 함수 실행 결과를 포함하며, 이후 모델이 응답을 생성하는 데 추가 컨텍스트로 사용됨. |
# application.properties
# system prompt
quietjun.ai.system-prompt=You are an artificial intelligence known as an omniscient scholar.
When you speak, use {language} and answer with a {character} personality.
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions chatOptions;
}
참고 https://github.com/camp-robbie/spring-ai-study
https://docs.spring.io/spring-ai/reference/2.0/api/chatclient.html 까지 읽었다!