SQRL 소개
RAG 파이프라인의 텍스트 청킹(chunking) 라이브러리로 잘 알려진 Chonkie의 개발사 feyn이 자연어 질문을 SQL 쿼리로 변환하는 모델 제품군 SQRL 을 공개했습니다. SQRL은 SQRL-4B, SQRL-9B, SQRL-35B-A3B 세 가지 크기로 제공되며, 모두 Hugging Face에 Apache 2.0 라이선스로 공개되어 있습니다.
SQRL의 핵심 차별점은 이름에서 드러나듯 "먼저 파헤친 뒤 질의한다(Digs Before It Queries)" 는 동작 방식에 있습니다. 대부분의 text-to-SQL 모델은 질문과 스키마를 받으면 곧바로 SQL을 생성합니다. 반면 SQRL은 필요하다고 판단하면 답을 확정하기 전에 데이터베이스에 읽기 전용(read-only) 탐색 쿼리를 던져 값이 실제로 어떤 형식으로 저장돼 있는지, 조인(join) 경로가 올바른지, 필터가 실제로 행에 걸리는지를 확인합니다. 즉, 스키마만 보고 추측하는 대신 데이터에게 직접 물어봅니다.
성능도 눈에 띕니다. 플래그십인 SQRL-35B-A3B는 대표적인 text-to-SQL 벤치마크인 BIRD Dev에서 실행 정확도(Execution Accuracy) 70.6%를 기록해, 원문이 비교 대상으로 제시한 Claude Opus 4.6의 68.77%를 앞섭니다. 더 흥미로운 지점은 이 능력을 4B, 9B 규모의 작은 모델로 증류(Distillation) 했을 때에도 성능이 거의 유지된다는 점입니다. 가장 작은 SQRL-4B조차 데이터베이스 옆에서 자체 호스팅할 수 있는 크기임에도 스키마와 쿼리, 관측 데이터를 외부로 내보내지 않고 프론티어 모델급 정확도에 근접합니다.
text-to-SQL이 단순한 "번역 문제"가 아닌 이유
text-to-SQL은 흔히 번역 문제로 설명됩니다. 사용자가 자연어로 질문하면 모델이 대응하는 SQL을 작성한다는 것입니다. 그러나 이 관점은 이 작업에서 가장 어려운 부분을 놓치고 있습니다.
쿼리는 문법적으로 완벽한 SQL이면서도 여전히 틀릴 수 있습니다. 엉뚱한 테이블을 조인하거나, 모호한 컬럼을 잘못 해석하거나, 존재하지 않는 값으로 필터링할 수 있습니다. 이 중 어느 것도 오류를 발생시키지 않지만, 모두 잘못된 답을 반환합니다. 문법 검사기는 이런 실수를 잡아내지 못합니다.
스키마 정보만으로는 좋은 쿼리를 작성하기에 충분하지 않다는 것이 원문의 핵심 주장입니다. 스키마는 테이블과 컬럼 이름, 타입, 때로는 관계를 알려주지만, 어떤 카운티가 Alameda, Alameda County, ALAMEDA 중 어떤 형태로 저장돼 있는지는 보여주지 않습니다. 비슷한 두 식별자가 같은 엔티티를 가리키는지 설명해 주지도 않고, 어떤 조인이 중복 행을 만들어 내는지도 알려주지 않습니다.
BIRD 벤치마크는 바로 이런 실패를 드러내도록 설계됐습니다. 95개의 데이터베이스가 실제 도메인을 아우르며, 불완전한 값과 모호한 컬럼, 단순하지 않은 관계를 담고 있습니다. 채점은 모델이 생성한 SQL을 실제로 실행해서 나온 결과를 정답 쿼리의 결과와 비교하는 방식입니다. 쿼리 언어에서는 문법적 정확성만으로는 충분하지 않다는 것을 이 벤치마크가 보여줍니다. 그리고 우리가 정확한 쿼리를 작성하는 데 필요한 정보는 이미 데이터베이스 안에 들어 있습니다. 모델이 그것을 물어볼 수 있게만 해주면 됩니다. SQRL은 바로 이 통찰 위에 세워졌습니다.
답변하기 전에 먼저 데이터베이스를 살펴보는 SQRL
SQRL은 질문과 스키마, 그리고 (선택적으로) 데이터베이스 구조나 내용에 대한 힌트(evidence)를 입력받습니다. 이 맥락만으로 충분하면 SQRL은 곧바로 쿼리를 반환합니다. 그러나 무언가 모호한 부분이 남아 있으면 읽기 전용 쿼리를 실행하고, 돌아온 행(row)을 근거로 최종 쿼리를 작성합니다.
살펴볼지 말지는 상황에 따라 결정됩니다. 예를 들어 행의 개수를 세는 질문은 데이터를 들여다볼 필요가 없으므로 SQRL은 곧장 답을 냅니다. 반면 특정 조건으로 필터링하는 질문은 그 값이 데이터베이스에 어떻게 저장돼 있는지 알아야 합니다. 아래 예시에서 SQRL은 스키마에 없는 정보인 "카운티 이름이 실제로 어떻게 저장돼 있는가"를 먼저 확인한 뒤 답을 확정합니다.
질문: Alameda County에 있는 학교는 무엇인가요?
# 스키마는 County 이름이 어떤 형식으로 저장됐는지 보여주지 않는다 → 먼저 탐색
<sql> SELECT DISTINCT `County Name` FROM frpm LIMIT 10 </sql>
# 관측(observation): County는 'Alameda'로 저장돼 있음
<observation> Alameda Contra Costa Fresno </observation>
# 이제 저장된 값에 맞춰 최종 쿼리를 확정
<answer> SELECT `School Name` FROM frpm WHERE `County Name` = 'Alameda' </answer>
이러한 상호작용에는 두 가지 서로 다른 행동이 있습니다. <sql> 블록 은 데이터베이스에 관측을 요청하는 탐색용 쿼리이고, <answer> 블록 은 최종 쿼리를 확정하는 행동입니다. 실행 하네스(harness)는 탐색 쿼리를 읽기 전용 모드로 실행하고 그 결과 행을 <observation> 태그로 감싸 모델에게 돌려줍니다. SQRL은 최대 5번까지 데이터베이스를 살펴볼 수 있지만, 대부분의 질문은 그보다 적은 단계로 해결됩니다.
이 설계는 기존 두 가지 접근을 하나의 모델 안에 결합한 것입니다. 원문은 전통적인 text-to-SQL이 두 갈래로 나뉘어 왔다고 정리합니다.
- 단일 샷(single-shot) 모델: 서빙 비용이 저렴하고 한 번의 턴에 전체 쿼리를 생성합니다. 그러나 모든 것을 스키마로부터 추론해야 하므로 논리적으로 틀린 쿼리로 이어질 수 있습니다.
- 프론티어 파이프라인: 맥락을 검색하고, 후보를 생성하고, 비평하고, 답을 선택합니다. 정확도를 극대화할 수 있지만 질문 하나마다 값비싼 프론티어 모델 호출과 여러 번의 데이터베이스 왕복이 필요해, 지연이 중요한 실시간 경로(hot path)에서 쓰기 어렵습니다.
SQRL은 이 둘의 장점을 한 모델에 담았습니다. 쉬운 질문은 짧게 끝나고, 모호한 질문만 탐색이라는 비용을 치릅니다.
"언제 살펴볼지"를 학습으로 가르치기
모델에게 데이터베이스 접근 권한을 주는 것만으로는 언제, 어떻게 살펴봐야 하는지를 알게 되지 않습니다. 이 행동은 학습으로 가르쳐야 합니다.
실행 기반 학습(execution-based training)은 냉정합니다. 정답 쿼리 자체가 틀려 있으면, 모델이 옳은 답을 내놓아도 잘못된 보상(reward) 을 받게 됩니다. 그래서 feyn은 어떤 모델도 학습시키기 전에 먼저 학습 데이터 풀을 정제했습니다. BIRD와 Spider에서 출발해, 정답 SQL이 쓸 만한 결과를 내지 못하는 예제를 제거했습니다. 남은 질문과 쿼리 쌍은 3개의 LLM 심판(judge) 모델이 검토해, 질문에 적힌 대로 답하지 못하는 쿼리는 모두 걷어냈습니다. 마지막으로 Spider를 분할하고 BIRD dev와 합쳐 테스트 세트를 만들었으며, 나머지 데이터를 학습에 사용했습니다. BIRD-dev와 Spider-test는 학습에 전혀 사용되지 않았습니다.
정제가 신뢰할 수 있는 보상을 만들어 준 뒤에야 교사(teacher) 모델을 학습시킬 수 있었습니다. 35B-A3B 교사 모델은 별도의 지도 미세조정(Supervised Fine-Tuning, SFT) 단계 없이, 기반 모델에 MiniMax의 M1 연구에서 제안된 CISPO 강화학습을 곧바로 적용해 학습했습니다. 각 질문마다 모델은 8개의 완전한 궤적(trajectory)을 생성하고, feyn은 모든 최종 쿼리를 실행해 그 결과를 정답 쿼리의 결과와 비교했습니다.
predicted_result = execute(predicted_sql)
gold_result = execute(gold_sql)
reward = int(predicted_result == gold_result)
이 보상은 벤치마크와 같은 원칙을 따릅니다. 두 쿼리가 같은 단어를 쓰는지는 무시하고, 오직 같은 답을 반환하는지만 확인합니다. 그룹 상대(group-relative) 학습에는 각 그룹 안에서의 변동이 필요합니다. 8번 모두 성공하거나 8번 모두 실패하면 어떤 결정이 도움이 됐는지에 대한 정보가 거의 없습니다. 그래서 교사 모델은 8번의 시도 중 일부만 성공한 "혼합 지대(mixed zone)" 에서 학습됐고, 이를 통해 올바른 궤적과 잘못된 궤적을 가른 선택, 즉 "언제 살펴봐야 하는가"를 배웠습니다.
다음 과제는 이 행동을 배포 가능한 크기로 줄이는 것이었습니다. feyn은 교사의 완전한 궤적을 샘플링해, 최종 SQL이 올바른 결과를 반환한 실행만 남겼습니다. 이렇게 약 10,200개의 예제가 만들어졌고, 각 예제는 추론(reasoning), 탐색 쿼리, 관측, 최종 답변까지 전체 상호작용을 보존했습니다. 교사와 달리, 4B와 9B 학생(student) 모델은 이 궤적으로 먼저 지도 미세조정(SFT) 을 거쳐 질문에서 탐색을 지나 최종 쿼리에 이르는 전 과정을 배웠습니다. 이후 두 학생 모델도 교사와 동일한 실행 보상으로 CISPO 강화학습을 거쳐 행동을 한층 더 다듬었습니다.
3종 모델 라인업과 벤치마크 성능
SQRL은 서로 다른 배포 예산에 대응하는 세 가지 체크포인트로 제공됩니다. 세 모델 모두 Qwen 계열을 기반으로 하며, 기반 모델의 비전 타워(vision tower)를 그대로 물려받아 VL 체크포인트로도 로드되지만 SQL 학습은 텍스트 전용으로 이뤄졌습니다.
| 모델 | 기반 모델 | 규모 | BIRD-dev pass@1 | BIRD-dev vote@8 |
|---|---|---|---|---|
| SQRL-4B | Qwen3.5-4B | 4B | 64.6% | 68.8% |
| SQRL-9B | Qwen3.5-9B | 9B | 66.6% | 69.8% |
| SQRL-35B-A3B | Qwen3.6-35B-A3B | 35B (활성 약 3B, MoE) | 68.7% | 70.6% |
여기서 두 가지 지표를 구분하는 것이 중요합니다. pass@1 은 샘플 하나의 평균 실행 정확도(BIRD-dev 전체 1,534개 질문 기준)이고, vote@8 은 8개의 샘플을 뽑아 실행 결과가 동일한 것끼리 묶은 뒤 가장 큰 묶음의 쿼리를 고르는 실행 기반 다수결(execution-clustered majority voting) 방식입니다. 이는 여러 샘플을 뽑아 다수가 동의하는 답을 택하는 자기일관성(Self-Consistency) 기법을 문자열이 아닌 실행 결과를 기준으로 적용한 것으로, 추론 시점에 더 많은 연산(test-time compute)을 투입해 정확도를 끌어올린 수치입니다.
원문이 제시한 BIRD Dev 리더보드는 다음과 같습니다. SQRL 항목은 위 표의 vote@8 값에 해당합니다.
| 모델 | BIRD-dev 실행 정확도 |
|---|---|
| SQRL-35B-A3B | 70.60% |
| SQRL-9B | 69.80% |
| SQRL-4B | 68.80% |
| Claude Opus 4.6 | 68.77% |
| Claude 4.5 Sonnet | 67.34% |
| Qwen3-Coder-480B-A35B | 66.17% |
| GLM-4.7 | 63.82% |
| DeepSeek-R1 | 61.67% |
| Kimi-K2-Thinking | 60.63% |
주목할 점은 규모 대비 효율입니다. 9B 학생 모델은 vote@8에서 69.80%로 35B 교사 모델(70.60%)과 0.8%p 차이에 불과하고, 4B 모델도 68.80%로 리더보드의 Claude Opus 4.6 수치와 어깨를 나란히 합니다. feyn은 서빙 비용이 중요하다면 투표를 적용한 9B 모델이 가장 균형 잡힌 배포 선택지라고 권합니다.
이 정확도가 학습 과정에서 실제로 만들어진 것이라는 점은 단계별 수치에서 드러납니다. 모델 카드에 따르면 동일한 하네스에서 기반 모델인 Qwen3.5-4B는 약 52%에 그치지만, 증류 미세조정만으로 약 63.6%까지, 이어진 CISPO 강화학습으로 pass@1 64.6%까지 올라가고, 여기에 투표를 더하면 68.8%에 이릅니다. 또한 SQRL-4B는 학습에 사용되지 않은 평가 분할인 Spider 테스트셋(2,147개 질문)에서도 pass@1 84.0%, vote@8 85.9%를 기록해, BIRD 한 벤치마크에만 맞춰진 성능이 아님을 시사합니다.
다만 이 비교에는 맥락이 필요합니다. SQRL의 리더보드 수치는 8개 샘플 투표(vote@8)를 거친 값인 반면, 비교 대상 모델들의 수치가 동일한 다수결 조건에서 측정된 것인지는 원문에 명시돼 있지 않습니다. 모델 카드에 따르면 SQRL-4B의 단일 샷(pass@1) 정확도는 64.6%로, 투표가 약 +4.3%p를 더해 68.8%에 이르게 합니다. 또한 투표는 대략 8~16회에서 포화되어 그 이상은 정확도를 거의 높이지 못한다고 합니다.
한 가지 유용한 부수 효과는 투표 만장일치를 무료 신뢰도 신호로 활용 할 수 있다는 점입니다. 8개 샘플이 모두 같은 답에 동의하면 그 답이 옳을 확률이 약 87%인 반면, 표가 갈리거나 근소하게 이긴 경우의 정확도는 19~43%에 그칩니다. 이 신호는 어떤 질문을 사람이나 더 큰 모델에게 넘길지(routing/escalation) 판단하는 데 쓸 수 있습니다.
데이터베이스 옆에서 직접 실행하기
세 체크포인트는 서로 다른 배포 예산을 겨냥합니다. SQRL-4B가 가장 작고, SQRL-9B가 권장 기본값이며, SQRL-35B-A3B가 가장 높은 정확도를 제공하면서도 전문가 혼합(Mixture of Experts, MoE) 구조 덕분에 토큰당 활성 파라미터는 약 3B에 불과합니다. 모델은 모두 vLLM으로 서빙할 수 있습니다.
vllm serve feyninc/sqrl-9b \
--served-model-name sqrl-9b \
--gpu-memory-utilization 0.90 \
--max-model-len 32768
애플리케이션 루프는 단순합니다. 데이터베이스 실행을 읽기 전용으로 유지하고, 각 관측 결과를 모델에게 돌려주기만 하면 됩니다. 아래는 모델 카드에 실린 최소 드라이버 루프입니다.
import re
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
messages = [{"role": "system", "content": system_prompt},
{"role": "user", "content": user0}]
for step in range(6):
r = client.chat.completions.create(model="sqrl-9b", messages=messages,
temperature=0.7, top_p=0.95, max_tokens=8192)
content = r.choices[0].message.content
if "</think>" in content: # strip inline think scratchpad
content = content.split("</think>")[-1].strip()
messages.append({"role": "assistant", "content": content})
ans = re.findall(r"<answer>(.*?)</answer>", content, re.S)
if ans:
final_sql = ans[-1].strip(); break
sql = re.findall(r"<sql>(.*?)</sql>", content, re.S)
if not sql:
break
obs = run_readonly(sql[-1].strip()) # your sqlite executor
messages.append({"role": "user",
"content": f"<observation>\n{obs}\n</observation>\n"
"Continue with <sql> or <answer>."})
한 가지 반드시 지켜야 할 주의사항이 있습니다. 서빙 계층에서 추론 파서(reasoning parser)를 활성화하면 안 됩니다 (예: --reasoning-parser qwen3). SQRL의 행동 프로토콜(<sql> 또는 <answer>)은 </think> 태그 다음 의 콘텐츠에 담기는데, 추론 파서가 그 부분을 잘라내거나 다른 경로로 보내면 모델의 행동 자체가 사라집니다. 원문에 따르면 이 경우 실행 정확도가 약 12%p 하락합니다. 따라서 원본 메시지 콘텐츠를 그대로 파싱하고, 마지막 닫는 </think> 태그 뒤의 모든 내용을 보존해야 합니다. 권장 샘플링 설정은 temperature 0.7, top_p 0.95 이며 SQLite 방언에 맞춘 백틱 식별자 인용을 사용합니다.
라이선스
SQRL 제품군의 세 모델은 모두 Apache License 2.0으로 배포되고 있어, 연구 목적은 물론 상업적 용도로도 자유롭게 사용 및 수정이 가능합니다. 스키마와 쿼리, 데이터베이스 관측 결과를 외부 서비스로 내보내지 않고 데이터가 위치한 인프라 안에서 자체 호스팅할 수 있다는 점이, 데이터 주권이 중요한 조직에게는 특히 매력적인 선택지가 됩니다.
SQRL Digs Before It Queries 소개 블로그
SQRL 모델 컬렉션 (Hugging Face)
feyn GitHub 저장소
더 읽어보기
-
Distil-Text2SQL(SQirreL): 자연어 질문을 SQL 쿼리로 변환하는, 로컬에서 실행 가능한 경량 모델(0.6B/4B)
-
DataFlow📜: 데이터 중심 AI를 위한, LLM 기반 통합 데이터 준비 및 워크플로우 자동화 프레임워크 기술 문서 리뷰
이 글은 GPT 모델로 정리한 글을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 덧글로 알려주시기를 부탁드립니다. ![]()
파이토치 한국 사용자 모임
이 정리한 이 글이 유용하셨나요? 회원으로 가입하시면 주요 글들을 이메일
로 보내드립니다! 텔레그램(Telegram)이나 Slack/Discord/Teams/Dooray/GoogleChat 등으로도 새 글 알림을 받으실 수 있습니다. ![]()
아래
쪽에 좋아요
를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~ ![]()
