11from langchain_core .messages import SystemMessage , AIMessage
2+ import re
23
34from core .shared .states .states import CustomsAgentState
45from core .shared .utils .llm import get_llm
6+ from core .shared .constants import (
7+ TARIFF_SESSION_KEYWORDS ,
8+ NUMBER_SELECTION_PATTERNS ,
9+ TARIFF_PREDICTION_KEYWORDS ,
10+ CUSTOMS_TRACKING_KEYWORDS ,
11+ INTENT_CLASSIFICATION_PROMPT ,
12+ INTENT_TYPES ,
13+ DEFAULT_INTENT
14+ )
515
616def intent_router (state : CustomsAgentState ) -> CustomsAgentState :
717 """사용자 쿼리의 의도를 분류합니다."""
@@ -15,10 +25,7 @@ def intent_router(state: CustomsAgentState) -> CustomsAgentState:
1525 if hasattr (msg , 'content' ) and isinstance (msg .content , str ):
1626 content = msg .content .lower ()
1727 # 관세 예측 관련 키워드가 있거나 HS 코드 선택 메시지가 있으면 관세 예측 세션으로 판단
18- if any (keyword in content for keyword in [
19- 'hs6 코드 후보' , 'hs10 코드 후보' , '번호를 선택' , '관세 계산' , '관세 예측' ,
20- '상품묘사' , '구매 국가' , '상품 가격' , '시나리오 선택' , 'tariff_prediction'
21- ]):
28+ if any (keyword in content for keyword in TARIFF_SESSION_KEYWORDS ):
2229 is_in_tariff_session = True
2330 break
2431
@@ -29,21 +36,19 @@ def intent_router(state: CustomsAgentState) -> CustomsAgentState:
2936 if 'tariff_prediction' in last_msg .content :
3037 is_in_tariff_session = True
3138
39+ # 관세 예측 세션 중이면 무조건 tariff_prediction으로 분류
40+ if is_in_tariff_session :
41+ state ["intent" ] = "tariff_prediction" # type: ignore
42+ state ["messages" ].append (AIMessage (content = f"의도 분류 완료: { state ['intent' ]} (관세 예측 세션 연속성 유지)" ))
43+ print (state )
44+ return state
45+
3246 # 현재 쿼리가 숫자 선택인지 확인
3347 current_query = state ["query" ].strip ()
3448 is_number_selection = False
3549
3650 # 숫자 선택 패턴 확인 (1번, 2번, 3번, 1, 2, 3 등)
37- import re
38- number_patterns = [
39- r'^\d+번?$' , # 1번, 2번, 3번
40- r'^\d+$' , # 1, 2, 3
41- r'^\d+\.?\d*$' , # 8471.60, 8517.70 등 HS 코드
42- r'^\d{4,6}$' , # 8471, 851770 등 HS 코드
43- r'^\d{4}\.\d{2}$' , # 8471.60 등 HS 코드
44- ]
45-
46- for pattern in number_patterns :
51+ for pattern in NUMBER_SELECTION_PATTERNS :
4752 if re .match (pattern , current_query ):
4853 is_number_selection = True
4954 break
@@ -63,42 +68,35 @@ def intent_router(state: CustomsAgentState) -> CustomsAgentState:
6368 print (state )
6469 return state
6570
66- # 일반적인 의도 분류
67- llm = get_llm ()
71+ # 관세 예측 관련 키워드가 있으면 무조건 tariff_prediction으로 분류
72+ current_query_lower = current_query .lower ()
73+ if any (keyword in current_query_lower for keyword in TARIFF_PREDICTION_KEYWORDS ):
74+ state ["intent" ] = "tariff_prediction" # type: ignore
75+ state ["messages" ].append (AIMessage (content = f"의도 분류 완료: { state ['intent' ]} (관세 예측 키워드 감지)" ))
76+ print (state )
77+ return state
6878
69- classification_prompt = """
70- 다음 사용자 쿼리를 아래 세 카테고리 중 하나로 분류하세요.
71-
72- 1. customs_tracking: 운송장, 배송, 통관, 조회, 추적, 배송상태, 위치, 도착, 출고, 통관번호, 운송장번호 등
73- 2. tariff_prediction: 관세, 세금, 세율, 관세 계산, 관세 예측, 세금 얼마, 관세 얼마, 관세 계산해줘, 관세 예측해줘, 세금 예측, 예상 관세, 뭘 샀어, 뭐 샀어, 샀어, 구매 등
74- 3. qna: 관세청 정보, 전화번호, 법령, 수입/수출 절차, 일반 안내, 기타 FAQ
75-
76- # 예시
77- - "관세 예측해줘" → tariff_prediction
78- - "관세 계산해줘" → tariff_prediction
79- - "이 물건의 세금이 얼마나 나올까?" → tariff_prediction
80- - "노트북 샀어" → tariff_prediction
81- - "미국에서 뭐 샀어" → tariff_prediction
82- - "운송장 번호 123456 어디쯤이야?" → customs_tracking
83- - "배송이 어디까지 왔어?" → customs_tracking
84- - "통관 진행 상황 알려줘" → customs_tracking
85- - "관세청 전화번호 알려줘" → qna
86- - "수입 절차가 궁금해" → qna
87- - "관세청 홈페이지 알려줘" → qna
88- - "관세법 제12조가 뭐야?" → qna
89-
90- 사용자 쿼리: {query}
91-
92- 반드시 다음 중 하나만 응답하세요: customs_tracking, tariff_prediction, qna
93- """
79+ # 운송장/배송 관련 키워드가 있으면 customs_tracking으로 분류
80+ if any (keyword in current_query_lower for keyword in CUSTOMS_TRACKING_KEYWORDS ):
81+ state ["intent" ] = "customs_tracking" # type: ignore
82+ state ["messages" ].append (AIMessage (content = f"의도 분류 완료: { state ['intent' ]} (배송 추적 키워드 감지)" ))
83+ print (state )
84+ return state
9485
95- result = llm .invoke ([
96- SystemMessage (content = classification_prompt .format (query = state ["query" ]))
97- ])
86+ # 일반적인 의도 분류 (LLM 사용)
87+ llm = get_llm ()
9888
99- intent = str (result .content ).strip ()
100- if intent not in ["customs_tracking" , "tariff_prediction" , "qna" ]:
101- intent = "qna" # 기본값
89+ try :
90+ result = llm .invoke ([
91+ SystemMessage (content = INTENT_CLASSIFICATION_PROMPT .format (query = state ["query" ]))
92+ ])
93+
94+ intent = str (result .content ).strip ()
95+ if intent not in INTENT_TYPES :
96+ intent = DEFAULT_INTENT # 기본값을 tariff_prediction으로 변경
97+ except Exception as e :
98+ print (f"[DEBUG] LLM 분류 오류: { e } " )
99+ intent = DEFAULT_INTENT # 오류 시에도 tariff_prediction으로 분류
102100
103101 state ["intent" ] = intent # type: ignore
104102 state ["messages" ].append (AIMessage (content = f"의도 분류 완료: { intent } " ))
0 commit comments