feat(nanoclaude): ask-first routing + 서고 안내 통일 + document 로그

- document 진입 시 기본 ask (근거 중심 답변)
- 명시적 목록 요청만 search_full (목록/리스트/제목만 등)
- 안내 문구 "서고를 확인하는 중입니다..." 통일
- document 호출 전후 라우팅/지연 로그 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-04-16 08:59:22 +09:00
parent 26e011d4a8
commit e7a86c81da
+14 -17
View File
@@ -202,22 +202,10 @@ def _pre_route(message: str) -> dict | None:
query = query.replace(rm, "") query = query.replace(rm, "")
query = query.strip() query = query.strip()
if query: if query:
# 질문형 강신호 # 명시적 목록 요청만 search_full, 나머지는 ask (근거 중심 답변 기본값)
ask_signals = ["알려줘", "설명해", "차이", "비교", "절차", "요건", "무엇", "", "어떻게", "뭐야", "뭔가", "뭐지", "내용"] list_signals = ["목록", "리스트", "검색 결과", "몇 개", "list", "제목만", "문서만"]
# 탐색형 강신호 list_request = any(s in msg for s in list_signals)
search_signals = ["찾아", "검색", "목록", "최근", "업로드", "리스트"] operation = "search_full" if list_request else "ask"
ask_score = sum(1 for s in ask_signals if s in msg)
search_score = sum(1 for s in search_signals if s in msg)
# 도메인 키워드만으로 진입한 경우 질문형으로 간주 (+1 보너스)
if domain_hit and not doc_entry:
ask_score += 1
# 초기 운영 가드: ask는 강신호 2개 이상일 때만
if ask_score >= 2 and ask_score > search_score:
operation = "ask"
else:
operation = "search_full"
return {"action": "tools", "tool": "document", "operation": operation, "params": {"query": query}} return {"action": "tools", "tool": "document", "operation": operation, "params": {"query": query}}
# 인프라 도구 키워드 # 인프라 도구 키워드
@@ -377,15 +365,24 @@ async def run(job: Job) -> None:
else: else:
# 문서 도구 호출 시 안내 문구 # 문서 도구 호출 시 안내 문구
if tool_name == "document" and job.callback == "synology": if tool_name == "document" and job.callback == "synology":
notice = "서고를 확인하는 중입니다..." if operation == "ask" else "문서를 검색하는 중입니다..." notice = "서고를 확인하는 중입니다..."
await send_to_synology(notice, raw=True) await send_to_synology(notice, raw=True)
# 일반 도구 실행 (document.ask는 긴 timeout) # 일반 도구 실행 (document.ask는 긴 timeout)
timeout = DOCUMENT_ASK_TIMEOUT if (tool_name == "document" and operation == "ask") else TOOL_TIMEOUT timeout = DOCUMENT_ASK_TIMEOUT if (tool_name == "document" and operation == "ask") else TOOL_TIMEOUT
doc_start = time()
if tool_name == "document":
logger.info("Job %s document.%s domain_hit=%s list_request=%s query=%s",
job.id, operation,
any(k in job.message.lower() for k in ["산업안전", "위험성평가", "asme", "법령"]),
any(s in job.message.lower() for s in ["목록", "리스트", "제목만"]),
params.get("query", "")[:50])
try: try:
result = await asyncio.wait_for(execute_tool(tool_name, operation, params), timeout=timeout) result = await asyncio.wait_for(execute_tool(tool_name, operation, params), timeout=timeout)
except asyncio.TimeoutError: except asyncio.TimeoutError:
result = {"ok": False, "tool": tool_name, "operation": operation, "data": [], "summary": "", "error": "⚠️ 서비스 응답 시간이 초과되었습니다."} result = {"ok": False, "tool": tool_name, "operation": operation, "data": [], "summary": "", "error": "⚠️ 서비스 응답 시간이 초과되었습니다."}
if tool_name == "document":
logger.info("Job %s document.%s ok=%s elapsed=%.1fs", job.id, operation, result.get("ok"), time() - doc_start)
if not result["ok"]: if not result["ok"]:
response = result.get("error", "⚠️ 서비스를 사용할 수 없습니다.") response = result.get("error", "⚠️ 서비스를 사용할 수 없습니다.")