fix: JSON 파싱 견고화 + 분류기 프롬프트 강화

- _parse_classification: 어떤 형태든 첫{~마지막} 추출, 백틱 잔재 제거
- 분류기: 판단 예시 추가 (일정→tools, 인사→direct 등), 백틱/코드블록 금지 명시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-04-06 13:43:01 +09:00
parent 6e24da56a4
commit e786307a07
2 changed files with 27 additions and 17 deletions

View File

@@ -35,13 +35,22 @@ JSON 형식:
- direct/route/clarify: {"action": "...", "response": "...", "prompt": "..."}
- tools: {"action": "tools", "tool": "calendar|email|document", "operation": "...", "params": {...}}
규칙:
- JSON 외 텍스트는 절대 출력하지 마라
중요 규칙:
- 반드시 순수 JSON만 출력. 백틱, 코드블록, 설명 텍스트 금지
- 날짜는 YYYY-MM-DD, 시간은 HH:MM
- pending_draft가 있다고 [대화 이력]에 표시되어 있을 때만 create_confirmed 사용
- 오늘 날짜 정보가 [현재 시간]에 있으니 참고하라
- [현재 시간]의 날짜를 참고하여 "오늘", "내일", "이번주" 등을 YYYY-MM-DD로 변환하라
<EFBFBD><EFBFBD><EFBFBD>의 이름은 '이드'. 상냥하고 친근하게 대화한다.
판단 예시:
- "오늘 일정" → tools: calendar.today()
- "이번주 일정" → tools: calendar.search(이번주 월~일)
- "내일 3시 회의" → tools: calendar.create_draft(...)
- "최근 메일" → tools: email.search("", 7)
- "문서 찾아줘" → tools: document.search(...)
- "안녕" → direct
- "양자역학 설명해줘" → route
너의 이름은 '이드'. 상냥하고 친근하게 대화한다.
대화 이력이 있으면 맥락을 고려하라.\
"""

View File

@@ -70,20 +70,21 @@ async def _stream_with_cancel(adapter, message: str, job: Job, collected: list[s
def _parse_classification(raw: str) -> dict:
"""EXAONE JSON 응답 파싱. 실패 시 direct fallback."""
raw = raw.strip()
# JSON 블록 추출 (```json ... ``` 감싸는 경우 대응)
if "```" in raw:
start = raw.find("{")
end = raw.rfind("}") + 1
if start >= 0 and end > start:
raw = raw[start:end]
try:
result = json.loads(raw)
if "action" in result:
return result
except json.JSONDecodeError:
pass
# 어떤 형태든 첫 번째 { ~ 마지막 } 추출
start = raw.find("{")
end = raw.rfind("}")
if start >= 0 and end > start:
json_str = raw[start:end + 1]
try:
result = json.loads(json_str)
if "action" in result:
return result
except json.JSONDecodeError:
pass
# JSON 파싱 실패 → direct로 취급 (raw 텍스트가 직접 응답)
return {"action": "direct", "response": raw, "prompt": ""}
# 마크다운/코드블록 잔재 제거
cleaned = raw.replace("```json", "").replace("```", "").replace("`json", "").replace("`", "").strip()
return {"action": "direct", "response": cleaned, "prompt": ""}
async def _send_callback(job: Job, text: str) -> None: