[Springboot] Spring AI ChatClient 사용법과 오류 해결 :: 매운코딩
300x250

Spring AI ChatClient 사용법과 오류 해결

Spring AI에서 ChatClient를 org.springframework.ai.chat.client.ChatClient 못찾는 오류 해결법을 작성해본다.

기본 사용법부터 실전 예제, 그리고 그 유명한 클래스패스 오류까지 차근차근 풀어보자.

ChatClient 기본 개념과 생성

ChatClient는 Spring AI에서 AI 모델과 대화할 때 쓰는 fluent API다. ChatModel 위에 쌓여 있어서 Prompt를 메시지 단위로 쉽게 조립하고, 동기/스트리밍 둘 다 지원한다.

가장 간단한 생성법은 Spring Boot 자동 구성 쓰는 거. Controller에서 ChatClient.Builder를 주입받아서 build하면 된다.

@RestController
class MyController {
    private final ChatClient chatClient;

    public MyController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    @GetMapping("/ai")
    String generate(@RequestParam String message) {
        return this.chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

여기서 .prompt().user(message).call().content() 흐름이 핵심이다. user()로 사용자 메시지 넣고 call() 치면 AI 응답이 String으로 나온다. 

시스템 메시지와 파라미터 넣기

실무에선 시스템 프롬프트 없으면 안 된다. 기본 시스템 메시지 설정하거나 동적으로 param 넣을 수 있다.

@Bean
ChatClient chatClient(ChatClient.Builder builder) {
    return builder
            .defaultSystem("너는 {voice}처럼 말하는 챗봇이야.")
            .build();
}

Controller에서 쓰려면:

@GetMapping("/ai/chat")
Map<String, String> chat(@RequestParam String message, @RequestParam String voice) {
    return Map.of("response",
            chatClient.prompt()
                    .system(sp -> sp.param("voice", voice))
                    .user(message)
                    .call()
                    .content());
}

.system()에 람다로 param 주입하는 게 포인트. 공식 문서에 따르면 이렇게 하면 템플릿처럼 동작한다. voice가 "친근하게"면 그에 맞춰 응답 나온다.

스트리밍 응답 예제

Flux로 실시간 스트리밍 하려면 .stream() 쓰면 된다. 채팅 앱에서 딱이다.

@GetMapping("/stream")
Flux<String> stream(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .stream()
            .content();
}

이거 연결해서 WebFlux 쓰면 토큰 단위로 응답이 쭉 흘러간다. 배포해보니 OpenAI 모델에서 특히 빠르게 느껴지더라.

"ChatClient that could not be found" 오류 해결

이 오류는 대체로 의존성 누락이나 버전 충돌, 자동 구성 실패 때 뜬다. 나도 OpenAI starter 추가했는데 뜨길래 pom.xml부터 확인했다.

1. 의존성 확인

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0-M1</version>  <!-- 최신 버전으로 -->
</dependency>

spring-ai-openai만 넣으면 ChatClient 패키지가 안 잡힌다. starter 버전 써야 자동 구성 된다.^1_4

2. Builder 주입 문제
Controller에서 private ChatClient.Builder chatClientBuilder; 필드 선언하고 @Autowired 안 하면 NullPointer. 생성자 주입으로:

public MyController(ChatClient.Builder builder) {
    this.chatClient = builder.build();
}

직접 필드에 넣지 말고 생성자에서 build.

3. 여러 ChatModel 있을 때
OpenAI + Ollama 두 개 쓰면 "No qualifying bean of type 'ChatModel'" 뜬다. 각 모델별 ChatClient 빈 따로 만들어:

@Bean
@Qualifier("openai")
ChatClient openAiClient(ChatClient.Builder builder) {
    return ChatClient.builder(openAiChatModel).build();
}

@Bean
@Qualifier("ollama")
ChatClient ollamaClient(OllamaChatModel ollamaModel) {
    return ChatClient.create(ollamaModel);
}

그리고 Controller에서 @Qualifier로 지정. 이게 제일 깔끔하다.^1_2

4. Milestone 리포지토리 추가

<repositories>
    <repository>
        <id>spring-milestones</id>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

M1, RC1 같은 버전은 여기서 끌어온다.

놓치기 쉬운 팁

  • ChatClient는 프로토타입 빈이라 매번 새로 build 가능. 싱글톤으로 고정 안 해도 된다.
  • .advisor()로 메모리나 RAG 추가 쉬움. 예: .advisor(new ChatMemoryAdvisor(chatMemory))
  • application.yml에 spring.ai.openai.api-key 설정 잊으면 런타임에서 터짐.

이렇게 해보니 안정적으로 돌아가더라. 공식 문서 예제 따라 하다 막히는 부분 위주로 정리해봤다. 실제 프로젝트에 넣어보고 싶으면 OpenAI 키부터 세팅해보시라.
^1_10^1_7^1_9

728x90
728x90

+ Recent posts