treeru.com
AI

Text2SQL 실전 테스트 — LLM이 SQL을 직접 작성하면

2026-03-04
Treeru

"카페 아메리카노 가격이 얼마예요?"라는 질문에 LLM은 4,500원이라고 환각을 만들어냅니다. RAG는 문서에서 근거를 찾지만, 테이블이 13개이고 행이 386개인 복합 도메인에서는 DB 직접 검색이 더 정확합니다. 그래서 자연어를 SQL로 바꾸는 Text2SQL을 도입했습니다. LLM 라우터가 질문 의도를 분류하고, Text2SQL이 PostgreSQL에서 데이터를 가져오고, LLM이 자연어로 응답을 생성합니다. 40문항 실전 테스트 결과, 정확도가 10.8%에서 70.1%로 올라갔습니다.

10.8%→70.1%

팩트 정확도 향상

100%

SQL 문법 유효율

90%

LLM 라우팅 정확도

1,926ms

평균 응답 시간

동의어 사전의 한계

이전 하이브리드 검색에서는 동의어 사전으로 사용자 질문을 DB 스키마에 매핑했습니다. "가격" → price, "메뉴" → menu_items 같은 키워드 매핑입니다. 테이블이 3~4개일 때는 충분했지만, 13개 테이블로 확장하자 문제가 터졌습니다.

동의어 사전이 무너지는 이유

동의어 폭발13테이블 × 평균 5컬럼 = 65개 매핑. '비용', '요금', '가격', '단가'가 모두 다른 테이블의 다른 컬럼을 가리킴
다중 테이블 질문"진료과별 평균 진료비"는 departments + medical_records + billing 3개 테이블 JOIN이 필요. 키워드로는 판단 불가
집계 표현 다양성"가장 비싼", "평균", "총합", "~보다 큰" — 같은 MAX도 표현이 수십 가지
유지보수 지옥테이블 1개 추가할 때마다 동의어를 수동으로 등록. 누락 시 해당 질문은 무조건 실패

실제로 40개 질문을 동의어 사전 방식으로 테스트하면 정확도 41.2%였습니다. 단순 조회는 처리하지만, JOIN이나 집계가 들어가면 급격히 무너집니다. 테이블이 늘어날수록 동의어 관리가 비현실적이기 때문에, LLM이 직접 스키마를 이해하고 SQL을 작성하는 Text2SQL 방식으로 전환했습니다.

LLM 라우터 + Text2SQL 아키텍처

전체 흐름은 4단계입니다. LLM을 2번 호출하지만, SQL 실행과 RAG 검색은 수 ms 수준이므로 총 응답 시간은 2초 이내에 수렴합니다.

처리 흐름

🧭
LLM 라우터~900ms

자연어 질문 → Intent 분류 (DB조회 / 일반대화 / RAG)

📝
Text2SQL 생성라우팅에 포함

테이블 스키마 + 질문 → SQL 쿼리 생성 (LLM)

SQL 실행~7ms

PostgreSQL에서 쿼리 실행 → 결과 행 반환

💬
답변 생성~1,000ms

SQL 결과 + 원본 질문 → 자연어 응답 (LLM)

핵심은 LLM 라우터입니다. 질문이 DB 조회인지, 일반 대화인지, RAG가 필요한지를 먼저 판단합니다. DB 조회로 분류되면 동시에 SQL을 생성합니다. 라우팅 정확도가 낮으면 아무리 SQL을 잘 만들어도 의미가 없기 때문에, 라우터 성능이 전체 파이프라인의 상한선을 결정합니다.

스키마 프롬프트 설계: 13개 테이블의 DDL(CREATE TABLE 문)을 LLM 프롬프트에 직접 주입합니다. 테이블명, 컬럼명, 데이터 타입, FK 관계까지 포함하면 약 2,000토큰입니다. LLM은 이 스키마를 보고 어떤 테이블을 JOIN할지, 어떤 컬럼을 WHERE에 넣을지 판단합니다. 동의어 사전은 "사람이 매핑을 정의"하지만, Text2SQL은 "LLM이 스키마를 읽고 추론"합니다.

40문항 실전 테스트

테스트 도메인은 종합병원입니다. 환자, 의사, 진료과, 진료기록, 처방, 수납, 병실, 예약 등13개 테이블, 386행의 데이터로 구성했습니다. 질문은 4단계 난이도(Tier)로 설계했습니다.

Tier난이도예시 질문문항 수정확도
Tier 1단순 조회내과 소속 의사 목록은?1275%
Tier 2JOIN김환자의 처방 이력을 알려줘1088%
Tier 3집계진료과별 평균 진료비는?1064%
Tier 4복합3월에 가장 많이 처방된 약은?852%
전체 평균4070.1%

흥미로운 점은 Tier 2(JOIN)가 Tier 1(단순 조회)보다 높은 88%를 기록한 것입니다. JOIN 질문은 "김환자의 처방"처럼 테이블 간 관계가 명확해서 LLM이 FK를 정확히 잡습니다. 반면 단순 조회라도 "현재 입원 중인 환자"처럼 상태 필터링이 필요하면,status = 'admitted' 같은 값을 추론해야 해서 오히려 어렵습니다.

SQL 생성 품질 지표

100%

SQL 생성률

40문항 모두 SQL 쿼리 생성 성공

100%

문법 유효율

생성된 SQL 전체가 문법적으로 유효

95%

실행 성공률

38/40 쿼리가 에러 없이 실행 완료

70.1%

정답 정확도

실행 결과가 실제 정답과 일치

SQL 생성률과 문법 유효율이 모두 100%인 것은, 스키마 DDL을 프롬프트에 직접 주입한 효과입니다. LLM이 실제 테이블 구조를 보기 때문에 존재하지 않는 컬럼을 참조하는 오류가 거의 없습니다. 정확도 격차(100% → 70.1%)는 "올바른 SQL이지만 의미적으로 다른 결과를 반환"하는 경우입니다.

3방식 정확도 비교

동일한 40문항을 3가지 방식으로 테스트했습니다. LLM만 사용한 경우와의 차이가 극명합니다.

LLM만 (지식 기반)10.8%

DB 데이터를 전혀 참조하지 않음. 숫자·이름을 전부 환각으로 생성

동의어 사전 + DB41.2%

키워드 매핑으로 단순 조회는 성공. JOIN·집계에서 급격히 하락

Text2SQL + LLM 라우터70.1%

LLM이 스키마를 읽고 SQL을 직접 생성. 복합 쿼리까지 처리

LLM만 사용하면 환자 이름, 진료비, 처방약 등 모든 수치 데이터를 환각으로 생성합니다. 정확도 10.8%는 "예/아니오" 류 질문에서 우연히 맞춘 수준입니다. 동의어 사전은 단순 조회에서 효과적이지만, 테이블이 늘어나면 매핑 관리가 한계에 도달합니다.

왜 70.1%가 의미 있는가: 하이브리드 검색에서 RAG의 팩트 정확도가 92.5%였지만, RAG는 "문서에 있는 정보"만 검색합니다. Text2SQL은 "테이블에 있는 모든 데이터"에 SQL로 접근하므로 커버리지가 다릅니다. 특히 집계(SUM, AVG, MAX)나 조건부 필터링은 RAG로 불가능하고 SQL만 가능한 영역입니다. 실전에서는 RAG + Text2SQL을 함께 사용하는 것이 최선입니다.

레이턴시 분석

전체 응답 시간은 평균 1,926ms입니다. 목표였던 2,500ms를 넉넉히 달성했습니다. 병목은 명확합니다 — LLM 호출입니다.

단계소요 시간전체 비중비고
LLM 라우팅 + SQL 생성~900ms46.7%1차 LLM 호출
SQL 실행 (PostgreSQL)~7ms0.4%인덱스 활용, 386행
RAG 검색 (병렬)~18ms0.9%DB 조회와 동시 실행
답변 생성 (LLM)~1,000ms51.9%2차 LLM 호출
합계~1,926ms100%목표 2,500ms 이내 달성

SQL 실행(7ms)과 RAG 검색(18ms)은 합쳐도 25ms입니다. 전체 응답 시간의 98.7%가 LLM 호출입니다. 성능 최적화를 한다면, LLM 추론 속도를 높이는 것이 유일하게 의미 있는 방향입니다. GPU 업그레이드나 AWQ 양자화로 tok/s를 높이면 응답 시간이 비례해서 줄어듭니다.

LLM 라우터 성능

90%

라우팅 정확도

36/40 올바르게 분류

4건

오분류

DB→일반으로 잘못 분류

0건

역방향 오류

일반→DB 오분류 없음

라우팅 오류 4건은 모두 "DB 조회가 필요한 질문을 일반 대화로 분류"한 경우입니다. 역방향 오류(일반 질문을 DB로 보내는 것)는 0건이므로, 불필요한 SQL 실행은 발생하지 않습니다. 라우터가 "확실하지 않으면 일반 대화로 보내는" 보수적인 전략을 학습한 것으로 보입니다.

한계와 개선 방향

70.1%는 동의어 사전(41.2%)보다 크게 개선됐지만, 아직 실서비스에 바로 넣기에는 부족합니다. 오답 30%를 분석하면 패턴이 보입니다.

날짜 계산오답 중 33%

증상: "최근 3개월간"을 SQL의 DATE_SUB로 변환 실패

개선안: 현재 날짜를 프롬프트에 주입 + 날짜 함수 Few-shot 예시 추가

빈 결과 해석오답 중 25%

증상: SQL은 정확하지만 결과가 0행일 때 "데이터가 없다"고 답해야 하는데 환각 생성

개선안: 결과가 0행이면 LLM에 명시적으로 "해당 데이터 없음" 컨텍스트 주입

금액 포맷오답 중 17%

증상: 15000을 "만오천원"으로 변환 시 단위 오류

개선안: SQL 결과를 숫자 그대로 전달하고, 포맷팅은 후처리 레이어에서 처리

암묵적 조건오답 중 25%

증상: "현재 입원 중"이라는 상태 값이 스키마에 없으면 추론 실패

개선안: 스키마 프롬프트에 주요 enum 값과 비즈니스 규칙을 주석으로 추가

이 개선안들은 모두 프롬프트 엔지니어링 수준에서 해결 가능합니다. 모델을 바꾸거나 아키텍처를 변경할 필요 없이, 스키마 프롬프트에 날짜 함수 예시, enum 값 목록, 0행 처리 규칙을 추가하면 됩니다. 개선 적용 후 80% 이상을 목표로 합니다.

환각 방어 사례

Text2SQL의 가장 큰 장점은 "데이터가 없으면 SQL이 빈 결과를 반환한다"는 것입니다. LLM만 사용하면 존재하지 않는 환자 이름, 가짜 진료비를 만들어내지만, Text2SQL은 DB에 없으면 0행을 반환합니다. 문제는 이 0행을 LLM이 어떻게 해석하느냐입니다.

"이영희 환자의 진료 기록" → SQL 0행 → "해당 환자의 진료 기록이 없습니다" ✓
"피부과 진료비 평균" → SQL 0행 → "피부과 진료비 평균은 약 50,000원입니다" ✗ (환각)

SQL 결과가 0행일 때 LLM이 환각을 생성하는 케이스는 프롬프트에 명시적 가드레일을 추가해 방어합니다.

결론

동의어 사전 → Text2SQL 전환의 결론은 명확합니다. 테이블이 5개를 넘어가면 동의어 사전은 유지보수가 불가능해지고, LLM이 스키마를 직접 읽는 Text2SQL이 정확도와 확장성 모두에서 우위입니다.

최종 정리

항목LLM만동의어사전Text2SQL
팩트 정확도10.8%41.2%70.1%
확장성 (테이블 추가)변화 없음동의어 수동 추가DDL만 프롬프트에 추가
집계 쿼리불가매우 제한적SUM/AVG/MAX 가능
유지보수 비용없음높음낮음
응답 시간~1,000ms~1,200ms~1,926ms

응답 시간이 1,926ms로 가장 길지만, LLM 2회 호출이 원인이므로 GPU 성능에 비례해 단축됩니다. 정확도 향상(10.8% → 70.1%)과 유지보수 비용 절감을 고려하면 합리적인 트레이드오프입니다.

AI 챗봇의 데이터 검색 파이프라인은 이제 3계층으로 완성됩니다: RAG는 비정형 문서 검색, 하이브리드 검색은 DB+RAG 병렬 결합, 그리고 Text2SQL은 구조화된 데이터의 직접 쿼리를 담당합니다. LLM 라우터가 질문 의도에 따라 적절한 경로를 선택하면, 각각의 강점을 최대로 활용할 수 있습니다.

다음 단계: RAG + Text2SQL + 하이브리드 검색을 하나의 라우터 아래에 통합하고, 질문 유형에 따라 자동으로 최적 경로를 선택하는 통합 파이프라인을 구축할 예정입니다. 라우팅 정확도 90% → 95% 이상을 목표로, Few-shot 예시와 피드백 루프를 추가합니다.

T

Treeru

웹 개발, IT 인프라, AI 솔루션 분야의 실무 인사이트를 공유합니다. 기업의 디지털 전환을 돕는 IT 파트너, Treeru입니다.

공유

댓글

(4개)
4.85/ 5

로그인하면 댓글을 작성할 수 있습니다.

2026-03-04
555.0

13테이블 386행 도메인에서 SQL 생성률 100%, 문법 유효율 100%면 놀랍습니다. 동의어 사전 방식에서 Text2SQL로 넘어가는 명확한 근거가 되겠네요.

2026-03-04
4.954.9

LLM 라우터의 라우팅 정확도 90%가 핵심인 것 같습니다. Intent 분류가 틀리면 아무리 SQL을 잘 생성해도 소용없으니까요. 라우터 성능 개선이 다음 과제겠네요.

2026-03-04
4.854.8

4-Tier 난이도 분석이 실용적입니다. 단순조회 75%, JOIN 88%, 집계 64%, 복합 52% — JOIN이 단순조회보다 높은 이유가 의외였습니다. JOIN은 테이블 관계가 명확해서 LLM이 잘 잡나 봅니다.

관련 글

© 2026 TreeRU. All rights reserved.

본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.