Files
syn-chat-bot/QUICK_REFERENCE.md
Hyungi Ahn 1543abded6 Phase 7a: GPU 모델 id-9b:latest 전환 + 워크플로우 배포 자동화
- qwen3.5:9b-q8_0 → id-9b:latest 전체 교체 (워크플로우, Python 스크립트)
- deploy_workflows.sh 생성 (n8n REST API 자동 배포)
- .env.example: CalDAV/IMAP/Karakeep 기본값 수정
- 문서 업데이트: tk_qc_issues 컬렉션, 맥미니 Ollama 기동 안내

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:13:24 +09:00

12 KiB

Quick Reference

작업 시작 전 체크리스트.

현재 상태 확인

# 챗봇 컨테이너 상태
docker ps -a --filter "name=bot-" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# Qdrant 상태 + 3컬렉션 확인
docker ps --filter "name=qdrant" --format "table {{.Names}}\t{{.Status}}"
curl -s http://localhost:6333/collections | python3 -c "import sys,json; [print(f'  {c[\"name\"]}') for c in json.loads(sys.stdin.read())['result']['collections']]"

# 맥미니 Ollama 모델 확인 (brew services로 자동기동, 임베딩/리랭킹 전용)
# 중지 상태일 때: brew services start ollama
ollama list

# GPU 서버 Ollama 상태
curl -s http://192.168.1.186:11434/api/tags | python3 -m json.tool

# GPU 서버 id-9b 헬스체크
curl -s http://192.168.1.186:11434/api/generate -d '{"model":"id-9b:latest","prompt":"hi","stream":false}' | python3 -m json.tool

접속 정보

서비스 URL
n8n 편집기 http://localhost:5678
Qdrant 대시보드 http://localhost:6333/dashboard
bot-postgres localhost:15478
Ollama API (맥미니) http://localhost:11434
Ollama API (GPU) http://192.168.1.186:11434
Synology Chat NAS (192.168.1.227)
chat_bridge http://localhost:8091
HEIC converter http://localhost:8090
caldav_bridge http://localhost:8092
devonthink_bridge http://localhost:8093

Docker 명령어

# 프로젝트 경로
cd ~/Documents/code/syn-chat-bot

# 시작/종료
docker compose up -d
docker compose down

# 로그 확인
docker compose logs -f bot-n8n
docker compose logs -f bot-postgres

# n8n만 재시작
docker compose restart bot-n8n

# DB 접속
docker exec -it bot-postgres psql -U bot -d chatbot

# DB 테이블 확인
docker exec bot-postgres psql -U bot -d chatbot -c '\dt'

# v2 마이그레이션 실행 (기존 DB가 있을 때)
docker exec -i bot-postgres psql -U bot -d chatbot < init/migrate-v2.sql

# Qdrant tk_company 컬렉션 + 인덱스 설정
bash init/setup-qdrant.sh

# v3 마이그레이션 실행 (Phase 5-6 테이블 추가)
docker exec -i bot-postgres psql -U bot -d chatbot < init/migrate-v3.sql

헬스체크 (전체)

# 한 번에 전체 확인
echo "=== Docker ===" && \
docker ps -a --filter "name=bot-" --filter "name=qdrant" --format "table {{.Names}}\t{{.Status}}" && \
echo "=== 맥미니 Ollama ===" && \
curl -s http://localhost:11434/api/tags | python3 -c "import sys,json; [print(f'  {m[\"name\"]}') for m in json.loads(sys.stdin.read())['models']]" && \
echo "=== GPU 서버 Ollama ===" && \
curl -s http://192.168.1.186:11434/api/tags | python3 -c "import sys,json; [print(f'  {m[\"name\"]}') for m in json.loads(sys.stdin.read())['models']]" && \
echo "=== Qdrant 컬렉션 ===" && \
curl -s http://localhost:6333/collections | python3 -c "import sys,json; [print(f'  {c[\"name\"]}') for c in json.loads(sys.stdin.read())['result']['collections']]" && \
echo "=== tk_company ===" && \
curl -s http://localhost:6333/collections/tk_company | python3 -c "import sys,json; r=json.loads(sys.stdin.read())['result']; print(f'  벡터수: {r[\"points_count\"]}, 상태: {r[\"status\"]}')" 2>/dev/null || echo "  (미생성)" && \
echo "=== 네이티브 서비스 ===" && \
curl -s http://localhost:8090/health && echo && \
curl -s http://localhost:8091/health && echo && \
curl -s http://localhost:8092/health && echo && \
curl -s http://localhost:8093/health && echo && \
./manage_services.sh status && \
echo "=== n8n ===" && \
curl -s -o /dev/null -w '  HTTP %{http_code}' http://localhost:5678 && echo && \
echo "=== API 사용량 ===" && \
docker exec bot-postgres psql -U bot -d chatbot -t -c "SELECT tier, call_count, estimated_cost FROM api_usage_monthly WHERE year=EXTRACT(YEAR FROM NOW()) AND month=EXTRACT(MONTH FROM NOW())" 2>/dev/null || echo "  (테이블 없음)"

디렉토리 구조

syn-chat-bot/
├── docker-compose.yml    ← 컨테이너 정의
├── .env                  ← API 키, DB 비밀번호, 토큰, 예산 (git 제외)
├── .env.example          ← 환경변수 템플릿
├── CLAUDE.md             ← 프로젝트 문서
├── QUICK_REFERENCE.md    ← 이 파일
├── heic_converter.py     ← HEIC→JPEG 변환 API (macOS sips, port 8090)
├── chat_bridge.py        ← DSM Chat API 브릿지 (사진 폴링/다운로드, port 8091)
├── caldav_bridge.py      ← CalDAV REST 래퍼 (Synology Calendar, port 8092)
├── devonthink_bridge.py  ← DEVONthink AppleScript 래퍼 (port 8093)
├── inbox_processor.py    ← OmniFocus Inbox 폴링 (LaunchAgent, 5분)
├── news_digest.py        ← 뉴스 번역·요약 (LaunchAgent, 매일 07:00)
├── manage_services.sh    ← 네이티브 서비스 관리 (start/stop/status)
├── deploy_workflows.sh   ← n8n 워크플로우 자동 배포 (REST API)
├── start-bridge.sh       ← 브릿지 서비스 시작 헬퍼
├── com.syn-chat-bot.*.plist ← LaunchAgent 설정 (6개)
├── docs/
│   ├── architecture.md   ← 아키텍처, DB 스키마, 파이프라인 상세
│   └── claude-code-playbook.md
├── n8n/
│   ├── data/             ← n8n 런타임 데이터
│   └── workflows/
│       ├── main-chat-pipeline.json  ← 메인 워크플로우 (51노드)
│       └── mail-processing-pipeline.json ← 메일 처리 파이프라인 (7노드)
├── init/
│   ├── init.sql          ← DB 초기 스키마 v2 (12테이블)
│   ├── migrate-v2.sql    ← 기존 DB 마이그레이션
│   ├── migrate-v3.sql    ← v3 마이그레이션 (Phase 5-6 테이블)
│   └── setup-qdrant.sh   ← Qdrant 컬렉션/인덱스 설정
└── postgres/data/        ← DB 데이터

트러블슈팅

# n8n 웹훅 안 올 때 — NAS에서 맥미니 접근 가능한지 확인
curl http://<맥미니IP>:5678/webhook-test/chat

# Ollama 임베딩 테스트 (맥미니)
curl http://localhost:11434/api/embeddings -d '{"model":"bge-m3","prompt":"test"}'

# GPU 서버 분류 테스트
curl http://192.168.1.186:11434/api/generate -d '{"model":"id-9b:latest","prompt":"안녕하세요","stream":false}'

# Qdrant 컬렉션 확인
curl http://localhost:6333/collections

# tk_company 검색 테스트
curl -X POST http://localhost:6333/collections/tk_company/points/search \
  -H 'Content-Type: application/json' \
  -d '{"vector": [0.1, ...], "limit": 3, "with_payload": true}'

# bot-postgres 접속
docker exec -it bot-postgres psql -U bot -d chatbot

# 분류기 로그 확인
docker exec bot-postgres psql -U bot -d chatbot -c "SELECT created_at, output_json->>'intent', output_json->>'response_tier', fallback_used FROM classification_logs ORDER BY created_at DESC LIMIT 10"

# API 사용량 확인
docker exec bot-postgres psql -U bot -d chatbot -c "SELECT * FROM api_usage_monthly ORDER BY year DESC, month DESC"

# GPU 서버 연결 안 될 때
ping 192.168.1.186
curl -s http://192.168.1.186:11434/api/tags

# chat_bridge 상태 확인
curl -s http://localhost:8091/health | python3 -m json.tool

# chat_bridge 사진 조회 테스트
curl -s -X POST http://localhost:8091/chat/recent-photo \
  -H 'Content-Type: application/json' \
  -d '{"channel_id":17,"user_id":6,"before_timestamp":9999999999999}' | python3 -m json.tool

# chat_bridge 로그
tail -50 /tmp/chat-bridge.log
tail -50 /tmp/chat-bridge.err

# caldav_bridge 상태 확인
curl -s http://localhost:8092/health | python3 -m json.tool

# devonthink_bridge 상태 확인
curl -s http://localhost:8093/health | python3 -m json.tool

# inbox_processor 로그
tail -50 /tmp/inbox-processor.log

# news_digest 로그
tail -50 /tmp/news-digest.log

n8n 접속 정보

Synology Chat 연동

NAS에서 Outgoing Webhook 설정 필요:

  1. Synology Chat > 통합 > 봇 > 만들기
  2. 발신 웹훅(Outgoing Webhook) URL: http://<맥미니IP>:5678/webhook/chat
  3. 토큰은 자동 생성됨 → .env의 SYNOLOGY_CHAT_TOKEN에 설정

수신 웹훅(Incoming Webhook)은 .env의 SYNOLOGY_CHAT_WEBHOOK_URL에 이미 설정됨.

진행 상황

Phase 0: 맥미니 정리

  • ollama rm qwen3.5:35b-a3b (삭제)
  • ollama rm qwen3.5:35b-a3b-think (삭제)

Phase 1: 기반 (Qdrant + DB)

  • init.sql v2 (12테이블 + 분류기 v2 프롬프트 + 메모리 판단 프롬프트)
  • migrate-v2.sql (기존 DB 마이그레이션)
  • setup-qdrant.sh (tk_company 컬렉션 + 인덱스)
  • DB 마이그레이션 실행
  • Qdrant 설정 실행

Phase 2: 3단계 라우팅 + 검색 라우팅

  • 워크플로우 v2 (42노드): 토큰검증, Rate Limit, 프리필터, 분류기v2, 3-tier, 멀티-컬렉션 RAG
  • .env + docker-compose.yml 환경변수 추가
  • n8n에 워크플로우 임포트 + 활성화
  • 테스트: "안녕" → local, "요약해줘" → Haiku, "법률 해석" → Opus

Phase 3: 선택적 메모리

  • Memorization Check 노드 (비동기, 응답 후)
  • Should Memorize? + Embed & Save Memory
  • 테스트: 인사 → 미저장, 기술질문 → 저장

Phase 4: 회사 문서 등록

  • /문서등록 명령어 파서 (placeholder)
  • 텍스트 청킹 + 임베딩 + tk_company 저장 구현
  • 문서 버전 관리 (deprecated + version++)

Phase 5: 현장 리포팅 + API 사용량 추적

  • field_reports 테이블 + SLA 인덱스
  • 비전 모델 사진 분석 (base64 변환 + HEIC 자동 변환)
  • HEIC→JPEG 변환 서비스 (heic_converter.py, macOS sips)
  • chat_bridge.py — DSM Chat API 브릿지 (사진 폴링 + 다운로드 + ack)
  • n8n Handle Log Event / Handle Field Report → bridge 연동
  • API 사용량 추적 (api_usage_monthly UPSERT)
  • /보고서 월간 보고서 생성 구현
  • report_cache 캐시 + --force 재생성

Phase 6: 캘린더·메일·DEVONthink·OmniFocus·뉴스

  • mail_logs, calendar_events 테이블
  • 분류기 v3 (calendar, reminder, mail, note intent 추가)
  • caldav_bridge.py — CalDAV REST 래퍼 (Synology Calendar)
  • devonthink_bridge.py — DEVONthink AppleScript 래퍼
  • inbox_processor.py — OmniFocus Inbox 폴링 (LaunchAgent, 5분)
  • news_digest.py — 뉴스 번역·요약 (LaunchAgent, 매일 07:00)
  • manage_services.sh — 네이티브 서비스 관리
  • LaunchAgent plist 6개
  • n8n 파이프라인 51노드 (calendar/mail/note 핸들러 추가)
  • Mail Processing Pipeline (7노드, IMAP 폴링)
  • migrate-v3.sql (news_digest_log + calendar_events 확장)

서비스 기동 전제조건

  • Synology Calendar (CalDAV) — NAS에서 활성화 필요
  • Synology MailPlus — NAS에서 활성화 + 계정 설정 필요
  • DEVONthink 4 — 맥미니에 설치 필요 (AppleScript 접근)
  • OmniFocus — 맥미니에 설치 필요 (Inbox 폴링)

검증 체크리스트

  1. curl localhost:6333/collections → documents, tk_company, chat_memory 존재
  2. "안녕" → 프리필터 → local 응답 (GPU 미호출)
  3. "이거 요약해줘" → Haiku 답변
  4. "이 법률 해석해줘" → Opus 답변
  5. 인사 → chat_memory 미저장 (chat_logs에는 기록)
  6. 기술 질문 → chat_memory 저장
  7. "아까 물어본 거" → chat_memory 검색 성공
  8. GPU 서버 다운 → fallback Haiku 답변
  9. 잘못된 토큰 → reject
  10. 10초 내 6건 → rate limit
  11. "내일 회의 잡아줘" → calendar intent → CalDAV 이벤트 생성
  12. "최근 메일 확인" → mail intent → 메일 요약 반환
  13. "이거 메모해둬" → note intent → DEVONthink 저장