diff --git a/README.md b/README.md index 6a8c946..d554bed 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ - [로빙 컨테이너 아키텍처 설계](./docs/architecture/로빙_컨테이너_아키텍처_설계.md) - [Nginx 아키텍처](./docs/architecture/Nginx_아키텍처.md) - [스킬 허브 아키텍처](./docs/architecture/skillhub_architecture.md) +- [경량 버전 제의](./docs/architecture/로빙_아키텍쳐_설계_경량.md) ### 구현 가이드 - [MVP 단계 상세 계획](./docs/implementation/01_MVP%20단계_%20자세한%20계획.md) diff --git a/docs/architecture/로빙_아키텍쳐_설계_경량.md b/docs/architecture/로빙_아키텍쳐_설계_경량.md new file mode 100644 index 0000000..ee6d98a --- /dev/null +++ b/docs/architecture/로빙_아키텍쳐_설계_경량.md @@ -0,0 +1,433 @@ +# 로빙(Robing) 슬랙 요약 스킬 아키텍처 설계 + +## 1. 개요 + +### 1.1 배경 +- 로빙은 스탯 기반 성장형 AI 에이전트로, 회사별로 독립적인 컨테이너로 배포됨 +- 로빙 브레인은 스킬 라우팅과 결과 판단에 집중하며, 실제 처리는 공용 스킬 서버에서 수행 +- 프롬프트용 기억은 컨테이너 외부의 공용 저장소에 보관 + +### 1.2 설계 원칙 +- **경량화**: 회사별 로빙 컨테이너는 최소한의 리소스(512MB)로 운영 +- **확장성**: 스킬 서버는 독립적으로 스케일링 가능 +- **비용 효율성**: LLM API는 공용 서버에서만 호출하여 비용 최적화 +- **독립성**: 각 스킬은 마이크로서비스로 분리되어 독립적 배포/업데이트 가능 + +## 2. 전체 아키텍처 + +### 2.1 멀티테넌트 구조 + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ 회사 A 로빙 │ │ 회사 B 로빙 │ │ 회사 C 로빙 │ +│ (가벼운 라우터) │ │ (가벼운 라우터) │ │ (가벼운 라우터) │ +└────────┬────────┘ └────────┬────────┘ └────────┬────────┘ + │ │ │ + └───────────────────────┴───────────────────────┘ + │ + ┌────────────▼────────────┐ + │ 공용 스킬 서버 클러스터 │ + ├─────────────────────────┤ + │ • 슬랙 요약 서비스 │ + │ • 이메일 파싱 서비스 │ + │ • 일정 관리 서비스 │ + │ • LLM 처리 (Gemini/GPT) │ + └─────────────────────────┘ + │ + ┌────────────▼────────────┐ + │ 공용 데이터 저장소 │ + ├─────────────────────────┤ + │ • ChromaDB (벡터 DB) │ + │ • PostgreSQL (메타데이터) │ + │ • Redis (캐싱) │ + └─────────────────────────┘ +``` + +### 2.2 데이터 흐름 + +``` +1. Slack Event → 회사별 로빙 컨테이너 +2. 로빙 브레인이 의도 분석 (키워드 기반, LLM 없이) +3. 적절한 스킬 서버로 라우팅 +4. 스킬 서버에서 LLM 처리 및 결과 생성 +5. 결과를 로빙 컨테이너로 반환 +6. 로빙이 Slack으로 응답 전송 +``` + +## 3. 로빙 컨테이너 설계 + +### 3.1 핵심 역할 +- **Slack 이벤트 게이트웨이**: 회사별 Slack 이벤트 수신 및 ACK 응답 +- **간단한 의도 분석**: 키워드 기반 빠른 분류 (LLM 없이) +- **스킬 라우팅**: 적절한 스킬 서버로 요청 전달 +- **회사별 컨텍스트 관리**: 회사 설정, 사용자 스탯, 활성 스킬 관리 +- **학습 욕구 기록**: 처리하지 못한 요청 로컬 기록 + +### 3.2 구조 + +```python +app/ +├── core/ +│ ├── config.py # 회사별 설정 +│ ├── auth.py # 인증/인가 +│ └── router.py # 스킬 라우팅 +├── brain/ +│ └── intent.py # 의도 분석 (경량) +├── api/ +│ └── slack.py # Slack 이벤트 수신 +└── main.py # FastAPI 앱 +``` + +### 3.3 로빙 브레인 구현 + +```python +class RobeingBrain: + """스킬 라우터 + 의사결정자""" + + def __init__(self, company_id: str): + self.company_id = company_id + self.skill_registry = { + "요약": "http://skill-summary:8001", + "이메일": "http://skill-email:8002", + "일정": "http://skill-calendar:8003" + } + + async def route_message(self, message: str, context: dict): + # 1. 간단한 의도 분석 (LLM 없이) + intent = self._quick_intent_check(message) + + # 2. 스킬 결정 + skill_url = self.skill_registry.get(intent) + + # 3. 스킬 서버로 전달 + if skill_url: + return await self._call_skill(skill_url, message, context) + else: + self._record_learning_desire(message) + return "아직 그 기능은 없어요" +``` + +## 4. 슬랙 요약 스킬 마이크로서비스 + +### 4.1 프로젝트 구조 + +``` +skill-slack-summary/ +├── Dockerfile +├── requirements.txt +├── src/ +│ ├── api/ +│ │ └── endpoints.py # REST API +│ ├── core/ +│ │ ├── config.py +│ │ └── security.py # API 키 검증 +│ ├── services/ +│ │ ├── slack_client.py # Slack API 통신 +│ │ ├── summarizer.py # LLM 요약 로직 +│ │ └── memory.py # ChromaDB 인터페이스 +│ ├── models/ +│ │ └── summary.py # 데이터 모델 +│ └── utils/ +│ ├── cache.py # Redis 캐싱 +│ └── rate_limiter.py # API 제한 관리 +└── main.py +``` + +### 4.2 API 엔드포인트 + +```python +from fastapi import FastAPI, Depends +from pydantic import BaseModel + +app = FastAPI() + +class SummaryRequest(BaseModel): + company_id: str + channel_id: str + time_range: str # "1h", "2h", "today", etc. + user_id: str + user_stats: Dict[str, int] + +@app.post("/summarize") +async def summarize_messages( + request: SummaryRequest, + auth: str = Depends(verify_auth) +): + """슬랙 메시지 요약""" + # 1. 메시지 수집 + messages = await slack_client.fetch_messages( + request.channel_id, + request.time_range + ) + + # 2. LLM으로 요약 + summary = await summarizer.process(messages) + + # 3. 메모리 저장 + await memory_service.save(request.company_id, summary) + + return { + "summary": summary.content, + "key_points": summary.key_points, + "action_items": summary.action_items + } +``` + +### 4.3 스킬 메타데이터 + +```python +class SkillMetadata(BaseModel): + name: str = "slack_summary" + version: str = "1.0.0" + description: str = "슬랙 회의 내용 요약" + required_stats: Dict[str, int] = {"memory": 5} + triggers: List[str] = ["회의 요약", "미팅 정리", "summary"] +``` + +## 5. 통신 프로토콜 + +### 5.1 로빙 → 스킬 서비스 요청 + +```json +{ + "company_id": "company_a", + "user_id": "U123456", + "skill": "slack_summary", + "auth_token": "jwt_token", + "payload": { + "channel_id": "C789012", + "time_range": "2h", + "thread_ts": "1234567890.123456" + }, + "context": { + "user_stats": {"memory": 15, "compute": 10}, + "workspace_id": "T123456" + } +} +``` + +### 5.2 스킬 서비스 → 로빙 응답 + +```json +{ + "status": "success", + "data": { + "summary": "오늘 회의에서는 다음 분기 제품 로드맵에 대해 논의했습니다...", + "key_points": [ + "Q2 신제품 출시 일정 확정", + "마케팅 예산 20% 증액 승인" + ], + "action_items": [ + { + "assignee": "@김철수", + "task": "프로토타입 데모 준비", + "due_date": "2025-07-15" + } + ] + }, + "metadata": { + "processing_time": 2.5, + "tokens_used": 1500, + "cache_hit": false + } +} +``` + +## 6. LLM 처리 및 비용 최적화 + +### 6.1 LLM 관리 전략 + +```python +class LLMManager: + """중앙 집중식 LLM 관리""" + def __init__(self): + self.gemini_client = GeminiClient() + self.openai_client = OpenAIClient() + self.cache = Redis() + self.rate_limiter = RateLimiter() + + async def summarize(self, messages: List[str], company_id: str): + # 1. 캐시 확인 + cache_key = f"summary:{company_id}:{hash(messages)}" + if cached := await self.cache.get(cache_key): + return cached + + # 2. Rate limiting + await self.rate_limiter.check(company_id) + + # 3. LLM 호출 + summary = await self.gemini_client.summarize(messages) + + # 4. 캐시 저장 + await self.cache.set(cache_key, summary, ttl=3600) + + return summary +``` + +### 6.2 Rate Limit 대응 + +1. **다중 API 키 풀**: 여러 API 키를 로테이션하여 사용 +2. **큐 기반 처리**: 우선순위 큐로 유료 고객 우선 처리 +3. **배치 처리**: 여러 요청을 하나의 프롬프트로 묶어 처리 +4. **계층적 처리**: 부하에 따라 다른 모델 사용 (Pro vs Flash) +5. **스마트 캐싱**: 유사한 요청에 대한 캐시 재사용 + +## 7. 메모리 저장 구조 + +### 7.1 ChromaDB Collection + +```json +{ + "collection": "meeting_summaries", + "documents": [ + { + "id": "summary_company_a_20250701_123456", + "content": "오늘 회의에서는 다음 분기 계획을 논의했습니다...", + "metadata": { + "company_id": "company_a", + "user_id": "U123456", + "channel_id": "C789012", + "timestamp": "2025-07-01T14:30:00", + "participants": ["user1", "user2", "user3"], + "key_points": ["포인트1", "포인트2"], + "action_items": ["할일1", "할일2"], + "skill_version": "1.0.0" + } + } + ] +} +``` + +## 8. 배포 구성 + +### 8.1 Docker Compose - 공용 스킬 서버 + +```yaml +# docker-compose.skills.yml +version: '3.8' + +services: + skill-slack-summary: + build: ./skills/slack-summary + image: robing-skills/slack-summary:latest + ports: + - "8001:8001" + environment: + - GEMINI_API_KEY=${GEMINI_API_KEY} + - OPENAI_API_KEY=${OPENAI_API_KEY} + - REDIS_URL=redis://redis:6379 + - CHROMADB_HOST=chromadb + - MAX_REQUESTS_PER_MINUTE=60 + deploy: + replicas: 3 + resources: + limits: + memory: 2G + + redis: + image: redis:7-alpine + volumes: + - redis_data:/data + + chromadb: + image: chromadb/chroma + volumes: + - chroma_data:/chroma/chroma +``` + +### 8.2 Docker Compose - 회사별 로빙 + +```yaml +# docker-compose.company-a.yml +version: '3.8' + +services: + robing-company-a: + image: robing/core:latest + environment: + - COMPANY_ID=company_a + - SLACK_BOT_TOKEN=${COMPANY_A_SLACK_TOKEN} + - SLACK_SIGNING_SECRET=${COMPANY_A_SIGNING_SECRET} + - SKILL_SERVER_URL=https://skills.robing.ai + - JWT_SECRET=${JWT_SECRET} + ports: + - "10001:8000" + deploy: + resources: + limits: + memory: 512M + cpus: '0.5' + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + retries: 3 +``` + +## 9. 확장성 고려사항 + +### 9.1 수평 확장 +- 로빙 컨테이너: 회사별로 독립 배포, 필요시 여러 인스턴스 가능 +- 스킬 서버: 부하에 따라 레플리카 수 조정 +- 데이터베이스: 읽기 전용 복제본 추가 + +### 9.2 지역별 배포 +- 회사 위치에 따라 가까운 리전에 로빙 컨테이너 배포 +- 스킬 서버는 중앙 또는 주요 리전에 배포 + +### 9.3 모니터링 +- Prometheus + Grafana로 실시간 모니터링 +- 회사별 사용량 추적 +- API 사용량 및 비용 대시보드 + +## 10. 보안 고려사항 + +### 10.1 인증/인가 +- 로빙-스킬 간 통신: JWT 토큰 기반 인증 +- 회사별 데이터 격리: company_id 기반 접근 제어 +- API 키 관리: 환경 변수로 관리, 로빙 컨테이너에는 노출하지 않음 + +### 10.2 데이터 보호 +- 전송 중 암호화: HTTPS 사용 +- 저장 시 암호화: 민감한 데이터는 암호화하여 저장 +- 로그 마스킹: 개인정보가 로그에 노출되지 않도록 처리 + +## 11. 성능 최적화 + +### 11.1 캐싱 전략 +- Redis를 통한 LLM 응답 캐싱 +- 자주 요청되는 요약에 대한 사전 처리 +- 유사 요청 감지 및 재사용 + +### 11.2 비동기 처리 +- 모든 I/O 작업은 비동기로 처리 +- 백그라운드 태스크로 무거운 작업 분리 +- 웹훅 방식으로 결과 전달 옵션 + +## 12. 향후 로드맵 + +### Phase 1 (현재) +- 기본 슬랙 요약 기능 구현 +- 단일 스킬 서버 운영 + +### Phase 2 +- 다국어 지원 (한국어/영어) +- 실시간 요약 스트리밍 +- 더 많은 스킬 추가 + +### Phase 3 +- AI 기반 요약 품질 개선 +- 사용자별 요약 스타일 학습 +- 스킬 마켓플레이스 구축 + +## 13. 결론 + +이 아키텍처는 다음과 같은 이점을 제공합니다: + +1. **확장성**: 회사가 증가해도 효율적으로 대응 가능 +2. **비용 효율성**: LLM API 사용을 최적화하여 비용 절감 +3. **독립성**: 각 컴포넌트가 독립적으로 배포/업데이트 가능 +4. **안정성**: 장애 격리로 전체 시스템 안정성 향상 +5. **성능**: 캐싱과 배치 처리로 응답 속도 향상 + +이 설계를 통해 로빙은 수백 개의 회사를 효율적으로 서비스할 수 있는 확장 가능한 플랫폼으로 성장할 수 있습니다. \ No newline at end of file