10일 차 TIL
목표
1. Spring 심화 숙제 풀기 -> v
2. Spring AI 사전 설정 -> v
3. MSA 수강 진행 -> x
내일 할 것 : MSA 강의 수강 진행
Spring 심화 숙제
만약 Controller 별로 사용시간을 저장하는 것이 아니라 특정 API들만 저장을 한다면?
물론 @Pointcut을 사용해서 메서드도 지정할 수 있습니다.
하지만 시간을 측정하려는 메서드들의 이름이 통일되어있지 않고 여러 Controller에 산재해 있다면?
애너테이션을 직접 구현하여 AOP를 적용하는 방법을 구글링하여 찾아본 후 프로젝트에 적용해 보세요!
- Timer 애너테이션을 만듭니다.
- TimerAop 클래스를 만들고 Timer 애너테이션에 AOP를 적용합니다.
- Timer 애너테이션을 사용하여 상품 검색 API가 호출될 때만 사용시간이 저장될 수 있도록 설정해 봅니다.
+) 확인을 위해 UseTimeAop는 적용되지 않도록 @Component 애너테이션을 주석합니다.
제출 파일
- Timer.java
- TimerAop.java
- NaverApiController.java
1. Timer를 클래스가 아닌 @interface로 만들면 커스텀 애노테이션을 만들 수 있다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
2. @Around의 파라미터로 @annotaion(timer)를 설정할 수 있다.
즉 해당 애노테이션이 붙은 위치 전후로 실행된다.
@Slf4j(topic = "TimerAop")
@Aspect
@Component
@RequiredArgsConstructor
public class TimerAop {
private final ApiUseTimeRepository apiUseTimeRepository;
@Around("@annotation(timer)")
public Object execute(ProceedingJoinPoint joinPoint, Timer timer) throws Throwable {
// 측정 시작 시간
long startTime = System.currentTimeMillis();
try {
// 핵심기능 수행
Object output = joinPoint.proceed();
return output;
} finally {
// 측정 종료 시간
long endTime = System.currentTimeMillis();
// 수행시간 = 종료 시간 - 시작 시간
long runTime = endTime - startTime;
log.info("[TimerAop] Method: {} executed in {} ms",
joinPoint.getSignature().toShortString(), runTime);
}
}
}
}
위 코드는 @Timer가 붙은 메서드가 실행될 때, 수행시간에 대한 로그를 찍는다.
3. 컨트롤러에서 사용할 메서드에 적용
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class NaverApiController {
private final NaverApiService naverApiService;
@Timer
@GetMapping("/search")
public List<ItemDto> searchItems(@RequestParam String query) {
return naverApiService.searchItems(query);
}
}
searchItems() 메서드 실행 전 후로 TimerAop에서 설정한 execute() 메서드가 실행된다.
Spring AI 기초
Spring AI는
1. 프레임워크 : 여러 AI모델(Gpt, Claude, Gemini, Ollama 등)의 공통된 틀(인터페이스) = 추상화
2. 편의기능
을 제공한다.
Python -> LangChain
Ollama는 무료지만, 하드웨어 요구사항이 높아서 사용하기 힘들다.
따라서 유료지만 Gpt를 선택
모델에게 요청을 보낼 때는 ChatModel 인터페이스를 사용
call은 기본 String 반환, 동기방식
stream은 Flux<String> 반환, 비동기방식
프롬프트 3대 요소
1. 상황 (Context) => SystemMessage
- 역할 부여 : 너는~~전문가야
- 배경 지식 : AI가 업데이트 하고 난 후의 최신정보?
- 지시 사항 : 순서, 톤 등
2. 내용 (Task) => UserMessage
- 사용자의 질의
3. 형식 (Format) => AssistantMessage
- 응답 스키마 : 3가지 중 한 가지로 답해줘, 특정 객체로 답해줘 등
추가로 외부 도구 실행 후 전달되는 결과 값은 ToolResponseMessage로 받는다.
Re Act
추론 행동/도구
모델의 실행 결과를 Flux<String>으로 받을 때,
응답 Content-type 중
application/x-ndjson 사용할 수 있다.
ndjson은 Newline - Delimitted JSON를 뜻함
{키:값,_,_},
{키:값,_,_},
{키:값,_,_} 형태의 JSON이 반복되는 구조
ChatModel vs ChatClient
저수준 / 고수준
ChatClient는 메서드 체이닝, 즉 Fluent API
A2A
Agent to Agent
즉, ChatClient를 새로 만들어서 사용할 때,
여러 ChatClient를 사용할 때 사용한다. 즉 모델을 여러 개 사용할 때
@Service
class ChatService {
private final ChatClient chatClient;
public ChatService(ChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel).build();
}
}
프롬프트 엔지니어링?
3대 구성요소에 맞게 어떻게 작성하는가, 작성 기법?
1. 제로-샷
LLM이 가지고 있는 지식만으로 답변
2. 퓨-샷
응답 예시를 1개 이상 전달해 줌
3. 스텝-백
질의->일반적인 원리, 배경지식 도출 재 질문(LLM)-> 재질문 + 원래 질문을 합쳐서 다시 질문함. ( 총 3번 )
4. 생각의 사슬(cot)
추론의 근거, 단계별 추론 내용을 나열하게 함
5. 자기 일관성
다수결, 같은 질문을 여러 번 해서 가장 많이 나온 답변을 선택
6. 역할 부여
역할을 지정해서, 해당 context로 한정시켜서 답변하게 유도함
converter : 개발자는 데이터가 필요해서, 결과를 자바 객체로 반환하는 과정
- BeanOutputConverter
Advisor : LLM 요청 전 후의 기능을 구현할 때 사용, AOP를 활용
- CallAdvisor
'내배캠' 카테고리의 다른 글
| [내일배움캠프 본캠프] 12일 차 TIL MSA (0) | 2026.02.21 |
|---|---|
| [내일배움캠프 본캠프] 11일 차 TIL MSA, Git flow (0) | 2026.02.20 |
| [내일배움캠프 본캠프] 9일 차 TIL 소셜 로그인(OAuth), 단위 테스트, AOP, 예외 처리 (0) | 2026.02.18 |
| [내일배움캠프 본캠프] 8일 차 TIL 페이징처리, 다대다, AWS (0) | 2026.02.17 |
| [내일배움캠프 본캠프] 7일 차 TIL 지연로딩, cascade, scheduler, 헤더 JWT (0) | 2026.02.16 |
