샘플데이터베이스
postgresql용도 데이터베이스 샘플인 dvdrental 을 활용

PostgreSQL Sample Database
This tutorial introduces you to a PostgreSQL sample database that you can use for learning and practicing with PostgreSQL.
neon.com
구현
Prompt
sqlTool 에 기능을 분류하여 agent가 테이블 스키마를 조회하고 테이블을 조죄할 수 있도록 했다.
그리고 잘못된 컬럼을 요청했을 때 자기 수정 규칙을 두어 최대 3번까지 수정을 재시도할 수 있다.
당신은 PostgreSQL 전문가입니다. 데이터베이스 이름은 'aidb'이며, DVD 대여 시스템입니다.
1. [탐색]: 질문에 관련된 테이블이 무엇인지 'listTables'로 확인합니다.
2. [분석]: 해당 테이블의 구조를 'describeTable'로 파악하여 정확한 컬럼명을 확인합니다.
3. [계획]: 위 정보를 바탕으로 쿼리 실행 순서를 계획합니다.
4. [실행]: 'executeSqlQuery'로 최종 데이터를 가져옵니다.
반드시 제공된 도구를 사용해 SQL을 실행한 후, 그 결과를 바탕으로 자연스럽게 답변하세요.
[자기 수정 규칙]
1. 'executeSqlQuery' 실행 결과 'SQL 에러 발생'이 포함되어 있다면, 에러 메시지를 분석하세요.
2. 잘못된 컬럼명이나 테이블명 때문이라면, 스키마를 추측하지 말고 information_schema를 조회하거나 쿼리를 수정하세요.
3. 최대 3번까지 수정을 시도할 수 있습니다.
4. 최종적으로 성공한 결과만 요약해서 사용자에게 전달하세요.
승인 Service
그리고 생성된 쿼리를 DB에 수행요청 하기 전에 사용자에게 승인을 위임한다.
사용자는 60sec 이내에 승인API를 전송해야한다.
approvalService.request(chatId, query).get(60, TimeUnit.SECONDS);
agent.service.ApprovalService.java
// AI가 호출: 승인 요청을 등록하고 UI에 알림
public CompletableFuture<Boolean> request(String chatId, String query) {
String id = UUID.randomUUID().toString().substring(0, 8);// 60초 후 자동 만료되는 로직 추가 (Optional)
CompletableFuture<Boolean> future = new CompletableFuture<Boolean>()
.orTimeout(60, TimeUnit.SECONDS);
pendingApprovals.put(id, future);
// 1. DTO 객체 생성
ApprovalRequest approvalRequest = ApprovalRequest.builder()
.id(id)
.query(query)
.message("쿼리가 생성되어 사용자 승인을 기다립니다.")
.requestedAt(LocalDateTime.now())
.build();
// ⭐️ 해당 ChatId에 연결된 Sink를 찾아 데이터 방출
Sinks.Many<ApprovalRequest> sink = userSinks.get(chatId);
if (sink != null) {
Sinks.EmitResult result = sink.tryEmitNext(approvalRequest);
log.info("📢 [백엔드] ChatId: {} 에게 승인 요청 전송 - ID: {}, 결과: {}", chatId, id, result);
} else {
log.warn("⚠️ ChatId: {} 에 대한 활성화된 구독자가 없습니다.", chatId);
// 구독자가 없으면 즉시 실패 처리하거나 로직에 따라 조절
future.complete(false);
}
return future;
}
승인 요청 화면
채팅이 생성되면 클라이언트는 서버에 sse 구독을 해놓고,
서버가 sse를 전달하면 modal event가 발생되어 생성된 쿼리를 보여준다.

승인API
agent.web.ApprovalUiController.java
// 2. UI 버튼 클릭 시 호출
@PostMapping("/{id}/respond")
public Mono<ResponseEntity<String>> respond(@PathVariable("id") String id,
@RequestParam("approved") boolean approved) {
return Mono.just(id)
.publishOn(Schedulers.boundedElastic()) // 승인 처리를 별도 스레드에서 수행
.map(requestId -> {
approvalService.handleDecision(requestId, approved);
return ResponseEntity.ok("Success");
});
}
agent.web.ApprovalService.java
// 1. UI로 실시간 알림을 보내기 위한 통로 (SSE)
private final Map<String, Sinks.Many<ApprovalRequest>> userSinks = new ConcurrentHashMap<>();
// 2. 대기 중인 요청 저장소
private final Map<String, CompletableFuture<Boolean>> pendingApprovals = new ConcurrentHashMap<>();
// UI 버튼 클릭 시 호출: 승인 또는 취소
public void handleDecision(String id, boolean approved) {
log.info("📥 [백엔드] 결정 수신 - ID: {}, 승인여부: {}", id, approved);
CompletableFuture<Boolean> future = pendingApprovals.get(id);
if (future != null) {
future.complete(approved);
pendingApprovals.remove(id); // 결정 완료 후 삭제
} else {
log.warn("⚠️ 이미 만료되었거나 존재하지 않는 승인 ID입니다: {}", id);
}
}
상태를 complete로 만들어 중단되었던 쿼리를 수행한다.
검색해보기
이제 이런 검색을 해볼 수 있다!!
기초 조회
- "영화(film) 테이블에서 상영 시간이 180분 이상인 영화 제목 5개만 알려줘.”
- "특정 조건 + 리미트
통계/집계
- "우리 서비스에 등록된 전체 고객(customer)은 총 몇 명이야?"
- COUNT 함수 유도
조인(Join)
- "가장 많이 대여(rental)된 영화 제목 TOP 3가 뭐야?"
- film + inventory + rental 조인
수익 분석
- "각 영화 카테고리별로 총 매출(payment) 합계를 계산해줘."
- category + payment 집계
고객 분석
- "이메일 주소가 'P'로 시작하는 고객들의 이름과 성을 나열해줘."
- LIKE 패턴 검색
에이전트 협업
더 나아가 분석된 데이터를 수치화 할 수도 있다.
chartService 를 만들어 놨는데 "차트" 라는 단어가 질문에 포함되어있을 경우 sql+chart 두개의 Tool을 사용하도록 만들었다.



GitHub - joonhyeok95/spring-ai-google-gen: 제미나이 무료API로 구현하는 PDF RAG, 데이터베이스 추출, LLM 서비
제미나이 무료API로 구현하는 PDF RAG, 데이터베이스 추출, LLM 서비스. Contribute to joonhyeok95/spring-ai-google-gen development by creating an account on GitHub.
github.com
'개발 > Spring' 카테고리의 다른 글
| [Spring AI] 4편: MCP 서버 구동과 실행 (0) | 2026.03.20 |
|---|---|
| [Spring AI] 2편: RAG 문서 임베딩 (0) | 2026.03.20 |
| [Spring AI] 1편: 토이 프로젝트 개요 (0) | 2026.03.20 |
| [Springboot] @JsonProperty는 언제 써야 할까! (0) | 2023.02.22 |
| [MSA] SAGA pattern (0) | 2022.12.19 |