Skip to content

Feature/10 보여주는 결과의 확장 필요성 #55

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
388 changes: 388 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_0.json

Large diffs are not rendered by default.

368 changes: 368 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_1.json

Large diffs are not rendered by default.

398 changes: 398 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_2.json

Large diffs are not rendered by default.

388 changes: 388 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_3.json

Large diffs are not rendered by default.

373 changes: 373 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_4.json

Large diffs are not rendered by default.

378 changes: 378 additions & 0 deletions data/q_sql/default_0.0.1/eval_result_5.json

Large diffs are not rendered by default.

477 changes: 477 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_0.json

Large diffs are not rendered by default.

448 changes: 448 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_1.json

Large diffs are not rendered by default.

472 changes: 472 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_2.json

Large diffs are not rendered by default.

447 changes: 447 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_3.json

Large diffs are not rendered by default.

456 changes: 456 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_4.json

Large diffs are not rendered by default.

442 changes: 442 additions & 0 deletions data/q_sql/refine_update_0.0.1/eval_result_5.json

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions data/questions/0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"questions": [
"이 데이터베이스에서 가장 최근에 등록된 고객 정보는 무엇인가요? ",
"특정 날짜 범위 내의 주문 내역을 어떻게 조회하나요? ",
"제품별 판매량을 내림차순으로 정렬하는 SQL 쿼리를 알려주세요. ",
"고객의 이름과 연락처 정보를 한 번에 조회하는 방법은 무엇인가요? ",
"주문 상태가 '배송완료'인 주문 건수는 몇 건인가요? ",
"특정 고객의 구매 이력을 어떻게 분석할 수 있나요? ",
"매출액이 높은 상위 10개 상품을 찾는 SQL 쿼리를 보여주세요. ",
"날짜별 매출 추이를 그래프로 나타내려면 어떤 쿼리를 사용해야 하나요? ",
"재고가 10개 이하인 상품 목록을 조회하는 방법은 무엇인가요? ",
"고객 테이블과 주문 테이블을 조인하는 SQL 쿼리를 알려주세요."
],
"questions_md": "- 이 데이터베이스에서 가장 최근에 등록된 고객 정보는 무엇인가요? \n- 특정 날짜 범위 내의 주문 내역을 어떻게 조회하나요? \n- 제품별 판매량을 내림차순으로 정렬하는 SQL 쿼리를 알려주세요. \n- 고객의 이름과 연락처 정보를 한 번에 조회하는 방법은 무엇인가요? \n- 주문 상태가 '배송완료'인 주문 건수는 몇 건인가요? \n- 특정 고객의 구매 이력을 어떻게 분석할 수 있나요? \n- 매출액이 높은 상위 10개 상품을 찾는 SQL 쿼리를 보여주세요. \n- 날짜별 매출 추이를 그래프로 나타내려면 어떤 쿼리를 사용해야 하나요? \n- 재고가 10개 이하인 상품 목록을 조회하는 방법은 무엇인가요? \n- 고객 테이블과 주문 테이블을 조인하는 SQL 쿼리를 알려주세요.",
"persona": {
"name": "김민수",
"department": "영업팀",
"role": "영업 관리자",
"background": "다양한 고객 데이터를 분석하여 매출 증대를 위한 전략 수립 경험이 풍부함."
}
}
21 changes: 21 additions & 0 deletions data/questions/1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"questions": [
"이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? ",
"고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. ",
"주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? ",
"특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. ",
"상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? ",
"데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? ",
"날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. ",
"특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. ",
"고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? ",
"여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요."
],
"questions_md": "- 이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? \n- 고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. \n- 주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? \n- 특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. \n- 상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? \n- 데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? \n- 날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. \n- 특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. \n- 고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? \n- 여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요.",
"persona": {
"name": "이수진",
"department": "인사팀",
"role": "인사 담당자",
"background": "직원 정보와 인사 기록을 관리하며, 인사 정책에 대한 데이터 기반 의사결정을 수행함."
}
}
21 changes: 21 additions & 0 deletions data/questions/2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"questions": [
"이 데이터베이스에서 가장 최근에 등록된 고객 정보는 무엇인가요? ",
"특정 날짜 범위 내의 주문 내역을 어떻게 조회하나요? ",
"제품별 판매량을 내림차순으로 정렬하는 SQL 쿼리를 알려주세요. ",
"고객의 이름과 연락처 정보를 한 번에 조회하는 방법은 무엇인가요? ",
"주문 상태가 '배송완료'인 주문 건수는 몇 건인가요? ",
"특정 고객의 구매 이력을 어떻게 분석할 수 있나요? ",
"매출액이 높은 상위 10개 상품을 찾는 SQL 쿼리를 보여주세요. ",
"날짜별 매출 추이를 그래프로 나타내려면 어떤 쿼리를 사용해야 하나요? ",
"재고가 10개 이하인 상품 목록을 조회하는 방법은 무엇인가요? ",
"고객 테이블과 주문 테이블을 조인하는 SQL 쿼리를 알려주세요."
],
"questions_md": "- 이 데이터베이스에서 가장 최근에 등록된 고객 정보는 무엇인가요? \n- 특정 날짜 범위 내의 주문 내역을 어떻게 조회하나요? \n- 제품별 판매량을 내림차순으로 정렬하는 SQL 쿼리를 알려주세요. \n- 고객의 이름과 연락처 정보를 한 번에 조회하는 방법은 무엇인가요? \n- 주문 상태가 '배송완료'인 주문 건수는 몇 건인가요? \n- 특정 고객의 구매 이력을 어떻게 분석할 수 있나요? \n- 매출액이 높은 상위 10개 상품을 찾는 SQL 쿼리를 보여주세요. \n- 날짜별 매출 추이를 그래프로 나타내려면 어떤 쿼리를 사용해야 하나요? \n- 재고가 10개 이하인 상품 목록을 조회하는 방법은 무엇인가요? \n- 고객 테이블과 주문 테이블을 조인하는 SQL 쿼리를 알려주세요.",
"persona": {
"name": "박지훈",
"department": "마케팅팀",
"role": "마케팅 분석가",
"background": "시장 트렌드와 고객 행동 데이터를 분석하여 마케팅 캠페인 최적화에 기여함."
}
}
21 changes: 21 additions & 0 deletions data/questions/3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"questions": [
"이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? ",
"고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. ",
"주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? ",
"특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. ",
"상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? ",
"데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? ",
"날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. ",
"특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. ",
"고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? ",
"여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요."
],
"questions_md": "- 이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? \n- 고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. \n- 주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? \n- 특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. \n- 상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? \n- 데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? \n- 날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. \n- 특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. \n- 고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? \n- 여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요.",
"persona": {
"name": "최영희",
"department": "재무팀",
"role": "재무 분석가",
"background": "재무 데이터와 보고서를 분석하여 회사의 재무 상태를 모니터링하고 보고함."
}
}
21 changes: 21 additions & 0 deletions data/questions/4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"questions": [
"이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? ",
"고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. ",
"주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? ",
"특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. ",
"상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? ",
"데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? ",
"날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. ",
"특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. ",
"고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? ",
"여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요."
],
"questions_md": "- 이 테이블에서 특정 날짜 이후의 모든 데이터를 조회하는 SQL 쿼리를 어떻게 작성하나요? \n- 고객 이름과 주문 금액만 선택하는 SQL 문을 만들어 주세요. \n- 주문 테이블에서 주문 상태가 '완료'인 데이터만 필터링하는 방법은 무엇인가요? \n- 특정 고객의 주문 내역을 검색하는 SQL 쿼리를 알려 주세요. \n- 상품별 평균 가격을 계산하는 SQL 쿼리를 어떻게 작성하나요? \n- 데이터베이스에서 중복된 레코드를 제거하는 SQL 문은 무엇인가요? \n- 날짜별 주문 건수를 집계하는 SQL 쿼리를 만들어 주세요. \n- 특정 조건에 맞는 데이터를 업데이트하는 SQL 문을 알려 주세요. \n- 고객 테이블에서 이메일 주소가 비어 있지 않은 레코드만 선택하는 방법은 무엇인가요? \n- 여러 테이블을 조인하여 고객 이름과 주문 내역을 함께 조회하는 SQL 쿼리를 작성해 주세요.",
"persona": {
"name": "장민호",
"department": "IT팀",
"role": "데이터베이스 관리자",
"background": "데이터베이스 설계와 유지보수 경험이 있으며, 데이터의 무결성과 보안을 책임지고 있음."
}
}
92 changes: 92 additions & 0 deletions evaluation/gen_answer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from argparse import ArgumentParser
from langchain_core.messages import HumanMessage

from utils import load_question_json, save_answer_json

from tqdm import tqdm
import uuid

from llm_utils.graph import builder


def get_eval_result(
graph,
name=None,
version=None,
desc="",
debug=False,
input_dir="data/questions",
output_dir="data/q_sql",
):

if name is None:
# random name
name = str(uuid.uuid4())

if version is None:
version = "0.0.1"

results = load_question_json(input_dir)

for i, result in tqdm(enumerate(results), desc="Processing results"):
inputs = []
for question in result["questions"]:
inputs.append(
{
"messages": [HumanMessage(content=question)],
"user_database_env": "duckdb",
"best_practice_query": "",
}
)
response = graph.batch(inputs)
answers = []
for res in response:
refined_input_content = (
res["refined_input"].content
if hasattr(res["refined_input"], "content")
else res["refined_input"]
)
answers.append(
{
"user_database_env": res["user_database_env"],
"answer_SQL": res["generated_query"],
"answer_explanation": res["messages"][-1].content,
"question_refined": refined_input_content,
"searched_tables": res["searched_tables"],
}
)

# debug 모드일 때 결과를 print로 확인
if debug:
print(f"질문: {result['questions']}")
print(f"답변: {answers}")

result["answers"] = answers
result["name"] = name
result["version"] = version
result["desc"] = desc

save_answer_json(result, f"{output_dir}/{name}_{version}", i)


if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--input_dir", type=str, default="data/questions")
parser.add_argument("--output_dir", type=str, default="data/q_sql")
parser.add_argument("--name", type=str, default=None)
parser.add_argument("--version", type=str, default=None)
parser.add_argument("--desc", type=str, default="")
parser.add_argument("--debug", type=bool, default=False)
args = parser.parse_args()

graph = builder.compile() # langgraph 모델 load하여 사용하세요

get_eval_result(
graph,
name=args.name,
version=args.version,
desc=args.desc,
input_dir=args.input_dir,
output_dir=args.output_dir,
debug=args.debug,
)
49 changes: 49 additions & 0 deletions evaluation/gen_persona.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os

from utils import save_persona_json, pretty_print_persona
from persona_class import PersonaList

from llm_utils.tools import _get_table_info
from langchain_openai.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from argparse import ArgumentParser


def get_table_des_string(tables_desc):
return_string = "table name : table description\n---\n"
for table_name, table_desc in tables_desc.items():
return_string += f"{table_name} : {table_desc}\n---\n"
return return_string


def generate_persona(tables_desc):
description_string = get_table_des_string(tables_desc)

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
system_prompt = """주어진 Tabel description들을 참고하여 Text2SQL 서비스로 질문을 할만한 패르소나를 생성하세요"""

prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
]
)

chain = prompt | llm.with_structured_output(PersonaList)
return chain.invoke({"input": description_string})


def main(output_path):
# 데이터허브 서버 연결
tables_desc = _get_table_info()
personas = generate_persona(tables_desc)

for persona in personas.personas:
print(pretty_print_persona(persona))
save_persona_json(personas, output_path)


if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--output_path", type=str, default="data/personas.json")
args = parser.parse_args()
main(args.output_path)
72 changes: 72 additions & 0 deletions evaluation/gen_question.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from utils import load_persona_json, save_question_json
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai.chat_models import ChatOpenAI
from tqdm import tqdm

from argparse import ArgumentParser
import os


def get_persona_prompt(persona):
return f"""
Name: {persona.name}
Department: {persona.department}
Role: {persona.role}
Background: {persona.background}
"""


def split_question(question):
question = question.content
# remove -
question = question.replace("- ", "")
return question.split("\n")


def gen_question(persona):
llm = llm = ChatOpenAI(model="gpt-4.1-nano", temperature=0)
prompt = get_persona_prompt(persona)
system_prompt = """당신은 <persona> 에 해당하는 사람이며 Text2SQL 서비스를 사용하고 있다. 궁금한 질문들을 아래 <format> 에 해당하는 형식으로 질문하라 질문은 다양하게 생성하라

<persona>
{persona_prompt}
</persona>

<format>
- 질문 1
- 질문 2
- 질문 3
...
- 질문 n
</format>
"""
prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
]
)

chain = prompt | llm
result = {}

question = chain.invoke({"persona_prompt": prompt})
result["questions"] = split_question(question)
result["questions_md"] = question.content
result["persona"] = persona
return result


def main(persona_path, output_dir):
personas = load_persona_json(persona_path)
for i, persona in tqdm(enumerate(personas.personas)):
result = gen_question(persona)
file_path = os.path.join(output_dir, f"{i}.json")
save_question_json(result, file_path)


if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--persona_path", type=str, default="data/personas.json")
parser.add_argument("--output_dir", type=str, default="data/questions")
args = parser.parse_args()
main(args.persona_path, args.output_dir)
13 changes: 13 additions & 0 deletions evaluation/persona_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pydantic import BaseModel
from typing import List


class Persona(BaseModel):
name: str
department: str
role: str
background: str


class PersonaList(BaseModel):
personas: List[Persona]
Loading