Data Science/Research

SQL2NL Prompt Engineering - KCC(3)

eatplaylove 2025. 4. 14. 11:24

https://eglife.tistory.com/342

 

SQL2NL Prompt Engineering - KCC(2)

https://eglife.tistory.com/341 SQL2NL Prompt Engineering - KCC(1)SQL2NL Module의 정확도를 향상시키는 법에대한 고찰이다. 일단 생각해낼 것은, 어찌어찌 SQL2NL 정확도 올리는 법을 찾았다고 쳤을때 그 것을 어찌

eglife.tistory.com

지난 시간 충격적인 결과,

SQL to NL 모델을 이용할 때 되려 Naive한 Model이 Table Schema or Parsing Info가 추가된 Version보다 각 종 Accuracy Matrix 지표가 더 높았다.

얼핏봐도 Naive한 version에서 각종 Score가 높게 나타난다-_-; --> 근데, 이건 알고보니 GPT4o mini가 아니라 일반4o다!

 

그말은 즉슨, 어느 정도 Massage가 필요하다는 것..

 

일단,

 1. Parsing Info 부분을 좀 더 손 본다. 지금 Version은 너무 허접하다

 2. 평가지표를 좀 더 추가한다. Naive한 Version이 Weak한 지표

 3. Llama 7b 등 후진 LLM을 사용한다. 그러면 Naive한 Version의 정확도가 낮겠지..?

 

차근 차근 처리해나가보자

 

1. Parsing Info 부분을 좀 더 손 본다. 지금 Version은 너무 허접하다

 

SQL문을 Parsing 해주는 SQL GLOT이라는 친구를 이용해서 Parsing 부분을 좀 보강했다.

https://medium.com/@abhishekdas69597/python-meets-sqlglot-seamlessly-parse-and-convert-sql-queries-6b8e2f648fb0

 

Python Meets SQLGlot: Seamlessly Parse and Convert SQL Queries

Have you ever found yourself jumping between SQL dialects — MySQL, SparkSQL, PostgreSQL, Hive — and getting tripped up by subtle syntax…

medium.com

# ✅ Parsing Info 생성기 (SQLGlot 기반)
def generate_parsing_info_sqlglot(sql_query: str) -> str:
    try:
        cleaned_sql = clean_sql_for_sqlglot(sql_query)
        parsed = sqlglot.parse_one(cleaned_sql)
        result = []

        for sel in parsed.find_all(Select):
            for expr in sel.expressions:
                if isinstance(expr, Func):
                    func_name = expr.sql_name().upper()
                    target = expr.this.sql() if expr.this else "*"
                    if expr.args.get("distinct"):
                        result.append(f"{func_name} of DISTINCT {target}")
                    else:
                        result.append(f"{func_name} of {target}")
                else:
                    result.append(f"Select column {expr.sql()}")

        from_tables = parsed.find_all(Table)
        tables = []
        for t in from_tables:
            name = t.name
            alias = t.alias_or_name
            if alias != name:
                tables.append(f"{alias} = {name}")
            else:
                tables.append(name)
        if tables:
            result.append(f"From table(s): {', '.join(tables)}")

        for join in parsed.find_all(Join):
            join_type = join.args.get("kind", "INNER").upper()
            table = join.this.alias_or_name
            result.append(f"{join_type} JOIN with table {table}")
            if join.args.get("on"):
                result.append(f"Join condition: {join.args['on'].sql()}")

        if parsed.args.get("where"):
            result.append(f"Filter condition: {parsed.args['where'].this.sql()}")

        if parsed.args.get("group"):
            group_cols = [g.sql() for g in parsed.args['group'].expressions]
            result.append(f"Grouped by: {', '.join(group_cols)}")

        if parsed.args.get("having"):
            result.append(f"Having condition: {parsed.args['having'].sql()}")

        if parsed.args.get("order"):
            for o in parsed.args["order"].expressions:
                col = o.this.sql()
                direction = "descending" if o.args.get("desc") else "ascending"
                result.append(f"Sorted by: {col} in {direction} order")

        return " | ".join(result)

    except Exception as e:
        return f"[Parsing Error] {e}"

사실상 Rule Based로 움직이는 거라서 이 세상 모든 SQL문을 다 커버하지는 못하겠지만, 그래도 대충 어느 정도 SQL문을 커버하긴 한다고 판단.. 그래도 영 찝찝하긴 하다.

 

 2. 평가지표를 좀 더 추가한다. Naive한 Version이 Weak한 지표

 

아나 이 Matrix 녀석들을 추가만 하려고 하면 Local Jupyternotebook에서 자꾸 ERROR가 난다. Module Import는 제일 간단하고 당연히 되어야 하는 것인데 왜 이리 삐걱거리는지..

 

어느정도 초기 실험만 진행하고 나면 실험 Platform을 Google Colab으로 옮겨야 겠다.

그래도 꾸역꾸역 BERTScore와(Semantic 기반) ROUGE-L(n-gram 기반)는 구현했는데, 하나만 더 확인해보면 좋을 거 같아서 BARTScore라는 친구를 섭외중인데 자꾸만 Error가 뜬다 -_-

https://github.com/neulab/BARTScore

 

GitHub - neulab/BARTScore: BARTScore: Evaluating Generated Text as Text Generation

BARTScore: Evaluating Generated Text as Text Generation - neulab/BARTScore

github.com

이 BARTScore라는 친구는 LLM기반 의미 유사도를 나타낸다고 한다.

행 레이블 평균 :BERTScore_Precision 평균:BERTScore_Recall 평균:BERTScore_F1 평균:ROUGE_L
naive 0.555243507 0.656571782 0.599943502 0.302555951
naive+parsing 0.532932121 0.642146792 0.581089028 0.276398327
naive+table_schema 0.54466723 0.657748947 0.594467975 0.294097353
총 평균 0.544280953 0.65215584 0.591833502 0.29101721

 

일단 BART Score도 잘 나오지 않아서 BERT , ROUGE 를 가지고 진행했다. GPT 4o mini Naive 왜케 좋냐. Prompt를 추가했는데 정확도가 줄어드는 현상이다 ㅠㅠ Bird Data set 150ea 가지고 test를 돌린 결과이다.

Model이 그래도 좀 더 후질거라고 판단되는 GPT 3.5 Turbo로도 함 돌려보련다..

GPT3.5-turbo (BIRD Data) 평균 : BERTScore_Precision 평균 : BERTScore_Recall 평균 : BERTScore_F1 평균 : ROUGE_L
naive 0.600441869 0.67114907 0.631691917 0.360542455
naive+parsing 0.530655225 0.631048029 0.574595395 0.31253113
naive+table_schema 0.583881952 0.674307453 0.622885662 0.357007537
총합계 0.571659682 0.658834851 0.609724325 0.343360374

 

GPT3.5 Turbo도 결과는 비슷하다 이런.. Llama에 다음 결과를 맡겨봐야겄다 ㅠ

일단 보기 좋게 아래와 같이 데이터를 갖고 있어야 겠다.

GPT4o-mini (BIRD Data) 평균 : BERTScore_Recall 평균 : ROUGE_L
naive 0.656571782 0.302555951
naive+parsing 0.642146792 0.276398327
naive+table_schema 0.657748947 0.294097353
총 평균 0.65215584 0.29101721
GPT3.5-turbo (BIRD Data) 평균 : BERTScore_Recall 평균 : ROUGE_L
naive 0.67114907 0.360542455
naive+parsing 0.631048029 0.31253113
naive+table_schema 0.674307453 0.357007537
총합계 0.658834851 0.343360374

Colab으로 BLEU-4 Score , BARTScore도 추가했다. BERTScore는 그나마 위 Table에서 차이가 있던 Recall만 쓰는 것으로..

✅ 1. BLEU-4 Score

📌 정의

BLEU (Bilingual Evaluation Understudy)는 기계 번역 성능 평가에 널리 쓰이는 지표입니다.
BLEU-44-gram precision을 기준으로 생성된 문장과 참조문이 얼마나 유사한지 평가합니다.

📊 범위

📈 값이 클수록?

  • 좋다 (문장이 참조문과 더 유사하다)
  • 단어, 구문 순서, 표현 방식이 정확히 일치할수록 높은 점수

⚠️ 주의

  • BLEU는 정확히 일치하는 단어 조합이 많아야 점수 상승
  • 의미는 비슷해도 표현 방식이 다르면 점수 낮게 나올 수 있음

✅ 2. BARTScore

📌 정의

BARTScore는 사전학습된 BART 언어모델의 로그 생성 확률을 기반으로
"참조 문장을 생성할 수 있을 정도로, 입력 문장이 얼마나 의미적으로 유사한가"를 평가합니다.

📊 범위

  • 실제 점수는 BART의 log-likelihood 평균값이므로 음수가 많지만,
    더 클수록 의미적으로 더 유사한 문장으로 간주됩니다.

📈 값이 클수록?

  • 좋다
  • 생성 문장이 참조 문장과 의미적으로 거의 동일하다고 판단됨
  • GPT나 사람 수준의 표현을 잘 반영했을 때 높은 점수가 나옴

다시 Sample 100ea BIRD/Spider Data set을 통해 측정한 GPT SQL2NL 정확도 지표요약..

GPT-4o-mini-BIRD
GPT-4o-mini-Spider
GPT-3.5-Turbo-BIRD

GPT-3.5-Turbo-Spider

 

각 Evaluation Matrix에 대한 자세한 설명은 요기

https://eglife.tistory.com/344

 

English Natural Language Evaluation Matrix

영어 문장간의 Word 또는 Semantic(문맥) 을 기준으로 일치성, 통일성, Accuracy를 비교하는 Matrix에 대한 설명이다.SQL을 NL(Natural Language)로 변환하는 과정에서 NL이 기존 답안 NL과 비교했을 때 얼마나 정

eglife.tistory.com

 

 3. Llama 7b 등 후진 LLM을 사용한다. 그러면 Naive한 Version의 정확도가 낮겠지..?

 

지금 GPT 4o mini는 생각보다 성능이 좋다. 좀 더 꾸진 Light한 LLM에서의 실험이 필요하다.

그리고 위 2번 항목의 Evaluation Matrix를 추가하기 위해.. google colab으로 실험환경 옮겨보기..!


아.. Ollama는 Local에서는 돌아가는데 Colab에서는 돌아가지 않는다고 한다.. colab은 Google의 Cloud Server라는 것..ㅠㅠ

 

다시 Ollama 작업은 Local에서 진행해야할 거 같다.

 

근데 문제는 Local에선 Llama가 너무 느리다. Prompt를 넣어서 그런가.. GPT는 API를 타고와도 거의 Query 한 개당 6초면 작업이 진행되었는데 Llama는 Program 돌리기만 하면 함흥차사다 -_-;;;

일단 코드를 돌리고 있긴 한데 정말 너무 느리다.. Bird / Spider 모든 DataSet에서 돌리는건 완전 무리가 있을 거 같고, 한 100개 정도씩만(이것도 느리다..) 돌려봐야겠다. 아니면 이런 머신러닝 Model을 유료로 돌려주는 사이트가 있다던데 그것을 이용해봐야겠다.

 

좀전에 또 Local에서 돌린 실험Data가 뻑(?)이 났다. 바료 유료사이트 결제...

https://console.runyour.ai/gpu-cloud

 

Runyour AI

Runyour AI(런뉴어 AI)는 클라우드 기반 AI 개발 플랫폼으로, GPU 서버와 데이터 분석 도구로 비용 절감과 고성능 AI 솔루션을 제공합니다.

www.runyour.ai

 

역시 빠르다. 시간당 얼마~ 개념으로 장사를 하는 사이트인데, 쫄려서 GPU 싼 걸 골랐는데도 성능이 확실히 좋다.

에효... 어차피 시간단위로 계산되는 거, GPU 빡센걸 고를 걸 하는 후회가 된다.. ㅎㅎ 뭐.. 처음 써보는 거니까~~

 

Llama BIRD Dataset으로 100ea local에서 꾸역꾸역 Test 돌린결과는 아래와 같다.

Recall 부분에서 아무래도 Navie보다 Table Shema 추가버전의 Accuracy가 더 높은 것을 볼 수 있다. 이 부분에 집중해서 논문을 써나가야겠다.

 

Llama3 8b - local 환경

다시 BIRD Dev SET 약 1533ea 와 Spider Dev SET 약 1034ea를 돌려서 평가지표 결과를 뽑아내야겠다.

Data를 일단 갖고 있으면 이것들을 어떻게 요리할 지 각이 보일 것이다.

 

250410 19:30, 지금은 해당 과정 Calculating....


결과가 나왔으니 정리해보자 일단 GPT-4o-mini 와 Llama3_8b 즉 Light한 LLM만을 사용했다.

Data set은 BIRD_1533ea / Spider_1034ea dev set 다 돌렸다.

 

 

gpt-4o_mini_Bird의 경우 다시 돌리면 아래와 같이 Table이 BERTScore에서 1등하는 데이터도 얻을 수 있다.

즉, 수차례 실험 데이터를 필두로, BERTScore의 Recall / BARTScore의 경우 Table Schema를 Prompt로 추가하는 것이 Semantic 추론에 더 좋다는 것을 알 수 있다.

 

근데, 또 Llama3_70b로 했을땐 parsing 기법의 정확도가 괜찮게 나왔다. 오호..

Light LLM의 경우 Table Prompt, Heavy LLM의 경우 Parsing Prompt가 효과가 좋은 것인가..?  Bird로만 해봤는데 Spider Dataset으로 추가실험 해보고 결론지어야 겠다.

 

취합한 Data 중 Table Schema가 Prompt로 있는 버전의 SQL2NL 변환 정확도가 큰 것을 따와서 논문작성!

 

일단 글이 너무 길어지니 여기서 한 번 컷을 줘야겠다.

 

다음 Turn에는 본격적인 논문작성으로..!