Skip to content

Commit 015b3cb

Browse files
authored
Merge pull request #25 from hanjuhn/main
chore: 관세 재예측 문구 추가
2 parents 526b066 + 5b66c88 commit 015b3cb

10 files changed

Lines changed: 432 additions & 588 deletions

File tree

app/dto/request.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
class Request(BaseModel):
44
message: str
5+
session_id: str = None

app/routes.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from flask import Blueprint, request, jsonify
1+
from flask import Blueprint, request, jsonify, make_response
22
from app.dto.request import Request
33
from flasgger import swag_from
44
from .service import run_model
5+
import uuid
56

67
api_blueprint = Blueprint("api", __name__)
78

@@ -19,6 +20,11 @@
1920
'question': {
2021
'type': 'string',
2122
'example': '이 물건의 세금이 얼마나 나올까?'
23+
},
24+
'session_id': {
25+
'type': 'string',
26+
'example': 'uuid-1234',
27+
'required': False
2228
}
2329
},
2430
'required': ['question']
@@ -42,5 +48,8 @@
4248
})
4349
def predict():
4450
request_data = Request(**request.get_json())
45-
answer = run_model(question=request_data.message)
46-
return jsonify(answer.model_dump())
51+
session_id = request_data.session_id or request.cookies.get("session_id")
52+
answer = run_model(question=request_data.message, session_id=session_id)
53+
answer_dict = answer.model_dump()
54+
response = make_response(jsonify(answer_dict))
55+
return response

app/service.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
from app.dto.response import Response
22
from core.graphs.runner import run_customs_agent
3+
from langchain_core.messages import HumanMessage, AIMessage
4+
5+
# 세션 맵: {session_id: messages}
6+
session_map = {}
7+
8+
def run_model(question: str, session_id: str = None) -> "Response":
9+
# session_id가 없으면 대화내역 없이 동작
10+
if not session_id:
11+
messages = [HumanMessage(content=question)]
12+
else:
13+
# session_map에 없으면 빈 리스트 할당
14+
if session_id not in session_map:
15+
session_map[session_id] = []
16+
messages = session_map[session_id]
17+
messages.append(HumanMessage(content=question))
18+
19+
# agent 실행 (messages를 넘김)
20+
state = run_customs_agent(question, session_id=session_id, messages=messages)
21+
22+
# AI 응답 메시지 추가 (state["final_response"] 기준)
23+
ai_reply = state.get("final_response")
24+
if session_id and ai_reply:
25+
messages.append(AIMessage(content=ai_reply))
26+
session_map[session_id] = messages
327

4-
def run_model(question: str) -> "Response":
5-
"""
6-
중앙 관리 모델을 통해 각 요청을 적절한 모델로 라우팅
7-
아무 모델과도 관계없는 경우 중앙 모델에서 적절한 응답을 생성해야 합니다.
8-
ex : "안녕, 너는 뭘 할 수 있어?"
9-
예시 코드는 아래와 같습니다.
10-
"""
11-
state = run_customs_agent(question)
1228
return Response(
13-
reply=state.get("final_response"),
29+
reply=ai_reply,
1430
progress_details=state.get("progress_details"),
1531
error_reason=state.get("error_reason"),
1632
success=True

core/graphs/runner.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
from core.shared.states.states import CustomsAgentState
55

66

7-
def run_customs_agent(query: str) -> CustomsAgentState:
7+
def run_customs_agent(query: str, session_id: str = None, messages=None) -> CustomsAgentState:
88
"""관세청 에이전트를 실행합니다."""
99

1010
# 그래프 생성
1111
app = create_customs_graph()
1212

13+
# messages가 없으면 query만 포함
14+
if messages is None:
15+
messages = [HumanMessage(content=query)]
16+
1317
# 초기 상태 설정
1418
initial_state = CustomsAgentState(
15-
messages=[HumanMessage(content=query)],
19+
messages=messages,
1620
query=query,
1721
intent=None,
1822
final_response="",

core/shared/constants/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
# 질문 형태 감지 패턴
3636
QUESTION_PATTERNS = [
3737
r'\?$', # 물음표로 끝나는 경우
38+
r'뭐야', r'뭔가요', r'무엇이야', r'무엇인가요',
3839
r'^어떻게', r'^무엇', r'^언제', r'^어디서', r'^왜', r'^누가',
3940
r'^무슨', r'^어떤', r'^얼마나', r'^어디', r'^언제', r'^왜',
4041
r'알려줘', r'알려주세요', r'궁금해', r'궁금합니다'

core/shared/router/intent_router.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from langchain_core.messages import SystemMessage, AIMessage
22
import re
33
from typing import List, Optional
4+
import uuid
45

56
from core.shared.states.states import CustomsAgentState
67
from core.shared.utils.llm import get_llm
@@ -89,57 +90,61 @@ def _classify_with_llm(query: str) -> str:
8990

9091

9192
def _add_classification_message(state: CustomsAgentState, intent: str, reason: str) -> None:
92-
"""의도 분류 완료 메시지를 추가합니다."""
93-
state["messages"].append(
94-
AIMessage(content=f"의도 분류 완료: {intent} ({reason})")
95-
)
93+
# 의도 분류 메시지를 messages에 남기지 않음
94+
pass
9695

9796

9897
def intent_router(state: CustomsAgentState) -> CustomsAgentState:
99-
"""사용자 쿼리의 의도를 분류합니다."""
100-
98+
prev_intent = state.get("intent")
10199
current_query = state["query"].strip()
102100
if not current_query:
103101
state["intent"] = DEFAULT_INTENT
104102
_add_classification_message(state, DEFAULT_INTENT, "빈 쿼리")
105103
return state
106-
107104
# 세션 연속성 확인
108105
is_in_tariff_session = _is_in_tariff_session(state)
109-
110106
# 관세 예측 세션 중이면 무조건 tariff_prediction으로 분류
111107
if is_in_tariff_session:
112108
state["intent"] = "tariff_prediction"
113109
_add_classification_message(state, "tariff_prediction", "관세 예측 세션 연속성 유지")
114110
return state
115-
116111
# 패턴 기반 분류
117112
is_number_selection = _is_number_selection(current_query)
118113
is_question = _is_question(current_query)
119-
120114
# 질문 형태이면서 관세 예측 세션이 아닌 경우 QnA로 분류
121115
if is_question:
122116
state["intent"] = "qna"
123-
_add_classification_message(state, "qna", "질문 형태 감지")
117+
_add_classification_message(state, "qna", "질문 형태 감지(우선)")
118+
if prev_intent == "tariff_prediction":
119+
try:
120+
from core.tariff_prediction.agent.tariff_prediction_agent import workflow_manager
121+
workflow_manager.cleanup_session()
122+
except Exception:
123+
pass
124124
return state
125-
126125
# 키워드 기반 분류
127126
keyword_intent = _classify_by_keywords(current_query)
128127
if keyword_intent:
129128
state["intent"] = keyword_intent
130129
_add_classification_message(state, keyword_intent, "키워드 기반 분류")
130+
if prev_intent == "tariff_prediction" and keyword_intent != "tariff_prediction":
131+
try:
132+
from core.tariff_prediction.agent.tariff_prediction_agent import workflow_manager
133+
workflow_manager.cleanup_session()
134+
except Exception:
135+
pass
131136
return state
132-
133-
# 숫자 선택이지만 관세 예측 세션이 아닌 경우에도 tariff_prediction으로 분류
134-
# (HS 코드 직접 입력 등의 경우)
135137
if is_number_selection:
136138
state["intent"] = "tariff_prediction"
137139
_add_classification_message(state, "tariff_prediction", "숫자 선택 감지")
138140
return state
139-
140-
# LLM 기반 의도 분류를 수행
141141
intent = _classify_with_llm(current_query)
142142
state["intent"] = intent
143143
_add_classification_message(state, intent, "LLM 분류")
144-
144+
if prev_intent == "tariff_prediction" and intent != "tariff_prediction":
145+
try:
146+
from core.tariff_prediction.agent.tariff_prediction_agent import workflow_manager
147+
workflow_manager.cleanup_session()
148+
except Exception:
149+
pass
145150
return state

0 commit comments

Comments
 (0)