로빙 아키텍쳐 경량 버전 제시

This commit is contained in:
0914eagle 2025-07-24 11:26:39 +09:00
parent 7ecef617af
commit 42d6b0335f
2 changed files with 434 additions and 0 deletions

View File

@ -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)

View File

@ -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. **성능**: 캐싱과 배치 처리로 응답 속도 향상
이 설계를 통해 로빙은 수백 개의 회사를 효율적으로 서비스할 수 있는 확장 가능한 플랫폼으로 성장할 수 있습니다.