Skip to content

Commit 388b2bc

Browse files
committed
feat: hs 코드 재예측 기능 추가와 환율 api 사용 수정
1 parent a404a4f commit 388b2bc

13 files changed

Lines changed: 669 additions & 156 deletions

core/shared/constants/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Shared constants package
2+
3+
from .constants import (
4+
TARIFF_SESSION_KEYWORDS,
5+
NUMBER_SELECTION_PATTERNS,
6+
TARIFF_PREDICTION_KEYWORDS,
7+
CUSTOMS_TRACKING_KEYWORDS,
8+
INTENT_CLASSIFICATION_PROMPT,
9+
INTENT_TYPES,
10+
DEFAULT_INTENT
11+
)
12+
13+
from .error_codes import *
14+
15+
__all__ = [
16+
'TARIFF_SESSION_KEYWORDS',
17+
'NUMBER_SELECTION_PATTERNS',
18+
'TARIFF_PREDICTION_KEYWORDS',
19+
'CUSTOMS_TRACKING_KEYWORDS',
20+
'INTENT_CLASSIFICATION_PROMPT',
21+
'INTENT_TYPES',
22+
'DEFAULT_INTENT'
23+
]

core/shared/constants/constants.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,64 @@
1-
# 진짜 나중에 리팩토링 할 예정
1+
# Shared constants for the entire application
2+
3+
# 관세 예측 세션 관련 키워드
4+
TARIFF_SESSION_KEYWORDS = [
5+
'hs6 코드 후보', 'hs10 코드 후보', '번호를 선택', '관세 계산', '관세 예측',
6+
'상품묘사', '구매 국가', '상품 가격', '시나리오 선택', 'tariff_prediction',
7+
'해외직구로 예상하고 안내를 도와드릴게요', '선택하신 hs', 'hs 10자리 코드 후보'
8+
]
9+
10+
# 숫자 선택 패턴 (HS 코드, 번호 선택 등)
11+
NUMBER_SELECTION_PATTERNS = [
12+
r'^\d+번?$', # 1번, 2번, 3번
13+
r'^\d+$', # 1, 2, 3
14+
r'^\d+\.?\d*$', # 8471.60, 8517.70 등 HS 코드
15+
r'^\d{4,6}$', # 8471, 851770 등 HS 코드
16+
r'^\d{4}\.\d{2}$', # 8471.60 등 HS 코드
17+
]
18+
19+
# 관세 예측 관련 키워드
20+
TARIFF_PREDICTION_KEYWORDS = [
21+
'코드', 'hs', '관세', '세금', '세율', '관세 계산', '관세 예측', '세금 얼마', '관세 얼마',
22+
'관세 계산해줘', '관세 예측해줘', '세금 예측', '예상 관세', '뭘 샀어', '뭐 샀어', '샀어', '구매',
23+
'없다', '코드가 없다', '재예측', '다시', '틀렸다', '맞지 않다', '다른', '새로', '다시 예측', '다른 코드', '적합하지 않다', '코드가 없어',
24+
'저기에', '저기', '그곳에', '그곳', '여기에', '여기', '저기에는', '그곳에는', '여기에는',
25+
'적합하지', '맞지', '틀렸', '잘못', '다른 것', '다른 코드', '새로운', '새로', '다시', '재시도'
26+
]
27+
28+
# 배송 추적 관련 키워드
29+
CUSTOMS_TRACKING_KEYWORDS = [
30+
'운송장', '배송', '통관', '조회', '추적', '배송상태', '위치', '도착', '출고', '통관번호', '운송장번호'
31+
]
32+
33+
# 의도 분류 프롬프트
34+
INTENT_CLASSIFICATION_PROMPT = """
35+
다음 사용자 쿼리를 아래 세 카테고리 중 하나로 분류하세요.
36+
37+
1. customs_tracking: 운송장, 배송, 통관, 조회, 추적, 배송상태, 위치, 도착, 출고, 통관번호, 운송장번호 등
38+
2. tariff_prediction: 관세, 세금, 세율, 관세 계산, 관세 예측, 세금 얼마, 관세 얼마, 관세 계산해줘, 관세 예측해줘, 세금 예측, 예상 관세, 뭘 샀어, 뭐 샀어, 샀어, 구매 등
39+
3. qna: 관세청 정보, 전화번호, 법령, 수입/수출 절차, 일반 안내, 기타 FAQ
40+
41+
# 예시
42+
- "관세 예측해줘" → tariff_prediction
43+
- "관세 계산해줘" → tariff_prediction
44+
- "이 물건의 세금이 얼마나 나올까?" → tariff_prediction
45+
- "노트북 샀어" → tariff_prediction
46+
- "미국에서 뭐 샀어" → tariff_prediction
47+
- "운송장 번호 123456 어디쯤이야?" → customs_tracking
48+
- "배송이 어디까지 왔어?" → customs_tracking
49+
- "통관 진행 상황 알려줘" → customs_tracking
50+
- "관세청 전화번호 알려줘" → qna
51+
- "수입 절차가 궁금해" → qna
52+
- "관세청 홈페이지 알려줘" → qna
53+
- "관세법 제12조가 뭐야?" → qna
54+
55+
사용자 쿼리: {query}
56+
57+
반드시 다음 중 하나만 응답하세요: customs_tracking, tariff_prediction, qna
58+
"""
59+
60+
# 의도 분류 결과
61+
INTENT_TYPES = ["customs_tracking", "tariff_prediction", "qna"]
62+
63+
# 기본 의도 (오류 시 사용)
64+
DEFAULT_INTENT = "tariff_prediction"

core/shared/router/intent_router.py

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
from langchain_core.messages import SystemMessage, AIMessage
2+
import re
23

34
from core.shared.states.states import CustomsAgentState
45
from 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

616
def 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

Comments
 (0)