CoT와 React 패턴 적용
CoT(Chain-of-Thought) 적용
CoT란?
CoT(Chain-of-Thought)는 사용자의 질문에 대해 단계적 사고 절차를 모델 내부에서 수행하도록 유도하는 프롬프트 기법이다.
핵심은 생각은 내부에서 정리하고, 최종 답만 출력하게 만드는 것이다.
사고 절차 흐름은 다음과 같다.
의도 파악 → 필요한 데이터 확인 → 도구 선택 및 실행 → 결과 통합 → 검증
CoT 적용 전
“안녕하세요!” 같은 단순한 인사에도 장황한 답변이 반복되었고, 불확실한 경우에는 “정보가 부족합니다.”를 과도하게 남발했다.

String prompt = """
아래는 사용자와 챗봇 간의 최근 대화 내용입니다.
대화의 흐름을 이해하고, 사용자의 질문에 답변하세요.
대화 내역:
%s
사용자 요청:
%s
응답 지침:
- 대화의 맥락을 유지하면서 자연스럽게 응답하세요.
- 경기, 팀 관련 데이터는 사실에 기반해 답변하세요.
- 불확실한 정보일 경우 추측하지 말고 "정보가 부족합니다."라고 답변하세요.
- 답변은 한국어로 작성하세요.
""".formatted(historyText, userMessage);
이전에는 단순히 “정보 부족 시 응답 제한”만 설정되어 내부적 사고 과정 없이 즉각적인 문장 생성이 이루어졌다.
CoT 적용 후
아래와 같이 모델 내부 사고 절차와 검증 체크리스트, 최종 출력 규칙을 명시한 시스템 프롬프트를 추가했다.
String system = """
너는 e스포츠 도메인 어시스턴트다.
[사고 지침(내부)]
- 질문을 1) 의도 파악 → 2) 필요 데이터 확인 → 3) 툴 선택/인자 결정 → 4) 결과 통합 → 5) 검증 체크리스트 순으로 생각한다.
- 필요한 경우에만 툴을 호출한다. 툴 결과의 범위/단위/시간대를 점검한다.
- 모순되면 재검토하고, 데이터가 부족하면 부족하다고 말한다.
[출력 지침(외부)]
- 최종 한국어 답변만 출력한다. 중간 사고 과정, 단계적 이유, 체크리스트는 출력하지 않는다.
- 간결하지만, 사용자에게 실용적인 요약/근거(출처 유형)를 포함한다.
[툴 사용 원칙]
- 일정/승률/예측 등 사실 확인이 필요하면 제공된 툴을 사용한다.
- 한 번에 여러 툴이 필요하지 않다면 호출을 최소화한다.
""";
String prompt = """
[최근 대화]
%s
[사용자 요청]
%s
""".formatted(historyText, userMessage);


이후부터는 모델이 응답 전 내부적으로 의도 분석 → 도구 판단 → 결과 검증 단계를 거치며, 불필요한 문장 없이 핵심적인 답변만 출력하게 되었다.
결과
- 인사나 단순 질의에 대해 군더더기 없는 자연스러운 응답으로 개선
- 잘못된 데이터나 시간대 불일치 상황에서도 추론 및 검증 후 올바른 툴 호출 수행
- 프롬프트에 사고 절차와 검증 기준을 명시하는 것만으로 응답 품질 안정성이 크게 향상되었다
React 적용 정리
React란?
React(Reason + Act)는 LLM이 질문을 이해하고 필요한 정보를 판단한 뒤, 적절한 도구를 호출하여 데이터를 얻고 결과를 관찰해 최종 답을 작성하는 일련의 사고 절차를 말한다.
즉, “사고 → 행동 → 관찰 → 최종 답”의 구조를 구현한 것이다.
구성 요소
React 구조에서는 모델이 여러 종류의 도구를 상황에 맞게 활용한다.
- DB 조회 도구: 경기 일정, 승패 기록, 승률 요약 등 내부 데이터 접근
- 외부 API 도구: 외부 일정, 뉴스, 배당 정보 등 Web API 호출
- 계산/정규화 도구: 승률 계산, 날짜 해석 등 비즈니스 로직 처리
Spring AI Tool Calling
수동 JSON 오케스트레이션 없이, Spring AI가 제공하는 tool calling을 사용했다.
@Tool 메서드로 툴을 노출하고 모델이 필요 시 자동으로 툴을 호출하고 결과를 재주입해 최종 답을 만든다.
툴 정의 예시
@Tool(
name = "query_schedule",
description = "날짜 표현(오늘/내일/어제/이번주/지난주/주말)을 해석해 해당 기간의 경기 일정을 조회한다."
)
public ScheduleResponse querySchedule(
@ToolParam(description = "예: 오늘/내일/어제/이번주/지난주/주말", required = false)
String when
) {
String w = (when == null || when.isBlank()) ? "오늘" : when.trim();
LocalDate today = LocalDate.now();
LocalDateTime start;
LocalDateTime end;
// 중간 로직...
List<Match> matches = matchRepository.findByStartTimeBetweenOrderByStartTimeAsc(start, end);
if (matches.isEmpty()) {
return ScheduleResponse.noMatch(w, start, end, "해당 기간에 등록된 일정이 없습니다.");
}
List<ScheduleItem> items = matches.stream()
.map(ScheduleItem::of)
.toList();
return ScheduleResponse.of(items, w, start, end);
}
CallResponseSpec call = chatClient
.prompt(prompt)
.system(system)
.tools(scheduleTools, winRateTools)
.call();
동작 흐름
1. 프롬프트 구성
system에는 CoT 지침(의도 → 정보 확인 → 선택적 도구 사용 → 결과 통합 → 검증 → 최종 출력)을 포함
prompt에는 최근 대화와 사용자의 질문을 포함한다.
2. 툴 스키마 노출
`@Tool`이 붙은 메서드는 Spring AI가 자동으로 스키마를 생성하여 모델에 전달한다.
3. 모델 판단(Reason)
질문의 의미를 해석하고, 툴이 필요한지 여부를 스스로 판단한다.
툴 설명에 명시된 키워드(예: “오늘”, “이번주”)가 있을 경우 모델이 더 정확히 선택한다.
4. 도구 실행(Act)
모델이 툴 사용을 결정하면 Spring AI가 해당 메서드를 자동 실행한다.
5. 결과 관찰 및 응답 생성
툴의 결과가 모델 입력에 다시 주입되고, 모델이 이 데이터를 바탕으로 최종 한국어 응답을 생성한다.
적용 효과
- 도구 호출 시 직접 JSON 파싱/오케스트레이션 불필요
- 모델이 상황에 따라 동적으로 도구를 선택해 실행
- CoT 지침과 결합 시 불필요한 호출 최소화, 응답 품질 향상
- Spring 환경에서 AI + 비즈니스 로직 간 결합도 최소화
마치며
이번 CoT와 React 적용을 통해 챗봇이 단순 텍스트 생성 수준을 넘어 사고하고 행동하는 에이전트로 발전했다.
CoT는 내부 사고의 구조화를, React는 외부와의 상호작용(도구 실행)을 담당한다.
결국 두 요소를 함께 설계함으로써 Spring AI 기반 챗봇의 응답 정확도와 일관성이 한 단계 향상되었다.
'TIL' 카테고리의 다른 글
| 11/7 (0) | 2025.11.07 |
|---|---|
| 11/6 (0) | 2025.11.06 |
| 11/4 (0) | 2025.11.04 |
| Spring Boot 성능 최적화 7 (0) | 2025.11.03 |
| Spring Boot 성능 최적화 6 (0) | 2025.10.31 |