feat(infra): Phase 1.5 진단 도구 3개 + trace 정리
scheduler_status, queue_status, run_verify 추가. MCP 10개 도구 + NanoClaude wrapper + pre-route 키워드. worker.py trace print 제거. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -190,7 +190,7 @@ def _pre_route(message: str) -> dict | None:
|
||||
return {"action": "tools", "tool": "document", "operation": "search", "params": {"query": query}}
|
||||
|
||||
# 인프라 도구 키워드
|
||||
infra_keywords = ["docker", "컨테이너", "디스크", "용량", "헬스체크", "tailscale", "ollama 모델", "mlx 모델"]
|
||||
infra_keywords = ["docker", "컨테이너", "디스크", "용량", "헬스체크", "tailscale", "ollama 모델", "mlx 모델", "스케줄러", "scheduler", "큐 상태", "queue", "처리 큐", "verify", "검증"]
|
||||
if any(k in msg for k in infra_keywords):
|
||||
# docker/컨테이너 상태
|
||||
if any(k in msg for k in ["docker", "컨테이너"]):
|
||||
@@ -212,6 +212,15 @@ def _pre_route(message: str) -> dict | None:
|
||||
if any(k in msg for k in ["ollama 모델", "mlx 모델"]):
|
||||
host = "mlx" if "mlx" in msg else "gpu"
|
||||
return {"action": "tools", "tool": "infra", "operation": "models", "params": {"host": host}}
|
||||
# 스케줄러
|
||||
if any(k in msg for k in ["스케줄러", "scheduler"]):
|
||||
return {"action": "tools", "tool": "infra", "operation": "scheduler", "params": {}}
|
||||
# 큐
|
||||
if any(k in msg for k in ["큐 상태", "queue", "처리 큐"]):
|
||||
return {"action": "tools", "tool": "infra", "operation": "queue", "params": {}}
|
||||
# 검증
|
||||
if any(k in msg for k in ["verify", "검증"]):
|
||||
return {"action": "tools", "tool": "infra", "operation": "verify", "params": {"check_name": "gpu-snapshot"}}
|
||||
|
||||
# 시스템 상태 질문 — 마커만 반환 (worker에서 비동기 조회)
|
||||
if any(k in msg for k in ["추론 모델", "gemma", "젬마", "서버 상태", "시스템 상태"]) or \
|
||||
@@ -254,11 +263,9 @@ async def run(job: Job) -> None:
|
||||
# --- 사전 라우팅 (키워드 기반, EXAONE 스킵) ---
|
||||
pre = _pre_route(job.message)
|
||||
classify_latency = 0
|
||||
print(f"[TRACE] Job {job.id} pre_route result: {pre}", flush=True)
|
||||
|
||||
if pre:
|
||||
classification = pre
|
||||
print(f"[TRACE] Job {job.id} PRE-ROUTED: {pre.get('tool','')}.{pre.get('operation','')}", flush=True)
|
||||
logger.info("Job %s pre-routed: %s.%s", job.id, pre.get("tool", ""), pre.get("operation", pre.get("action", "")))
|
||||
else:
|
||||
# --- EXAONE 분류기 호출 ---
|
||||
@@ -291,7 +298,6 @@ async def run(job: Job) -> None:
|
||||
response_text = classification.get("response", "")
|
||||
route_prompt = classification.get("prompt", "")
|
||||
|
||||
print(f"[TRACE] Job {job.id} final action='{action}' classification={classification}", flush=True)
|
||||
logger.info("Job %s classified as '%s'", job.id, action)
|
||||
|
||||
# 대화 기록: 사용자 메시지
|
||||
|
||||
@@ -14,6 +14,8 @@ from infra.core.health import service_health, VALID_SERVICES
|
||||
from infra.core.system import disk_usage
|
||||
from infra.core.network import tailscale_status
|
||||
from infra.core.models import ollama_models, mlx_models
|
||||
from infra.core.docserver import scheduler_status as _scheduler_status, queue_status as _queue_status
|
||||
from infra.core.verify import run_verify as _run_verify, VERIFY_COMMANDS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -111,3 +113,18 @@ async def models(host: str = "gpu") -> dict:
|
||||
summary = f"{result.source} on {result.host}: {len(result.models)}개 모델"
|
||||
return {"ok": True, "tool": "infra", "operation": "models",
|
||||
"data": data, "summary": summary, "error": ""}
|
||||
|
||||
|
||||
async def scheduler() -> dict:
|
||||
"""Document Server scheduler status."""
|
||||
return await _scheduler_status()
|
||||
|
||||
|
||||
async def queue() -> dict:
|
||||
"""Document Server queue status."""
|
||||
return await _queue_status()
|
||||
|
||||
|
||||
async def verify(check_name: str = "gpu-snapshot") -> dict:
|
||||
"""Run predefined verify command."""
|
||||
return await _run_verify(check_name)
|
||||
|
||||
@@ -21,7 +21,7 @@ ALLOWED_OPS = {
|
||||
"calendar": {"today", "search", "create_draft", "create_confirmed"},
|
||||
"email": {"search", "read"},
|
||||
"document": {"search", "read"},
|
||||
"infra": {"status", "health", "disk", "network", "models"},
|
||||
"infra": {"status", "health", "disk", "network", "models", "scheduler", "queue", "verify"},
|
||||
}
|
||||
|
||||
# payload hard limit
|
||||
@@ -113,6 +113,12 @@ async def _exec_infra(operation: str, params: dict) -> dict:
|
||||
return await infra_tool.network()
|
||||
elif operation == "models":
|
||||
return await infra_tool.models(params.get("host", "gpu"))
|
||||
elif operation == "scheduler":
|
||||
return await infra_tool.scheduler()
|
||||
elif operation == "queue":
|
||||
return await infra_tool.queue()
|
||||
elif operation == "verify":
|
||||
return await infra_tool.verify(params.get("check_name", "gpu-snapshot"))
|
||||
return _error("infra", operation, "미구현")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user