From c1fae04344dc5632378aab1a95b9483654e1f081 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Sat, 7 Mar 2026 11:06:07 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20PAAI=20=ED=8A=B8=EB=9F=AC=EB=B8=94?= =?UTF-8?q?=EC=8A=88=ED=8C=85=20=EA=B8=B0=EB=A1=9D=20(2026-03-07)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/PAAI_TROUBLESHOOTING_2026-03-07.md | 353 ++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 docs/PAAI_TROUBLESHOOTING_2026-03-07.md diff --git a/docs/PAAI_TROUBLESHOOTING_2026-03-07.md b/docs/PAAI_TROUBLESHOOTING_2026-03-07.md new file mode 100644 index 0000000..28b66ad --- /dev/null +++ b/docs/PAAI_TROUBLESHOOTING_2026-03-07.md @@ -0,0 +1,353 @@ +# PAAI 시스템 트러블슈팅 기록 + +**날짜:** 2026-03-07 +**작성자:** 용림 (AI 디지털 직원) +**상태:** ✅ 해결 완료 + +--- + +## 📋 목차 + +1. [시스템 아키텍처](#시스템-아키텍처) +2. [모델 전략 (Opus vs Sonnet)](#모델-전략-opus-vs-sonnet) +3. [발생한 문제들](#발생한-문제들) +4. [해결 과정](#해결-과정) +5. [수정된 코드](#수정된-코드) +6. [서브에이전트 활용](#서브에이전트-활용) +7. [교훈 및 권장사항](#교훈-및-권장사항) + +--- + +## 시스템 아키텍처 + +### 전체 흐름 + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ PIT3000 POS │────▶│ prescription │────▶│ Flask │ +│ (MSSQL) │ │ _trigger.py │ │ (pmr_api) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ WebSocket │ HTTP + ▼ (ws://8765) ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ PMR 화면 │ │ KIMS API │ + │ (실시간) │ │ (약물 상호작용) │ + └─────────────────┘ └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Clawdbot │ + │ Gateway │ + │ (ws://18789) │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Claude API │ + │ (Sonnet 4) │ + └─────────────────┘ +``` + +### PM2 서비스 구성 + +| 서비스 | PM2 이름 | 포트 | 역할 | +|--------|----------|------|------| +| Flask 웹서버 | `flask-pharmacy` | 7001 | API 엔드포인트, PMR 화면 | +| 처방 감지 | `websocket-rx` | 8765 | DB 폴링 → 실시간 알림 | +| Clawdbot | `clawdbot-gateway` | 18789 | AI 게이트웨이 | + +--- + +## 모델 전략 (Opus vs Sonnet) + +### Gateway 기본 설정 + +```json +// ~/.clawdbot/clawdbot.json +{ + "agents": { + "defaults": { + "model": { + "primary": "anthropic/claude-opus-4-5" // 기본 모델 + }, + "models": { + "anthropic/claude-opus-4-5": { "alias": "opus" }, + "github-copilot/gpt-5": {}, + "openai-codex/gpt-5.2-codex": {} + } + } + } +} +``` + +### PAAI 전용 모델 (비용 절감) + +PAAI 분석은 **빠른 응답**과 **비용 절감**이 중요하므로 **Sonnet**을 사용. + +```python +# pmr_api.py - Line 1417 +ai_text = ask_clawdbot( + message=prompt, + session_id='paai-analysis', + system_prompt=PAAI_SYSTEM_PROMPT, + timeout=60, + model='anthropic/claude-sonnet-4-5' # Sonnet 지정! +) +``` + +### sessions.patch 메커니즘 + +Gateway에서 모델이 allowlist에 없어도, `sessions.patch`로 세션별 모델 오버라이드 가능: + +```python +# clawdbot_client.py - _ask_gateway() + +# 4. 모델 오버라이드 (sessions.patch) +if model: + patch_frame = { + 'type': 'req', + 'method': 'sessions.patch', + 'params': { + 'key': session_id, + 'model': model, # 'anthropic/claude-sonnet-4-5' + } + } + await ws.send(json.dumps(patch_frame)) + # patch 실패해도 agent 요청은 계속 진행됨 +``` + +### 모델 비용 비교 + +| 모델 | 입력 (1M) | 출력 (1M) | 용도 | +|------|-----------|-----------|------| +| Claude Opus 4.5 | $15 | $75 | 메인 세션, 복잡한 작업 | +| Claude Sonnet 4.5 | $3 | $15 | PAAI 분석, 빠른 응답 필요 | + +**절감 효과:** PAAI를 Sonnet으로 돌리면 비용 **80% 절감**! + +--- + +## 발생한 문제들 + +### 문제 1: 처방 분석이 안 됨 (임명옥 환자) + +**증상:** +- 처방 감지는 되나 분석 결과가 안 나옴 +- DB에 `generating` 상태로 멈춤 + +**원인:** +1. PM2 `watch` 모드로 인한 과도한 재시작 (30회 이상) +2. 재시작 과정에서 분석 요청이 중단됨 + +### 문제 2: Flask 연결 끊김 + +**증상:** +``` +ConnectionResetError: [WinError 10054] +현재 연결은 원격 호스트에 의해 강제로 끊겼습니다 +``` + +**원인:** +- watch 모드가 파일 변경 감지 → Flask 재시작 +- 진행 중인 HTTP 요청이 끊김 + +### 문제 3: 모델 허용 오류 (경고) + +**증상:** +``` +WARNING: [Clawdbot] sessions.patch 실패: model not allowed: anthropic/claude-sonnet-4-5 +``` + +**분석:** +- Gateway allowlist에 `claude-sonnet-4-5` 없음 +- 하지만 **sessions.patch 실패해도 agent 요청은 진행됨** +- 세션의 기존 모델 또는 기본 모델로 폴백 +- 실제 분석에는 영향 없음 (비용만 더 나갈 수 있음) + +--- + +## 해결 과정 + +### Step 1: 상황 파악 + +```bash +# PM2 상태 확인 +pm2 list +# → flask-pharmacy: ↺ 17, websocket-rx: ↺ 30 (과도한 재시작) + +# 최근 성공한 분석 확인 +sqlite3 db/paai_logs.db "SELECT * FROM paai_logs WHERE status='success' ORDER BY id DESC LIMIT 5" +# → 00:24:32까지 성공, 이후 실패 +``` + +### Step 2: 원인 분석 + +```bash +# Flask 로그 확인 +pm2 logs flask-pharmacy --lines 50 + +# watch 모드가 문제임을 확인 +# uptime이 7초, 계속 재시작 중 +``` + +### Step 3: watch 모드 비활성화 + +```bash +# 기존 서비스 삭제 +pm2 stop flask-pharmacy websocket-rx +pm2 delete flask-pharmacy websocket-rx + +# watch 없이 재등록 +pm2 start app.py --name "flask-pharmacy" --interpreter python \ + --cwd "c:\Users\청춘약국\source\pharmacy-pos-qr-system\backend" + +pm2 start prescription_trigger.py --name "websocket-rx" --interpreter python \ + --cwd "c:\Users\청춘약국\source\prescription-trigger" + +# 저장 +pm2 save +``` + +### Step 4: 밀린 처방 수동 분석 + +```bash +# 임명옥 처방 수동 분석 요청 +curl -X POST http://localhost:7001/pmr/api/paai/analyze \ + -H "Content-Type: application/json" \ + -d '{"pre_serial": "20260307000059"}' + +# → 성공! +``` + +--- + +## 수정된 코드 + +### ThreadPoolExecutor 적용 (동시성 제한) + +**파일:** `prescription-trigger/prescription_trigger.py` + +**Before (문제):** +```python +# 무제한 스레드 생성 → 세션 과부하 +def _request_analysis(self, pre_serial, patient_name): + thread = threading.Thread(target=self._analyze_worker, args=(...)) + thread.start() + self._worker_threads.append(thread) +``` + +**After (해결):** +```python +from concurrent.futures import ThreadPoolExecutor + +class PrescriptionTrigger: + def __init__(self): + # 최대 3개 동시 처리 + self._executor = ThreadPoolExecutor(max_workers=3) + + def _request_analysis(self, pre_serial, patient_name): + self._executor.submit(self._analyze_worker, pre_serial, patient_name) + + def stop(self): + self._executor.shutdown(wait=True) # graceful shutdown +``` + +**커밋:** `feat: ThreadPoolExecutor로 동시 처리 제한 (max_workers=3)` + +### OTC 라벨 import 수정 + +**파일:** `backend/app.py` + +**문제:** PM2 환경에서 상대 import 실패 +``` +ModuleNotFoundError: No module named 'utils' +``` + +**해결:** +```python +# app.py 상단에서 미리 import +from utils.otc_label_printer import generate_label_commands +``` + +--- + +## 서브에이전트 활용 + +오늘 트러블슈팅에 **3개의 서브에이전트**를 활용: + +### 1. paai-investigation +- **목적:** PAAI 아키텍처 분석 +- **결과:** Clawdbot Gateway WebSocket 사용 확인 + +### 2. paai-queue-analysis +- **목적:** 큐 처리 로직 분석 +- **결과:** 날짜 필터로 어제 것은 무시, 오늘 것은 일괄 처리 + +### 3. paai-concurrency-design +- **목적:** 동시성 제어 방안 설계 +- **결과:** ThreadPoolExecutor 방식 제안 + +```python +# 서브에이전트 호출 예시 +sessions_spawn( + task="처방 분석 시스템의 동시성 제어 방안을 설계해주세요", + label="paai-concurrency-design" +) +``` + +--- + +## 교훈 및 권장사항 + +### ✅ PM2 watch 모드 사용 시 주의 + +```bash +# 개발 중에만 watch 사용 +pm2 start app.py --watch # 개발용 + +# 운영 환경에서는 watch 끄기 +pm2 start app.py # 운영용 + +# 코드 수정 후 수동 반영 +pm2 restart flask-pharmacy +``` + +### ✅ 모델 비용 최적화 + +| 용도 | 권장 모델 | 이유 | +|------|-----------|------| +| 메인 대화 | Opus | 복잡한 작업, 높은 품질 | +| PAAI 분석 | Sonnet | 빠른 응답, 정형화된 출력 | +| 업셀링 추천 | Sonnet | 간단한 추천 | + +### ✅ 동시성 제어 + +```python +# ThreadPoolExecutor 사용 +executor = ThreadPoolExecutor(max_workers=3) + +# 이점: +# 1. 리소스 제한 (CPU, 메모리) +# 2. Gateway 세션 과부하 방지 +# 3. 순차적 처리보다 빠름 +``` + +### ✅ 트러블슈팅 체크리스트 + +1. `pm2 list` - 재시작 횟수 확인 (↺) +2. `pm2 logs ` - 에러 로그 확인 +3. `paai_logs.db` - 분석 상태 확인 +4. `trigger_state.db` - 작업 큐 상태 확인 + +--- + +## 결론 + +| 항목 | Before | After | +|------|--------|-------| +| 안정성 | ❌ 30회 재시작 | ✅ 안정적 | +| 동시성 | 무제한 스레드 | 3개 제한 | +| 비용 | Opus (고비용) | Sonnet (저비용) | +| Watch 모드 | 활성화 (불안정) | 비활성화 (안정) | + +**시스템 정상화 완료!** 🎉