1111from llm_utils .chains import (
1212 query_refiner_chain ,
1313 query_maker_chain ,
14+ query_refiner_with_profile_chain ,
15+ profile_extraction_chain ,
16+ query_enrichment_chain ,
1417)
1518
1619from llm_utils .tools import get_info_from_db
1720from llm_utils .retrieval import search_tables
21+ from llm_utils .utils import profile_to_text
1822
1923# 노드 식별자 정의
2024QUERY_REFINER = "query_refiner"
2125GET_TABLE_INFO = "get_table_info"
2226TOOL = "tool"
2327TABLE_FILTER = "table_filter"
2428QUERY_MAKER = "query_maker"
29+ PROFILE_EXTRACTION = "profile_extraction"
30+ CONTEXT_ENRICHMENT = "context_enrichment"
2531
2632
2733# 상태 타입 정의 (추가 상태 정보와 메시지들을 포함)
@@ -31,12 +37,38 @@ class QueryMakerState(TypedDict):
3137 searched_tables : dict [str , dict [str , str ]]
3238 best_practice_query : str
3339 refined_input : str
40+ question_profile : dict
3441 generated_query : str
3542 retriever_name : str
3643 top_n : int
3744 device : str
3845
3946
47+ # 노드 함수: PROFILE_EXTRACTION 노드
48+ def profile_extraction_node (state : QueryMakerState ):
49+ """
50+ 자연어 쿼리로부터 질문 유형(PROFILE)을 추출하는 노드입니다.
51+
52+ 이 노드는 주어진 자연어 쿼리에서 질문의 특성을 분석하여, 해당 질문이 시계열 분석, 집계 함수 사용, 조건 필터 필요 여부,
53+ 그룹화, 정렬/순위, 기간 비교 등 다양한 특성을 갖는지 여부를 추출합니다.
54+
55+ 추출된 정보는 `QuestionProfile` 모델에 맞춰 저장됩니다. `QuestionProfile` 모델의 필드는 다음과 같습니다:
56+ - `is_timeseries`: 시계열 분석 필요 여부
57+ - `is_aggregation`: 집계 함수 필요 여부
58+ - `has_filter`: 조건 필터 필요 여부
59+ - `is_grouped`: 그룹화 필요 여부
60+ - `has_ranking`: 정렬/순위 필요 여부
61+ - `has_temporal_comparison`: 기간 비교 포함 여부
62+ - `intent_type`: 질문의 주요 의도 유형
63+
64+ """
65+ result = profile_extraction_chain .invoke ({"question" : state ["messages" ][0 ].content })
66+
67+ state ["question_profile" ] = result
68+ print ("profile_extraction_node : " , result )
69+ return state
70+
71+
4072# 노드 함수: QUERY_REFINER 노드
4173def query_refiner_node (state : QueryMakerState ):
4274 res = query_refiner_chain .invoke (
@@ -52,6 +84,80 @@ def query_refiner_node(state: QueryMakerState):
5284 return state
5385
5486
87+ # 노드 함수: QUERY_REFINER 노드
88+ def query_refiner_with_profile_node (state : QueryMakerState ):
89+ """
90+ 자연어 쿼리로부터 질문 유형(PROFILE)을 사용해 자연어 질의를 확장하는 노드입니다.
91+
92+ """
93+
94+ profile_bullets = profile_to_text (state ["question_profile" ])
95+ res = query_refiner_with_profile_chain .invoke (
96+ input = {
97+ "user_input" : [state ["messages" ][0 ].content ],
98+ "user_database_env" : [state ["user_database_env" ]],
99+ "best_practice_query" : [state ["best_practice_query" ]],
100+ "searched_tables" : [json .dumps (state ["searched_tables" ])],
101+ "profile_prompt" : [profile_bullets ],
102+ }
103+ )
104+ state ["messages" ].append (res )
105+ state ["refined_input" ] = res
106+
107+ print ("refined_input before context enrichment : " , res .content )
108+ return state
109+
110+
111+ # 노드 함수: CONTEXT_ENRICHMENT 노드
112+ def context_enrichment_node (state : QueryMakerState ):
113+ """
114+ 주어진 질문과 관련된 메타데이터를 기반으로 질문을 풍부하게 만드는 노드입니다.
115+
116+ 이 함수는 `refined_question`, `profiles`, `related_tables` 정보를 이용하여 자연어 질문을 보강합니다.
117+ 보강 과정에서는 질문의 의도를 유지하면서, 추가적인 세부 정보를 제공하거나 잘못된 용어를 수정합니다.
118+
119+ 주요 작업:
120+ - 주어진 질문의 메타데이터 (`question_profile` 및 `searched_tables`)를 활용하여, 질문을 수정하거나 추가 정보를 삽입합니다.
121+ - 질문이 시계열 분석 또는 집계 함수 관련인 경우, 이를 명시적으로 강조합니다 (예: "지난 30일 동안").
122+ - 자연어에서 실제 열 이름 또는 값으로 잘못 매칭된 용어를 수정합니다 (예: ‘미국’ → ‘USA’).
123+ - 보강된 질문을 출력합니다.
124+
125+ Args:
126+ state (QueryMakerState): 쿼리와 관련된 상태 정보를 담고 있는 객체.
127+ 상태 객체는 `refined_input`, `question_profile`, `searched_tables` 등의 정보를 포함합니다.
128+
129+ Returns:
130+ QueryMakerState: 보강된 질문이 포함된 상태 객체.
131+
132+ Example:
133+ Given the refined question "What are the total sales in the last month?",
134+ the function would enrich it with additional information such as:
135+ - Ensuring the time period is specified correctly.
136+ - Correcting any column names if necessary.
137+ - Returning the enriched version of the question.
138+ """
139+
140+ searched_tables = state ["searched_tables" ]
141+ searched_tables_json = json .dumps (searched_tables , ensure_ascii = False , indent = 2 )
142+
143+ question_profile = state ["question_profile" ].model_dump ()
144+ question_profile_json = json .dumps (question_profile , ensure_ascii = False , indent = 2 )
145+
146+ enriched_text = query_enrichment_chain .invoke (
147+ input = {
148+ "refined_question" : state ["refined_input" ],
149+ "profiles" : question_profile_json ,
150+ "related_tables" : searched_tables_json ,
151+ }
152+ )
153+
154+ state ["refined_input" ] = enriched_text
155+ state ["messages" ].append (enriched_text )
156+ print ("After context enrichment : " , enriched_text .content )
157+
158+ return state
159+
160+
55161def get_table_info_node (state : QueryMakerState ):
56162 # retriever_name과 top_n을 이용하여 검색 수행
57163 documents_dict = search_tables (
0 commit comments