Spring AI

Advisor(어드바이저)

Advisor는 LLM 호출의 앞(before)과 뒤(after)에 끼어드는 인터셉터다. 스프링 MVC의 인터셉터나 AOP와 같은 발상으로, 핵심 호출 코드는 그대로 두고 공통 관심사(로깅·말투 통일·검열·재시도·RAG·메모리)를 끼워 넣는다. 사실 앞서 본 RAG와 Chat Memory도 모두 어드바이저로 구현돼 있었다.

이 편에서 만드는 것

내장 SimpleLoggerAdvisor와 직접 만든 PoliteAdvisor를 체인으로 거는 /advisor/ask 엔드포인트.


1. 어드바이저 체인

요청은 등록된 어드바이저들을 순서대로 통과해 모델에 도달하고, 응답은 그 역순으로 되돌아 나온다.

flowchart LR
    Req["요청"] --> A1["Advisor 1<br/>before"]
    A1 --> A2["Advisor 2<br/>before"]
    A2 --> LLM["모델 호출"]
    LLM --> A2b["Advisor 2<br/>after"]
    A2b --> A1b["Advisor 1<br/>after"]
    A1b --> Res["응답"]

적용 방법

설명

.defaultAdvisors(...)

ChatClient.Builder에 등록 → 모든 요청에 적용

.advisors(...)

특정 요청에만 적용

getOrder()

체인에서의 순서. 값이 작을수록 먼저 실행


2. 내장 어드바이저 — SimpleLoggerAdvisor

Spring AI가 기본 제공하는 어드바이저다. 요청과 응답을 로그로 남긴다. 별도 구현 없이 등록만 하면 된다.

ChatClient.Builder builder ...
this.chatClient = builder
        .defaultAdvisors(new SimpleLoggerAdvisor())
        .build();

로그를 보려면 해당 패키지의 레벨을 DEBUG로 올린다.

logging:
  level:
    org.springframework.ai.chat.client.advisor: DEBUG
DEBUG o.s.a.c.c.advisor.SimpleLoggerAdvisor : request: ChatClientRequest[prompt=Prompt{...}]
DEBUG o.s.a.c.c.advisor.SimpleLoggerAdvisor : response: {...}

다른 내장 어드바이저들

SafeGuardAdvisor(금칙어 차단), MessageChatMemoryAdvisor(대화 기억), QuestionAnswerAdvisor(RAG) 등도 모두 어드바이저다. 새 의존성 없이 조합만으로 기능을 더할 수 있다.


3. 커스텀 어드바이저 — BaseAdvisor

BaseAdvisor를 구현하면 before/after 두 지점에 로직을 넣을 수 있다. 아래 PoliteAdvisor는 호출 전에 system 메시지를 가로채 규칙을 주입해, 모든 답변의 말투를 통일한다.

@Component
public class PoliteAdvisor implements BaseAdvisor {

    /** 호출 전: 프롬프트를 가로채 system 지시를 주입한다. */
    @Override
    public ChatClientRequest before(ChatClientRequest request, AdvisorChain chain) {
        Prompt augmented = request.prompt().augmentSystemMessage(
                "항상 정중한 존댓말로 답하고, 답변 맨 끝에 이모지 '😊'를 붙여라.");
        return new ChatClientRequest(augmented, request.context());
    }

    /** 호출 후: 응답을 가로챌 수 있다(여기선 그대로 통과). */
    @Override
    public ChatClientResponse after(ChatClientResponse response, AdvisorChain chain) {
        return response;
    }

    /** 체인에서의 실행 순서(작을수록 먼저). */
    @Override
    public int getOrder() {
        return 0;
    }
}

메서드

시점

할 수 있는 일

before

모델 호출 전

프롬프트 수정, 컨텍스트 주입, 검증/차단

after

모델 호출 후

응답 가공, 로깅, 후처리

getOrder

—

체인 내 실행 순서 결정


4. 체인으로 묶기

여러 어드바이저를 한 번에 등록하면 체인이 된다.

public AdvisorController(ChatClient.Builder builder, PoliteAdvisor politeAdvisor) {
    this.chatClient = builder
            .defaultAdvisors(
                    new SimpleLoggerAdvisor(),   // 내장: 로깅
                    politeAdvisor)               // 커스텀: 말투 통일
            .build();
}
curl -G "http://localhost:8080/advisor/ask" --data-urlencode "message=스프링이 뭐야? 짧게."
# 스프링(Spring)은 자바 기반의 프레임워크로 ... 효율적인 개발 환경을 제공합니다. 😊

답변이 존댓말로 끝나고 😊가 붙었다 — PoliteAdvisor의 before가 system 지시를 주입했기 때문이다. 동시에 콘솔에는 SimpleLoggerAdvisor의 요청/응답 로그가 남는다.

어드바이저로 분리하면 좋은 것들

토큰 사용량 측정, 민감정보 마스킹, 프롬프트 버전 관리, A/B 테스트, 응답 캐싱 등 여러 서비스에 공통으로 필요한 횡단 관심사. 비즈니스 로직을 더럽히지 않고 한 곳에 모아 둘 수 있다.


정리

  • 어드바이저는 LLM 호출의 before/after에 끼어드는 인터셉터다.

  • 내장(SimpleLoggerAdvisor·SafeGuardAdvisor 등)을 등록만으로 쓰거나, BaseAdvisor로 직접 만든다.

  • .defaultAdvisors(전체)·.advisors(요청별)로 적용하고 getOrder로 순서를 정한다.

  • RAG·Memory도 결국 어드바이저다 — 이 메커니즘을 이해하면 Spring AI의 확장이 한눈에 들어온다.

마지막 수정 2026년 10월 22일