자기 수정형 에이전트: smolagents (Hugging Face)를 활용한 Text-to-SQL
요약
Hugging Face의 smolagents를 활용하여 오류를 스스로 수정하는 Text-to-SQL 에이전트를 구축하는 방법을 소개합니다. ReAct 패턴을 통해 모델이 생성한 SQL을 검증하고 반복적으로 개선하는 파이프라인을 구현합니다.
핵심 포인트
- smolagents의 CodeAgent를 활용한 자기 수정형 에이전트 구축
- ReAct 패턴을 통한 추론 및 실행 결과 검증 프로세스 도입
- @tool 데코레이터와 docstring을 이용한 데이터베이스 스키마 전달
- SQLAlchemy와 SQLite를 결합한 테스트 환경 구성
전통적인 "텍스트 → SQL" 파이프라인의 문제점
데이터베이스를 위한 대부분의 AI 솔루션은 동일한 패턴을 따릅니다. 사용자가 자연어로 질문을 작성하면, 모델이 이를 SQL 쿼리로 번역하고, 그 쿼리가 데이터베이스에서 직접 실행됩니다. 이는 간단하지만 취약합니다. 만약 모델이 잘못된 쿼리를 생성하면, 이는 오류 없이 실행되어 유효해 보이지만 실제로는 그렇지 않은 결과를 반환할 수 있습니다. 눈에 보이는 실패가 없기 때문에 아무도 답변이 잘못되었다는 사실을 알지 못합니다.
Hugging Face의 에이전트 프레임워크인 smolagents의 공식 문서는 대안을 제시합니다. 단일 단계 파이프라인 대신, 자신의 쿼리 결과를 검토하고 수정이 필요한지 결정할 수 있는 **에이전트 (Agent)**를 구축하는 것입니다. ReAct (Reasoning + Acting, 추론 + 행동)라고 알려진 이 패턴은 맹목적인 번역을 반복적인 테스트 및 검증 프로세스로 전환합니다.
사용된 스택
- smolagents — Hugging Face의 코드 기반 에이전트 프레임워크.
CodeAgent— 프레임워크의 핵심 클래스: 코드를 작성하고 실행하며 이전 결과를 바탕으로 반복하는 추론 에이전트.- SQLAlchemy — 메모리 내 SQLite 데이터베이스를 생성하고 쿼리를 실행하기 위해 사용.
InferenceClientModel— 에이전트를 Hugging Face의 Inference API (Serverless 또는 전용)에 호스팅된 모델과 연결.- 프레임워크 리포지토리: github.com/huggingface/smolagents
- 예제 문서: Self-correcting Text-to-SQL
단계별 가이드: 에이전트 구축 방법
1. 데이터베이스 준비
SQLite에 receipt_id, customer_name, price, tip 컬럼을 가진 receipts (영수증) 테이블을 생성하고, 몇 가지 예시 행(고객 이름, 가격, 팁)을 삽입합니다.
2. 테이블을 에이전트용 도구 (tool)로 변환하기
여기에 설계의 가장 중요한 세부 사항이 있습니다. 테이블에 대한 설명은 별도의 프롬프트로 모델에게 "설명"되는 것이 아니라, @tool 데코레이터가 적용된 sql_engine 함수의 docstring에 직접 포함됩니다.
@tool
def sql_engine(query: str) -> str:
"""
테이블에 대해 SQL 쿼리를 수행할 수 있게 합니다. 결과의 문자열 표현을 반환합니다.
테이블 이름은 'receipts'입니다. 설명은 다음과 같습니다:
Columns:
\- receipt_id: INTEGER
\- customer_name: VARCHAR(16)
\- price: FLOAT
\- tip: FLOAT
Args:
query: 수행할 쿼리입니다. 올바른 SQL이어야 합니다.
"""
...
이 docstring이 바로 CodeAgent가 사용 가능한 스키마(schema)가 무엇인지, 그리고 쿼리를 어떻게 구성해야 하는지를 이해하기 위해 "읽는" 내용입니다.
3. 에이전트 생성
from smolagents import CodeAgent, InferenceClientModel
agent = CodeAgent(
tools=[sql_engine],
model=InferenceClientModel(model_id="meta-llama/Llama-3.1-8B-Instruct"),
)
agent.run("Can you give me the name of the client who got the most expensive receipt?")
이것만으로도 에이전트는 해당하는 SQL 쿼리를 생성하고, sql_engine 도구를 통해 이를 실행하며, 가장 비싼 영수증을 받은 고객의 이름을 반환할 수 있습니다.
레벨 2: 스키마가 복잡해질 때 (joins)
진정한 시험대는 각 receipt_id를 담당 웨이터의 이름과 연결하는 두 번째 테이블인 waiters (웨이터)가 추가될 때 찾아옵니다. 이는 에이전트가 "어떤 웨이터가 총 얼마의 팁을 가장 많이 받았나요?"와 같은 질문에 답하기 위해 두 테이블 간의 **조인 (join)**에 대해 추론하도록 강제합니다.
스키마가 변경됨에 따라, sql_engine 도구의 설명은 이제 두 테이블의 컬럼을 모두 포함하도록 동적으로 업데이트됩니다.
sql_engine.description = updated_description
```python
agent = CodeAgent(
tools=[sql_engine],
model=InferenceClientModel(model_id="Qwen/Qwen3-Next-80B-A3B-Thinking"),
)
agent.run("Which waiter got more total money from tips?")
여기서 두 가지 핵심적인 일이 일어납니다:
- 에이전트가 환경에 대한 이해를 업데이트합니다. 도구(tool)의 설명(description)이 변경되었기 때문에 단순히 업데이트되는 것이며, 아무것도 재학습(re-train)하거나 에이전트의 로직을 다시 작성할 필요가 없습니다.
- 모델이 더 강력한 모델로 교체되었습니다 (Llama-3.1-8B-Instruct 대신 Qwen3-Next-80B-A3B-Thinking 사용). 이는 조인(join)에 대해 추론하는 작업이 단일 테이블에 대한 단순 쿼리보다 더 어렵기 때문입니다. 문서에 따르면 이러한 모델 교체는 더 복잡한 쿼리에 대해 결과물을 눈에 띄게 개선합니다.
이 접근 방식이 직접적인 파이프라인보다 우수한 이유
| 직접적인 텍스트→SQL 파이프라인 | smolagents를 활용한 에이전트 (ReAct) |
|---|---|
| 단일 단계에서 쿼리를 생성하고 실행 | 쿼리를 생성, 실행, 결과를 관찰하고 수정할 수 있음 |
| ... |
결론
smolagents의 예시는 Text-to-SQL의 품질 도약이 단순히 더 큰 언어 모델을 사용하는 것에서 오는 것이 아니라, 모델에게 단일 응답을 "맹목적으로" 생성하게 하는 대신 행동하고, 관찰하고, 수정할 수 있는 능력을 부여하는 데서 온다는 것을 보여줍니다. 이는 스키마가 변경되고, 쿼리가 복잡해지며(조인, 집계, 중첩 필터), 조용한 오류가 잘못된 데이터에 기반한 결정으로 이어질 수 있는 실제 데이터베이스 환경에서 특히 가치가 있습니다.
직접 실험해보고 싶은 분들을 위해: huggingface/smolagents 리포지토리에는 Google Colab 또는 SageMaker Studio Lab에서 바로 실행할 수 있는 이 예제가 포함되어 있으며, 이 패턴을 자신의 데이터베이스에 맞게 조정하기 위한 훌륭한 시작점이 될 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기