RAG 아키텍처 v2: 3단계 라우팅, 멀티-컬렉션 RAG, 선택적 메모리
Phase 1-3 구현: - init.sql v2: 12테이블 (기존 5 + 신규 7) + 분류기 v2 프롬프트 - migrate-v2.sql: 기존 DB 마이그레이션 스크립트 - setup-qdrant.sh: tk_company 컬렉션 + payload 인덱스 설정 - 워크플로우 v2 (37노드): 토큰검증, Rate Limit, 프리필터, 분류기v2(response_tier), 3-tier 라우팅(local/Haiku/Opus), 멀티-컬렉션 RAG, 예산 체크, 선택적 메모리 - .env.example + docker-compose.yml: 새 환경변수 추가 - CLAUDE.md, QUICK_REFERENCE.md, docs/architecture.md 전면 갱신 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
331
docs/architecture.md
Normal file
331
docs/architecture.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# Architecture
|
||||
|
||||
## 전체 아키텍처
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ Synology Chat │ 사용자 인터페이스
|
||||
│ (NAS 192.168.1.227)│
|
||||
└─────────┬───────────┘
|
||||
│ Outgoing Webhook
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ bot-n8n (맥미니 Docker :5678) — 37노드 파이프라인 │
|
||||
│ │
|
||||
│ ⓪ 토큰 검증 + Rate Limit (username별 10초/5건) │
|
||||
│ │
|
||||
│ ① 규칙 기반 프리필터 │
|
||||
│ └─ 인사/감사 정규식 매칭 → 하드코딩 local 응답 │
|
||||
│ │
|
||||
│ ② 명령어 체크 (/설정, /모델, /성격, /문서등록, /보고서) │
|
||||
│ └─ 권한 체크 (ADMIN_USERNAMES allowlist) │
|
||||
│ │
|
||||
│ ③ GPU Qwen 9B 분류 v2 (10초 타임아웃) │
|
||||
│ → {intent, response_tier, needs_rag, rag_target, ...} │
|
||||
│ └─ 실패 시 fallback → api_light │
|
||||
│ │
|
||||
│ ④ [needs_rag=true] 멀티-컬렉션 RAG 검색 │
|
||||
│ documents + tk_company + chat_memory │
|
||||
│ → bge-m3 임베딩 → Qdrant 검색 → reranker → top-3 │
|
||||
│ │
|
||||
│ ⑤ response_tier 3단계 분기 │
|
||||
│ ├─ local → Qwen 9B 직접 답변 │
|
||||
│ ├─ api_light → Claude Haiku │
|
||||
│ └─ api_heavy → 예산 체크 → Claude Opus (or 다운그레이드) │
|
||||
│ │
|
||||
│ ⑥ 응답 전송 + chat_logs + api_usage_monthly │
|
||||
│ ⑦ [비동기] Qwen 메모리 판단 → 가치 있으면 벡터화 │
|
||||
│ └─ classification_logs 기록 │
|
||||
└──┬──────────┬───────────┬───────────┬──────────────────────┘
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
┌──────┐ ┌────────┐ ┌─────────┐ ┌──────────────┐
|
||||
│bot- │ │Qdrant │ │Ollama │ │Ollama (GPU) │
|
||||
│postgres│ │:6333 │ │:11434 │ │192.168.1.186 │
|
||||
│:15478│ │3컬렉션 │ │bge-m3 │ │:11434 │
|
||||
│12테이블│ │documents│ │reranker│ │qwen3.5:9b │
|
||||
│ │ │tk_company││비전모델 │ │(분류+응답) │
|
||||
│ │ │chat_memory│ │ │ │
|
||||
└──────┘ └────────┘ └─────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## 3단계 라우팅 상세
|
||||
|
||||
### response_tier 판단 (Qwen 9B 분류기 v2)
|
||||
|
||||
| tier | 모델 | 비용 | 대상 |
|
||||
|------|------|------|------|
|
||||
| **local** | Qwen 9B (GPU) | 무료 | 인사, 잡담, 단순 확인, 감사, 짧은 반응 |
|
||||
| **api_light** | Claude Haiku | ~$0.8/1M in, $4/1M out | 요약, 번역, RAG 정리, 비교 분석 |
|
||||
| **api_heavy** | Claude Opus | ~$15/1M in, $75/1M out | 법률 해석, 다중 문서 분석, 보고서 작성 |
|
||||
|
||||
**비용 최적화 목표:**
|
||||
- ~40% → local (무료, 프리필터+Qwen 직접 답변)
|
||||
- ~50% → Haiku (저비용)
|
||||
- ~10% → Opus (복잡한 질문만)
|
||||
|
||||
### 분류기 v2 출력 스키마
|
||||
|
||||
```json
|
||||
{
|
||||
"intent": "greeting|question|calendar|reminder|mail|photo|command|report|other",
|
||||
"response_tier": "local|api_light|api_heavy",
|
||||
"needs_rag": true,
|
||||
"rag_target": ["documents", "tk_company", "chat_memory"],
|
||||
"department_hint": "안전|생산|구매|품질|null",
|
||||
"report_domain": "안전|시설설비|품질|null",
|
||||
"query": "검색용 쿼리"
|
||||
}
|
||||
```
|
||||
|
||||
### 프리필터 → 분류기 → 모델 라우팅 흐름
|
||||
|
||||
```
|
||||
메시지 수신
|
||||
│
|
||||
├─ 프리필터 매칭 (인사/감사 정규식)
|
||||
│ └─ 매칭 → 하드코딩 local 응답 (GPU 서버 미호출)
|
||||
│
|
||||
└─ 미매칭 → Qwen 9B 분류기
|
||||
├─ response_tier=local → Qwen 9B 직접 답변
|
||||
├─ response_tier=api_light → Claude Haiku
|
||||
└─ response_tier=api_heavy → 예산 체크
|
||||
├─ 예산 내 → Claude Opus
|
||||
└─ 초과 → Claude Haiku (다운그레이드)
|
||||
```
|
||||
|
||||
## 3-컬렉션 RAG 상세
|
||||
|
||||
### 컬렉션 구조
|
||||
|
||||
| 컬렉션 | 용도 | 벡터 차원 | 필터 |
|
||||
|--------|------|----------|------|
|
||||
| `documents` | 개인/일반 문서, 메일 요약 | 1024 (bge-m3) | 없음 |
|
||||
| `tk_company` | TK 회사 문서, 현장 리포트 | 1024 (bge-m3) | department, year, doc_type |
|
||||
| `chat_memory` | 가치 있는 대화 기억 | 1024 (bge-m3) | username, topic, intent |
|
||||
|
||||
### 멀티-컬렉션 검색 흐름
|
||||
|
||||
```
|
||||
rag_target에 따라 동적 검색:
|
||||
- 단일 컬렉션 → top-10
|
||||
- 2개 → 각 top-7
|
||||
- 3개 → 각 top-5
|
||||
|
||||
각 컬렉션별 필터:
|
||||
- documents: 필터 없음
|
||||
- tk_company: department + year 필터
|
||||
- chat_memory: username 필터
|
||||
|
||||
합산 → bge-reranker 리랭킹 (실패 시 Qdrant score 정렬) → top-3
|
||||
|
||||
출처 표시:
|
||||
[회사/안전/절차서] 고소작업 안전절차 - "작업 전 반드시..."
|
||||
[개인문서] Safety Engineering - "Workers at height..."
|
||||
[이전대화/2026-03-10] "고소작업은 2m 이상..."
|
||||
```
|
||||
|
||||
### tk_company payload
|
||||
|
||||
```
|
||||
text, year(인덱스), department(인덱스), doc_type(인덱스),
|
||||
title, source_file, file_hash, chunk_index, total_chunks,
|
||||
uploaded_by, created_at(인덱스)
|
||||
```
|
||||
|
||||
### chat_memory payload
|
||||
|
||||
```
|
||||
text, feature, intent, username(인덱스), topic(인덱스), timestamp
|
||||
```
|
||||
|
||||
## 선택적 대화 메모리
|
||||
|
||||
```
|
||||
응답 전송 (즉시)
|
||||
↓ [비동기]
|
||||
Qwen 9B Memorization Check:
|
||||
"저장: 사실 정보, 결정사항, 선호, 지시, 기술 정보"
|
||||
"무시: 인사, 잡담, 날씨, 봇이 모른다고 답한 것"
|
||||
출력: {"save": true/false, "topic": "general|company|technical|personal"}
|
||||
↓
|
||||
Should Memorize?
|
||||
├─ true → bge-m3 Embed → chat_memory 저장
|
||||
└─ false → 스킵 (chat_logs에는 기록됨)
|
||||
```
|
||||
|
||||
- local tier (인사 등)는 메모리 체크 자체를 스킵 (GPU 절약)
|
||||
|
||||
## DB 스키마 상세
|
||||
|
||||
### 기존 테이블 (v1)
|
||||
|
||||
```sql
|
||||
-- ai_configs: feature별 모델/프롬프트 독립 관리
|
||||
-- feature: 'classifier', 'chat', 'chat_local', 'calendar', 'mail_summary'
|
||||
|
||||
-- routing_rules: complexity 기반 라우팅 (레거시 호환)
|
||||
|
||||
-- prompts: 프롬프트 버전 관리
|
||||
-- feature: 'classifier' v2 (활성), 'chat_local', 'memorize_check'
|
||||
|
||||
-- chat_logs: 대화 기록 (v2: +username, +response_tier)
|
||||
|
||||
-- mail_accounts: 메일 소스 관리 (Phase 6)
|
||||
```
|
||||
|
||||
### 신규 테이블 (v2)
|
||||
|
||||
```sql
|
||||
-- document_ingestion_log: 문서 등록 이력 + 버전 관리
|
||||
-- file_hash 중복 체크, doc_group_key로 버전 연결
|
||||
-- status: processing/completed/failed/deprecated
|
||||
|
||||
-- field_reports: 현장 리포트 (안전/시설설비/품질 통합)
|
||||
-- domain, category, severity → SLA 자동 계산
|
||||
-- due_at 기반 미처리 조회
|
||||
|
||||
-- classification_logs: 분류기 성능 모니터링
|
||||
-- input_text (200자 제한), output_json (JSONB)
|
||||
-- fallback_used, latency_ms
|
||||
|
||||
-- mail_logs: 메일 수신 로그 + 분류
|
||||
|
||||
-- calendar_events: 캘린더 이벤트
|
||||
|
||||
-- report_cache: 보고서 캐시 (domain + year_month UNIQUE)
|
||||
-- 동일 파라미터 재요청 → 캐시 반환, --force로 재생성
|
||||
|
||||
-- api_usage_monthly: API 사용량 + 예산 상한
|
||||
-- year + month + tier UNIQUE
|
||||
-- estimated_cost vs budget_limit 비교 → 다운그레이드
|
||||
```
|
||||
|
||||
### SLA 기준표
|
||||
|
||||
| domain | severity | 처리 기한 |
|
||||
|--------|----------|----------|
|
||||
| 안전 | 상 | 24시간 |
|
||||
| 안전 | 중 | 72시간 |
|
||||
| 안전 | 하 | 7일 |
|
||||
| 시설설비 | 상 | 48시간 |
|
||||
| 시설설비 | 중 | 5일 |
|
||||
| 시설설비 | 하 | 14일 |
|
||||
| 품질 | 상 | 48시간 |
|
||||
| 품질 | 중 | 5일 |
|
||||
| 품질 | 하 | 14일 |
|
||||
|
||||
## 안전장치
|
||||
|
||||
### 보안
|
||||
- **웹훅 토큰 검증**: SYNOLOGY_CHAT_TOKEN 비교, 불일치 → reject
|
||||
- **명령어 권한 체크**: ADMIN_USERNAMES allowlist
|
||||
- **서비스 포트 격리**: DB/Qdrant는 127.0.0.1 바인딩
|
||||
- **classification_logs**: input 200자 제한
|
||||
|
||||
### 비용 폭주 방지
|
||||
- **규칙 기반 프리필터**: GPU 서버 다운 시에도 잡담은 API 미호출
|
||||
- **Rate Limit**: username별 10초/5건 (in-memory, workflow static data)
|
||||
- **예산 상한**: api_usage_monthly → 초과 시 api_heavy→api_light 다운그레이드
|
||||
|
||||
### 파이프라인 복원력
|
||||
- **분류기 fallback**: Qwen 10초 타임아웃 → {response_tier: "api_light"}
|
||||
- **리랭커 fallback**: bge-reranker 실패 → Qdrant score 정렬
|
||||
- **비전 모델 fallback**: 사진 분석 실패 → 사용자 설명만으로 구조화
|
||||
|
||||
## 메인 채팅 파이프라인 v2 (37노드)
|
||||
|
||||
```
|
||||
Webhook POST /chat
|
||||
│
|
||||
▼
|
||||
[Parse Input] — 토큰 검증 + Rate Limit
|
||||
│
|
||||
├─ rejected → [Reject Response] → Send + Respond
|
||||
│
|
||||
▼
|
||||
[Regex Pre-filter] — 인사/감사 정규식
|
||||
│
|
||||
├─ match → [Pre-filter Response] → Send + Respond
|
||||
│
|
||||
▼
|
||||
[Is Command?]
|
||||
│
|
||||
├─ true → [Parse Command] + 권한 체크
|
||||
│ ├─ DB 필요 → [Command DB Query] → [Format] → Send + Respond
|
||||
│ └─ 직접 → [Direct Response] → Send + Respond
|
||||
│
|
||||
└─ false → [Qwen Classify v2] (10초 타임아웃)
|
||||
│
|
||||
├─ [Log Classification] (비동기, PostgreSQL)
|
||||
│
|
||||
├─ needs_rag=true
|
||||
│ → [Get Embedding] → [Multi-Collection Search]
|
||||
│ → [Build RAG Context] (출처 표시)
|
||||
│
|
||||
└─ needs_rag=false
|
||||
→ [No RAG Context]
|
||||
│
|
||||
▼
|
||||
[Route by Tier]
|
||||
├─ local → [Call Qwen Response]
|
||||
├─ api_light → [Call Haiku]
|
||||
└─ api_heavy → [Call Opus] (예산 체크 포함)
|
||||
│
|
||||
▼
|
||||
[Send to Chat] + [Respond Webhook] + [Log to DB]
|
||||
+ [API Usage Log] (API tier만)
|
||||
│
|
||||
▼ [비동기]
|
||||
[Memorization Check] → [Should Memorize?]
|
||||
├─ true → [Embed & Save Memory]
|
||||
└─ false → (끝)
|
||||
```
|
||||
|
||||
## 페르소나: 이드
|
||||
|
||||
### 전체 프롬프트 (api_light/api_heavy)
|
||||
|
||||
```
|
||||
당신의 이름은 "이드"입니다.
|
||||
|
||||
[성격]
|
||||
- 배려심이 깊고 대화 상대의 기분을 우선시합니다
|
||||
- 서포트하는 데 초점을 맞추며, 독선적이지 않습니다
|
||||
- 의견을 제시할 때는 부드럽게, 강요하지 않습니다
|
||||
- 틀린 것을 바로잡을 때도 상대방이 기분 나쁘지 않게 합니다
|
||||
|
||||
[말투]
|
||||
- 부드러운 존댓말을 사용합니다
|
||||
- 자신을 지칭할 때 겸양어를 씁니다
|
||||
- 자기 이름을 직접 말하지 않습니다
|
||||
- 자연스럽고 편안한 톤
|
||||
- 이모지는 가끔 핵심 포인트에만 사용합니다
|
||||
|
||||
[응답 원칙]
|
||||
- 간결하고 핵심적으로 답합니다
|
||||
- 질문의 의도를 파악해서 필요한 만큼만 답합니다
|
||||
- 모르는 것은 솔직하게, 추측은 추측이라고 밝힙니다
|
||||
```
|
||||
|
||||
### 경량 프롬프트 (local tier)
|
||||
|
||||
```
|
||||
당신은 "이드"입니다. 배려심 깊고 부드러운 존댓말을 사용하는 개인 어시스턴트입니다.
|
||||
간결하게 답하고, 모르면 솔직히 말하세요. 이모지는 핵심에만.
|
||||
```
|
||||
|
||||
## 향후 기능 (Phase 4-6)
|
||||
|
||||
### Phase 4: 회사 문서 등록
|
||||
- `/문서등록 [부서] [유형] [제목]` → 청킹 → tk_company 저장
|
||||
- hash 중복 체크, 문서 버전 관리
|
||||
|
||||
### Phase 5: 현장 리포팅
|
||||
- 사진 + 텍스트 → 비전 모델 → 구조화 → field_reports + tk_company
|
||||
- `/보고서 [영역] [년월]` → 월간 보고서 생성
|
||||
- SLA 트래킹 + 긴급 에스컬레이션
|
||||
|
||||
### Phase 6: 메일 + 캘린더
|
||||
- IMAP 폴링 → Qwen 분석 → mail_logs + Qdrant
|
||||
- CalDAV 연동 → calendar_events
|
||||
103
docs/claude-code-playbook.md
Normal file
103
docs/claude-code-playbook.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Claude Code Playbook
|
||||
|
||||
실전에서 검증된 Claude Code 활용 패턴 정리.
|
||||
|
||||
---
|
||||
|
||||
## Part 1: 핵심 워크플로우
|
||||
|
||||
### 1. CLAUDE.md에 투자하라
|
||||
|
||||
- 실수할 때마다 CLAUDE.md `## 실수 방지` 섹션에 추가
|
||||
- PR 리뷰에서 `@.claude` 태그 → CLAUDE.md 자동 업데이트 (복리 엔지니어링)
|
||||
- 프로젝트별 노트 디렉토리를 유지하고 CLAUDE.md에서 참조
|
||||
|
||||
### 2. Plan 모드부터 시작
|
||||
|
||||
- 대부분의 세션을 Plan 모드(Shift+Tab 두 번)로 시작
|
||||
- 계획을 충분히 다듬은 후 Auto-accept 모드로 전환하여 구현
|
||||
- 복잡한 작업은 반드시 Plan 모드 — 원샷 구현을 노린다
|
||||
- 문제가 생기면 다시 Plan 모드로 전환
|
||||
|
||||
### 3. 슬래시 명령어로 반복 자동화
|
||||
|
||||
- 하루에 여러 번 반복하는 "내부 루프" 워크플로우마다 명령어 생성
|
||||
- `.claude/commands/`에 저장, Git에 커밋
|
||||
- 이 프로젝트의 명령어:
|
||||
- `/simplify` — 변경 코드 리뷰 및 단순화
|
||||
- `/verify` — 전체 검증 (docker, env, sql, 헬스체크)
|
||||
- `/status` — 프로젝트 상태 확인
|
||||
|
||||
### 4. 서브에이전트로 워크플로우 분담
|
||||
|
||||
- 요청에 "서브에이전트를 사용해"를 추가하면 분산 처리
|
||||
- 메인 에이전트의 컨텍스트가 깨끗하게 유지됨
|
||||
- 활용 패턴:
|
||||
- code-simplifier: 작업 후 코드 단순화
|
||||
- build-validator: 빌드 확인
|
||||
- code-architect: 아키텍처 설계
|
||||
|
||||
### 5. 검증 피드백 루프 (가장 중요)
|
||||
|
||||
> "Claude에게 작업을 검증할 방법을 주면 최종 결과물의 품질이 2-3배 올라간다."
|
||||
|
||||
- Claude가 모든 변경사항을 테스트하도록 한다
|
||||
- `/verify` 명령어로 자동 검증
|
||||
- UI 변경 시 스크린샷 기반 확인
|
||||
|
||||
---
|
||||
|
||||
## Part 2: 고급 패턴
|
||||
|
||||
### 6. 병렬 워크트리
|
||||
|
||||
- 3-5개 Git 워크트리를 동시에 띄우고, 각각 전용 Claude 세션
|
||||
- 셸 별칭(za, zb, zc)으로 한 키로 이동
|
||||
- 독립적인 기능/버그를 동시에 진행 가능
|
||||
|
||||
### 7. PostToolUse 훅으로 자동 포맷
|
||||
|
||||
- Claude가 생성한 코드를 자동 포맷팅
|
||||
- CI에서 포맷팅 에러 발생 방지
|
||||
- 나머지 10%를 훅이 처리
|
||||
|
||||
### 8. 안전한 명령어 사전 승인
|
||||
|
||||
- `--dangerously-skip-permissions`는 사용하지 않음
|
||||
- `/permissions`로 안전한 Bash 명령어를 미리 허용
|
||||
- `.claude/settings.json`에 체크인하여 공유
|
||||
|
||||
### 9. 도구 통합 (MCP)
|
||||
|
||||
- Slack 검색 및 메시지 전송
|
||||
- CLI로 분석 쿼리 실행
|
||||
- 에러 로그 조회
|
||||
- `.mcp.json`에 체크인하여 공유
|
||||
|
||||
### 10. 프롬프팅 레벨업
|
||||
|
||||
- PR 제출 전 Claude에게 변경사항 리뷰 요청
|
||||
- 수정 후: "지금까지 알게 된 모든 것을 바탕으로, 이걸 버리고 우아한 솔루션을 구현해."
|
||||
- 모호함을 줄이는 상세한 스펙 작성
|
||||
|
||||
### 11. 터미널 & 환경
|
||||
|
||||
- `/statusline`으로 컨텍스트 사용량과 Git 브랜치 표시
|
||||
- 음성 입력 (fn x 2, macOS)으로 상세한 프롬프트 작성
|
||||
|
||||
### 12. Claude로 학습하기
|
||||
|
||||
- `/config`에서 "Explanatory" 또는 "Learning" 출력 스타일 활성화
|
||||
- 익숙하지 않은 코드를 설명하는 HTML 프레젠테이션 생성
|
||||
- 프로토콜과 코드베이스의 ASCII 다이어그램 요청
|
||||
|
||||
---
|
||||
|
||||
## 이 프로젝트에 적용된 패턴
|
||||
|
||||
| 패턴 | 적용 방법 |
|
||||
|------|----------|
|
||||
| CLAUDE.md 투자 | 실수 발생 시 `## 실수 방지` 섹션에 누적 |
|
||||
| 슬래시 명령어 | `/simplify`, `/verify`, `/status` |
|
||||
| 검증 루프 | `/verify`로 docker, env, sql, 헬스체크 자동 검증 |
|
||||
| 안전한 명령어 | DB 포트 localhost 바인딩, .env git 제외 |
|
||||
Reference in New Issue
Block a user