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["응답"]적용 방법 | 설명 |
|---|---|
|
|
| 특정 요청에만 적용 |
| 체인에서의 순서. 값이 작을수록 먼저 실행 |
2. 내장 어드바이저 — SimpleLoggerAdvisor
Spring AI가 기본 제공하는 어드바이저다. 요청과 응답을 로그로 남긴다. 별도 구현 없이 등록만 하면 된다.
ChatClient.Builder builder ...
this.chatClient = builder
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();로그를 보려면 해당 패키지의 레벨을 DEBUG로 올린다.
logging:
level:
org.springframework.ai.chat.client.advisor: DEBUGDEBUG 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;
}
}메서드 | 시점 | 할 수 있는 일 |
|---|---|---|
| 모델 호출 전 | 프롬프트 수정, 컨텍스트 주입, 검증/차단 |
| 모델 호출 후 | 응답 가공, 로깅, 후처리 |
| — | 체인 내 실행 순서 결정 |
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의 확장이 한눈에 들어온다.
전체 목차
① 소개와 모델 세팅 · ② 채팅 · ③ 프롬프트 · ④ 구조화 출력 · ⑤ Tool Calling · ⑥ RAG · ⑦ 이미지 · ⑧ 음성 · ⑨ Chat Memory · ⑩ Advisor