mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 16:06:23 +00:00
- 아키텍처_최적안_결정.md 신규 생성 (ADR-000 ~ ADR-004) - 하이브리드 접근 전략 결정: 단계적 독립 운영 → 조건부 통합 - 용어집: PostgreSQL+pgvector, 관련회의록: Azure AI Search - 구현방안-관련자료.md: AD-000 섹션 업데이트 - 구현방안-용어집.md: ADR-000, ADR-001 업데이트 및 버전 1.1 반영 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1837 lines
61 KiB
Markdown
1837 lines
61 KiB
Markdown
# 맥락기반 용어설명 데이터 확보 및 Claude AI 연동 아키텍처 결정 문서
|
|
|
|
## 1단계: 각자의 생각
|
|
|
|
### 민준 (Product Owner)
|
|
비즈니스 관점에서 용어 데이터는 두 가지 소스가 핵심입니다.
|
|
1. **조직 문서**: 내부 업무 매뉴얼, 정책, 프로젝트 문서가 차별화의 핵심
|
|
2. **외부 기술 문서**: 범용 기술 용어는 보조적으로 활용
|
|
|
|
데이터 품질이 서비스 차별화의 핵심이므로, 초기에는 작은 규모로 시작해도 정확도가 높아야 합니다. MVP에서는 핵심 조직 문서 100개 정도로 시작하고, 점진적으로 확장하는 전략이 필요합니다.
|
|
|
|
### 서연 (AI Specialist)
|
|
**전문용어 처리 파이프라인**을 4단계로 제안합니다:
|
|
|
|
1. **수집 (Collection)**
|
|
- 조직문서: SharePoint, Confluence, Google Drive API 연동
|
|
- 외부문서: 공개 API 문서, GitHub 기술문서
|
|
|
|
2. **추출 (Extraction)**
|
|
- NER(Named Entity Recognition) 기반 기술용어 추출
|
|
- TF-IDF + 도메인 사전 기반 조직 특화 용어 추출
|
|
- Claude API를 활용한 맥락 기반 용어 추출
|
|
|
|
3. **정제 (Refinement)**
|
|
- 중복 제거: Fuzzy matching으로 유사 용어 통합
|
|
- 품질 검증: 인간 피드백 루프(HITL) 구축
|
|
- 메타데이터 태깅: 카테고리, 출처, 신뢰도 점수
|
|
|
|
4. **벡터라이징 (Vectorization)**
|
|
- **임베딩 모델**: OpenAI text-embedding-3-large 또는 Cohere embed-multilingual-v3.0
|
|
- **벡터 DB**: Pinecone 또는 Qdrant (관리형 vs 자체 호스팅)
|
|
- **청크 전략**:
|
|
- 용어 정의: 단일 청크 (256 토큰)
|
|
- 문맥 정보: 슬라이딩 윈도우 (512 토큰, 128 오버랩)
|
|
|
|
**Claude API 연동 구조**:
|
|
```json
|
|
{
|
|
"request": {
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"max_tokens": 1024,
|
|
"system": "당신은 회의록 작성 보조 AI입니다. 전문용어를 회의 맥락에 맞춰 설명해주세요.",
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "회의 내용: {meeting_transcript}\n\n발견된 용어: {term}\n\n관련 문서:\n{rag_context}\n\n위 용어를 회의 맥락에 맞춰 2-3문장으로 설명해주세요."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"response": {
|
|
"id": "msg_...",
|
|
"type": "message",
|
|
"role": "assistant",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "API Gateway는 클라이언트와 백엔드 서비스 사이의 단일 진입점으로..."
|
|
}
|
|
],
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"stop_reason": "end_turn",
|
|
"usage": {
|
|
"input_tokens": 450,
|
|
"output_tokens": 120
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 준호 (Backend Developer)
|
|
**데이터 아키텍처 및 API 설계**를 제안합니다:
|
|
|
|
**1. 데이터 소스별 수집 전략**
|
|
```
|
|
조직 문서:
|
|
├── Confluence API (주간 배치)
|
|
├── SharePoint Graph API (주간 배치)
|
|
├── Google Drive API (주간 배치)
|
|
└── 수동 업로드 (관리자 페이지)
|
|
|
|
외부 문서:
|
|
├── GitHub 기술문서 크롤링 (월간 배치)
|
|
├── 공개 API 문서 (Swagger/OpenAPI)
|
|
└── 산업 표준 용어집 (수동 큐레이션)
|
|
```
|
|
|
|
**2. 데이터베이스 스키마**
|
|
```sql
|
|
-- 용어 마스터 테이블
|
|
CREATE TABLE terms (
|
|
term_id UUID PRIMARY KEY,
|
|
term_name VARCHAR(200) NOT NULL,
|
|
normalized_name VARCHAR(200) NOT NULL,
|
|
category VARCHAR(50),
|
|
source_type VARCHAR(20), -- 'internal', 'external'
|
|
definition TEXT,
|
|
context TEXT,
|
|
confidence_score DECIMAL(3,2),
|
|
created_at TIMESTAMP,
|
|
updated_at TIMESTAMP,
|
|
INDEX idx_normalized (normalized_name),
|
|
INDEX idx_category (category)
|
|
);
|
|
|
|
-- 용어-문서 매핑 테이블
|
|
CREATE TABLE term_documents (
|
|
mapping_id UUID PRIMARY KEY,
|
|
term_id UUID REFERENCES terms(term_id),
|
|
document_id UUID,
|
|
relevance_score DECIMAL(3,2),
|
|
excerpt TEXT,
|
|
created_at TIMESTAMP
|
|
);
|
|
|
|
-- 벡터 인덱스 메타데이터
|
|
CREATE TABLE term_vectors (
|
|
vector_id UUID PRIMARY KEY,
|
|
term_id UUID REFERENCES terms(term_id),
|
|
embedding_model VARCHAR(50),
|
|
vector_store_key VARCHAR(200),
|
|
created_at TIMESTAMP
|
|
);
|
|
```
|
|
|
|
**3. REST API 엔드포인트**
|
|
```
|
|
POST /api/v1/terms/extract
|
|
- 회의 전사 텍스트에서 용어 추출
|
|
- Request: { "transcript": "...", "meeting_id": "..." }
|
|
- Response: { "terms": [...], "extraction_time_ms": 1234 }
|
|
|
|
GET /api/v1/terms/{term_id}/context
|
|
- 특정 용어의 맥락 정보 조회
|
|
- Query params: meeting_context, max_results
|
|
- Response: { "term": {...}, "related_docs": [...], "ai_explanation": "..." }
|
|
|
|
POST /api/v1/terms/search
|
|
- 벡터 유사도 검색
|
|
- Request: { "query": "...", "filters": {...}, "top_k": 5 }
|
|
- Response: { "results": [...], "search_time_ms": 234 }
|
|
```
|
|
|
|
**4. 성능 최적화**
|
|
- Redis 캐싱: 자주 조회되는 용어 (TTL 1시간)
|
|
- CDN 캐싱: 외부 기술 문서 용어 (TTL 24시간)
|
|
- 배치 처리: 야간 시간대 벡터 업데이트
|
|
|
|
### 동욱 (Backend Developer)
|
|
**실용적인 구현 전략**을 제안합니다:
|
|
|
|
**Phase 1: MVP (4주)**
|
|
- JSON 파일 기반 용어 사전 (terms-dictionary.json)
|
|
- 수동 큐레이션 50개 핵심 용어
|
|
- Claude API 직접 호출 (RAG 없이 프롬프트 기반)
|
|
- 간단한 키워드 매칭
|
|
|
|
**Phase 2: 기본 RAG (4주)**
|
|
- PostgreSQL + pgvector 확장
|
|
- 조직 문서 100개 수집/임베딩
|
|
- 기본 벡터 검색 구현
|
|
- Claude API + RAG context 연동
|
|
|
|
**Phase 3: 고도화 (8주)**
|
|
- Pinecone 또는 Qdrant 도입
|
|
- 자동 수집 파이프라인 구축
|
|
- 하이브리드 검색 (키워드 + 벡터)
|
|
- 피드백 루프 및 품질 개선
|
|
|
|
**인프라 구성**:
|
|
```yaml
|
|
services:
|
|
term-extraction:
|
|
- NLP 서버 (Python FastAPI)
|
|
- spaCy, transformers 라이브러리
|
|
- 배치 작업용 Celery worker
|
|
|
|
vector-search:
|
|
- Qdrant (self-hosted) 또는 Pinecone (managed)
|
|
- API Gateway 통합
|
|
|
|
claude-api-proxy:
|
|
- Rate limiting (100 req/min)
|
|
- Response caching (Redis)
|
|
- Error handling & retry logic
|
|
```
|
|
|
|
### 유진 (Frontend Developer)
|
|
**사용자 경험 관점**에서 고려사항:
|
|
|
|
1. **실시간 용어 감지 UI**
|
|
- STT 텍스트 스트리밍 중 용어 하이라이트
|
|
- 1초 이내 반응 속도 보장
|
|
- 로딩 스피너 대신 skeleton UI
|
|
|
|
2. **용어 설명 모달**
|
|
- 빠른 프리뷰: 2-3줄 요약
|
|
- 상세보기 확장: 관련 문서 링크
|
|
- 즐겨찾기 기능
|
|
|
|
3. **성능 최적화**
|
|
- 용어 데이터 prefetch (회의 시작 시)
|
|
- 자주 사용되는 용어 로컬 캐싱
|
|
- Debouncing으로 API 호출 최소화
|
|
|
|
### 길동 (Architect)
|
|
**전체 시스템 아키텍처**를 제안합니다:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Client (Web/Mobile) │
|
|
└────────────────────┬────────────────────────────────────┘
|
|
│
|
|
┌────────────────────▼────────────────────────────────────┐
|
|
│ API Gateway │
|
|
│ (Rate Limiting, Auth, Routing) │
|
|
└────────┬──────────────────────────┬─────────────────────┘
|
|
│ │
|
|
┌────────▼────────┐ ┌─────────▼──────────┐
|
|
│ Meeting Service│ │ AI Service │
|
|
│ - 회의 진행 │ │ - 용어 추출 │
|
|
│ - STT 연동 │ │ - RAG 검색 │
|
|
│ - 실시간 협업 │ │ - Claude API 연동 │
|
|
└────────┬────────┘ └─────────┬──────────┘
|
|
│ │
|
|
│ ┌──────────▼───────────┐
|
|
│ │ Vector Store │
|
|
│ │ (Qdrant/Pinecone) │
|
|
│ └──────────────────────┘
|
|
│
|
|
┌────────▼─────────────────────────────────────┐
|
|
│ PostgreSQL │
|
|
│ - 회의/회의록 데이터 │
|
|
│ - 용어 마스터 데이터 │
|
|
│ - 메타데이터 (pgvector 확장) │
|
|
└───────────────────────────────────────────────┘
|
|
|
|
┌──────────────────────────────────────────────┐
|
|
│ Data Pipeline (배치 처리) │
|
|
│ 1. 문서 수집 (Confluence, SharePoint, etc) │
|
|
│ 2. 용어 추출 & 정제 │
|
|
│ 3. 벡터 임베딩 & 저장 │
|
|
│ 4. 품질 검증 (Human-in-the-loop) │
|
|
└──────────────────────────────────────────────┘
|
|
```
|
|
|
|
**주요 아키텍처 결정**:
|
|
1. **벡터 DB 선택**: Qdrant (자체 호스팅) - 비용 절감, 커스터마이징 용이
|
|
2. **임베딩 모델**: OpenAI text-embedding-3-large - 다국어 지원, 높은 정확도
|
|
3. **캐싱 전략**: 3-tier (Browser → Redis → Vector DB)
|
|
4. **확장성**: 마이크로서비스 분리로 독립적 스케일링 가능
|
|
|
|
### 도현 (QA Engineer)
|
|
**품질 보증 관점**:
|
|
|
|
1. **데이터 품질 검증**
|
|
- 용어 추출 정확도: 85% 이상
|
|
- 용어 설명 적합성: 사용자 피드백 4.0/5.0 이상
|
|
- False positive rate: 10% 이하
|
|
|
|
2. **성능 테스트 기준**
|
|
- 용어 추출: 1000자 텍스트 기준 < 2초
|
|
- RAG 검색: < 500ms
|
|
- Claude API 응답: < 3초
|
|
- 동시 사용자 100명 부하 테스트
|
|
|
|
3. **테스트 시나리오**
|
|
- 다양한 도메인 용어 (IT, 비즈니스, 법률, 의료)
|
|
- 약어 및 동음이의어 처리
|
|
- 긴 문맥에서의 용어 추출
|
|
- 오프라인/저속 네트워크 환경
|
|
|
|
### 도그냥 (서비스 기획자)
|
|
**사용자 시나리오 중심 접근**:
|
|
|
|
**핵심 사용 케이스**:
|
|
1. **신입 직원**: 회의 중 모르는 약어 실시간 확인
|
|
2. **PM**: 타부서 회의 참석 시 전문용어 이해
|
|
3. **경영진**: 기술 용어를 비즈니스 맥락으로 이해
|
|
|
|
**차별화 요소**:
|
|
- 단순 사전이 아닌 "이 회의에서의 의미" 제공
|
|
- 과거 회의록 맥락 자동 연결
|
|
- 개인화된 용어 학습 이력
|
|
|
|
**MVP 검증 지표**:
|
|
- 용어 설명 조회율: 회의당 평균 3회 이상
|
|
- 도움됨 비율: 80% 이상
|
|
- 재사용률: 동일 용어 2회 이상 조회 50%
|
|
|
|
### 주영 (DevOps)
|
|
**운영 관점 인프라 설계**:
|
|
|
|
**CI/CD 파이프라인**:
|
|
```yaml
|
|
data-pipeline:
|
|
schedule: "0 2 * * *" # 매일 새벽 2시
|
|
stages:
|
|
- collect-documents
|
|
- extract-terms
|
|
- generate-embeddings
|
|
- update-vector-store
|
|
- quality-check
|
|
|
|
monitoring:
|
|
- Prometheus metrics
|
|
- Grafana dashboard
|
|
- Alert on failure
|
|
```
|
|
|
|
**벡터 DB 배포**:
|
|
```yaml
|
|
qdrant:
|
|
deployment:
|
|
replicas: 3
|
|
resources:
|
|
cpu: 2
|
|
memory: 4Gi
|
|
storage: 100Gi SSD
|
|
|
|
backup:
|
|
schedule: daily
|
|
retention: 30 days
|
|
|
|
monitoring:
|
|
metrics:
|
|
- query_latency_p95
|
|
- index_size
|
|
- memory_usage
|
|
```
|
|
|
|
**비용 최적화**:
|
|
- Spot instances for 배치 작업
|
|
- Auto-scaling for API 서버
|
|
- CloudFront CDN for 정적 용어 사전
|
|
|
|
### 현정 (콘텐츠 기획자)
|
|
**콘텐츠 품질 관점**:
|
|
|
|
1. **용어 분류 체계**
|
|
```
|
|
기술 용어
|
|
├── 아키텍처 (API Gateway, Microservice, ...)
|
|
├── 프로그래밍 (REST, JWT, ...)
|
|
└── 인프라 (Kubernetes, Docker, ...)
|
|
|
|
비즈니스 용어
|
|
├── 전략 (MVP, PMF, ...)
|
|
├── 마케팅 (CAC, LTV, ...)
|
|
└── 재무 (ARR, MRR, ...)
|
|
|
|
조직 내부 용어
|
|
├── 프로젝트명
|
|
├── 팀/부서명
|
|
└── 내부 프로세스
|
|
```
|
|
|
|
2. **설명 작성 가이드**
|
|
- 1문장: 핵심 정의
|
|
- 2문장: 회의 맥락
|
|
- 3문장: 관련 정보/링크
|
|
|
|
3. **데이터 큐레이션 프로세스**
|
|
- 주간 신규 용어 리뷰
|
|
- 월간 품질 감사
|
|
- 분기별 카테고리 재정비
|
|
|
|
### 지수 (Product Designer)
|
|
**UX/UI 디자인 관점**:
|
|
|
|
**용어 표시 디자인 시스템**:
|
|
```
|
|
용어 배지 스타일:
|
|
- 조직 용어: ⭐ 골드 배지
|
|
- 기술 용어: 🔧 블루 배지
|
|
- 비즈니스 용어: 💼 그린 배지
|
|
|
|
인터랙션:
|
|
- Hover: 1줄 미리보기 툴팁
|
|
- Click: 상세 설명 모달 (슬라이드업)
|
|
- Long press (모바일): 빠른 설명 팝업
|
|
|
|
접근성:
|
|
- 키보드 네비게이션 지원
|
|
- Screen reader 호환
|
|
- High contrast mode 지원
|
|
```
|
|
|
|
**모바일 최적화**:
|
|
- 스와이프로 용어 사전 열기
|
|
- 음성으로 용어 질문 (STT 연동)
|
|
- 오프라인 캐싱 (자주 사용 50개 용어)
|
|
|
|
---
|
|
|
|
## 2단계: 의견 종합 및 중복 제거
|
|
|
|
### A. 데이터 수집 전략
|
|
1. **초기(MVP)**: 수동 큐레이션 50-100개 핵심 조직 용어
|
|
2. **자동화**: Confluence, SharePoint, Google Drive API 배치 수집
|
|
3. **외부 소스**: GitHub 기술문서, 공개 API 문서, 산업 표준 용어집
|
|
|
|
### B. 용어 추출 및 정제
|
|
1. **추출 방법**: NER, TF-IDF, Claude API 활용 맥락 추출
|
|
2. **정제 프로세스**: 중복 제거(Fuzzy matching), 품질 검증(HITL), 메타데이터 태깅
|
|
3. **분류 체계**: 기술/비즈니스/조직 내부 용어 3대 카테고리
|
|
|
|
### C. 벡터라이징 및 저장
|
|
1. **임베딩 모델**: OpenAI text-embedding-3-large (다국어, 고정확도)
|
|
2. **벡터 DB**: Qdrant (자체 호스팅, 비용 효율적)
|
|
3. **청크 전략**: 용어 정의 256토큰, 문맥 512토큰(128 오버랩)
|
|
|
|
### D. Claude API 연동
|
|
1. **모델**: claude-sonnet-4-5-20250929
|
|
2. **프롬프트 구조**: System message + 회의 전사 + 용어 + RAG context
|
|
3. **최적화**: Rate limiting, Response caching(Redis), Error handling
|
|
|
|
### E. 시스템 아키텍처
|
|
1. **마이크로서비스 구성**: Meeting Service, AI Service 분리
|
|
2. **데이터베이스**: PostgreSQL(메인) + pgvector + Qdrant(벡터)
|
|
3. **캐싱 전략**: 3-tier (Browser → Redis → Vector DB)
|
|
|
|
### F. 성능 및 품질 목표
|
|
1. **응답 시간**: 용어 추출 <2초, RAG 검색 <500ms, 전체 <3초
|
|
2. **정확도**: 추출 85% 이상, 사용자 만족도 4.0/5.0
|
|
3. **확장성**: 동시 사용자 100명 지원
|
|
|
|
---
|
|
|
|
## 3단계: 최적안 후보 5개 선정
|
|
|
|
### 후보 1: 단계적 MVP 접근 (Lean Startup)
|
|
**특징**:
|
|
- Phase 1(4주): JSON 기반 수동 큐레이션 50개 용어
|
|
- Phase 2(4주): PostgreSQL + pgvector, 100개 문서
|
|
- Phase 3(8주): Qdrant 도입, 자동 파이프라인
|
|
|
|
**장점**:
|
|
- 빠른 시장 검증
|
|
- 초기 비용 최소화
|
|
- 점진적 학습 및 개선
|
|
|
|
**단점**:
|
|
- 초기 기능 제한적
|
|
- 기술 부채 발생 가능
|
|
- 3번의 마이그레이션 필요
|
|
|
|
**비용**: $5K (Phase 1) → $20K (Phase 2) → $50K (Phase 3)
|
|
|
|
---
|
|
|
|
### 후보 2: 하이브리드 RAG 시스템 (균형형)
|
|
**특징**:
|
|
- 조직 용어: JSON 사전 (관리자 큐레이션)
|
|
- 외부 용어: RAG 시스템 (Qdrant + OpenAI embedding)
|
|
- Claude API 통합: 맥락 기반 설명 생성
|
|
|
|
**장점**:
|
|
- 정확도와 확장성 균형
|
|
- 조직 용어 품질 보장
|
|
- 외부 용어 자동 업데이트
|
|
|
|
**단점**:
|
|
- 이원화된 시스템 관리
|
|
- 동기화 복잡성
|
|
- 중간 수준 개발 비용
|
|
|
|
**비용**: $35K (초기 구축) + $5K/월 (운영)
|
|
|
|
---
|
|
|
|
### 후보 3: Full RAG 시스템 (최대 자동화)
|
|
**특징**:
|
|
- 모든 용어 자동 추출 및 RAG 검색
|
|
- Pinecone 관리형 서비스 사용
|
|
- 실시간 문서 크롤링 및 업데이트
|
|
- 자동 품질 검증 (ML 모델)
|
|
|
|
**장점**:
|
|
- 최대 확장성
|
|
- 관리 오버헤드 최소
|
|
- 최신 정보 자동 반영
|
|
|
|
**단점**:
|
|
- 초기 구축 비용 높음
|
|
- 조직 특화 용어 정확도 낮을 수 있음
|
|
- 운영 비용 지속 발생
|
|
|
|
**비용**: $80K (초기 구축) + $12K/월 (Pinecone + API)
|
|
|
|
---
|
|
|
|
### 후보 4: 커뮤니티 큐레이션 모델
|
|
**특징**:
|
|
- 사용자가 용어 추가/수정 제안
|
|
- AI가 제안 검증 및 자동 반영
|
|
- 크라우드소싱 기반 품질 관리
|
|
- Wikipedia 스타일 버전 관리
|
|
|
|
**장점**:
|
|
- 조직 맞춤 용어 자연 축적
|
|
- 사용자 참여도 향상
|
|
- 지속적인 품질 개선
|
|
|
|
**단점**:
|
|
- 초기 콘텐츠 부족
|
|
- 품질 관리 복잡
|
|
- 악의적 편집 방지 필요
|
|
|
|
**비용**: $30K (초기) + $3K/월 (모더레이션)
|
|
|
|
---
|
|
|
|
### 후보 5: LLM 직접 활용 (RAG-less)
|
|
**특징**:
|
|
- RAG 없이 Claude API에 전체 문서 임베딩 전달
|
|
- Claude의 장문 처리 능력 활용 (200K tokens)
|
|
- 실시간 맥락 생성, 별도 벡터 DB 불필요
|
|
|
|
**장점**:
|
|
- 아키텍처 단순화
|
|
- 개발 기간 단축 (4주)
|
|
- 인프라 비용 최소
|
|
|
|
**단점**:
|
|
- API 호출 비용 높음 (토큰당 과금)
|
|
- 응답 속도 느림 (5-10초)
|
|
- 확장성 제한 (회의 수 증가 시)
|
|
|
|
**비용**: $15K (초기) + $8K/월 (Claude API)
|
|
|
|
---
|
|
|
|
## 4단계: 각 최적안 후보 평가
|
|
|
|
### 평가 기준 (가중치)
|
|
1. **비즈니스 가치** (30%): 차별화, 사용자 만족도, ROI
|
|
2. **기술적 실현 가능성** (25%): 개발 난이도, 리스크, 일정
|
|
3. **확장성** (20%): 사용자/데이터 증가 대응
|
|
4. **비용 효율성** (15%): 초기 투자, 운영 비용
|
|
5. **유지보수성** (10%): 관리 복잡도, 기술 부채
|
|
|
|
### 후보 1 평가: 단계적 MVP 접근
|
|
| 평가 기준 | 점수 | 세부 평가 |
|
|
|---------|------|---------|
|
|
| 비즈니스 가치 | 7/10 | 빠른 검증 가능, 초기 기능 제한 |
|
|
| 기술적 실현 가능성 | 9/10 | 단계별 구현, 리스크 분산 |
|
|
| 확장성 | 6/10 | Phase 3 이후 확장 가능 |
|
|
| 비용 효율성 | 9/10 | 최소 초기 투자 |
|
|
| 유지보수성 | 7/10 | 마이그레이션 필요, 기술 부채 |
|
|
| **총점** | **7.6/10** | **실용적, 리스크 최소** |
|
|
|
|
**종합 의견**:
|
|
- **민준**: 비즈니스 검증에 최적. MVP 철학에 부합.
|
|
- **동욱**: 실무적으로 가장 현실적. 팀 역량 고려 시 추천.
|
|
- **도현**: 단계별 테스트 가능, 품질 관리 용이.
|
|
|
|
---
|
|
|
|
### 후보 2 평가: 하이브리드 RAG 시스템
|
|
| 평가 기준 | 점수 | 세부 평가 |
|
|
|---------|------|---------|
|
|
| 비즈니스 가치 | 9/10 | 조직 용어 품질 + 확장성 균형 |
|
|
| 기술적 실현 가능성 | 7/10 | 이원화 시스템 복잡도 |
|
|
| 확장성 | 8/10 | 외부 용어 자동 확장 |
|
|
| 비용 효율성 | 7/10 | 중간 수준 비용 |
|
|
| 유지보수성 | 6/10 | 두 시스템 동기화 필요 |
|
|
| **총점** | **7.7/10** | **균형잡힌 솔루션** |
|
|
|
|
**종합 의견**:
|
|
- **서연**: 기술적으로 가장 합리적. RAG의 장점 활용.
|
|
- **준호**: API 설계 명확, 확장 경로 분명.
|
|
- **길동**: 아키텍처 관점에서 장기적으로 유지 가능.
|
|
|
|
---
|
|
|
|
### 후보 3 평가: Full RAG 시스템
|
|
| 평가 기준 | 점수 | 세부 평가 |
|
|
|---------|------|---------|
|
|
| 비즈니스 가치 | 8/10 | 최대 확장성, 높은 비용 |
|
|
| 기술적 실현 가능성 | 6/10 | 복잡도 높음, 개발 기간 길어짐 |
|
|
| 확장성 | 10/10 | 무제한 확장 가능 |
|
|
| 비용 효율성 | 4/10 | 높은 초기/운영 비용 |
|
|
| 유지보수성 | 8/10 | 관리형 서비스로 간소화 |
|
|
| **총점** | **7.0/10** | **오버엔지니어링 리스크** |
|
|
|
|
**종합 의견**:
|
|
- **민준**: 초기 스타트업에 과도한 투자.
|
|
- **주영**: 운영 비용 부담, 단계적 접근 권장.
|
|
- **도그냥**: 사용자 검증 전 과한 투자.
|
|
|
|
---
|
|
|
|
### 후보 4 평가: 커뮤니티 큐레이션 모델
|
|
| 평가 기준 | 점수 | 세부 평가 |
|
|
|---------|------|---------|
|
|
| 비즈니스 가치 | 7/10 | 사용자 참여 높으나 초기 부족 |
|
|
| 기술적 실현 가능성 | 6/10 | 모더레이션 시스템 복잡 |
|
|
| 확장성 | 8/10 | 자연스러운 콘텐츠 성장 |
|
|
| 비용 효율성 | 8/10 | 중간 비용, 모더레이션 필요 |
|
|
| 유지보수성 | 5/10 | 품질 관리 지속 필요 |
|
|
| **총점** | **6.9/10** | **차별화되나 리스크 있음** |
|
|
|
|
**종합 의견**:
|
|
- **도그냥**: 장기적으로 차별화 포인트, MVP에는 부적합.
|
|
- **현정**: 콘텐츠 품질 관리 어려움.
|
|
- **지수**: UX는 흥미롭지만 초기 경험 부족.
|
|
|
|
---
|
|
|
|
### 후보 5 평가: LLM 직접 활용
|
|
| 평가 기준 | 점수 | 세부 평가 |
|
|
|---------|------|---------|
|
|
| 비즈니스 가치 | 6/10 | 빠른 구현, 성능 이슈 |
|
|
| 기술적 실현 가능성 | 8/10 | 단순 구조, 쉬운 구현 |
|
|
| 확장성 | 4/10 | API 비용 및 속도 문제 |
|
|
| 비용 효율성 | 5/10 | 낮은 초기, 높은 운영 비용 |
|
|
| 유지보수성 | 9/10 | 매우 단순한 구조 |
|
|
| **총점** | **6.1/10** | **단기 솔루션, 확장 제한** |
|
|
|
|
**종합 의견**:
|
|
- **서연**: 기술적으로 단순하나 성능 문제 예상.
|
|
- **준호**: 확장 시 비용 폭발 가능성.
|
|
- **도현**: 3초 응답 시간은 UX에 부정적.
|
|
|
|
---
|
|
|
|
## 5단계: 최적안 선정 (1차)
|
|
|
|
**선정 결과**: **후보 2 - 하이브리드 RAG 시스템** (7.7/10)
|
|
|
|
**선정 이유**:
|
|
1. 조직 특화 용어의 높은 정확도 보장 (JSON 큐레이션)
|
|
2. 외부 용어의 확장성 확보 (RAG 시스템)
|
|
3. 합리적인 비용 구조 ($35K 초기 + $5K/월)
|
|
4. 명확한 아키텍처, 유지보수 가능
|
|
5. 차별화 포인트 구현 가능
|
|
|
|
---
|
|
|
|
## 반복 2-10: 개선 및 최종 선정
|
|
|
|
### 반복 2: 하이브리드 모델 개선안
|
|
|
|
**개선 포인트**:
|
|
- Phase 1에서 JSON 사전으로 시작 (후보 1의 장점)
|
|
- Phase 2에서 RAG 추가 (점진적 확장)
|
|
- 비용 최적화: pgvector 우선 사용 → Qdrant는 필요 시 전환
|
|
|
|
**개선된 점수**: 8.0/10
|
|
|
|
---
|
|
|
|
### 반복 3-9: 세부 조정
|
|
(각 반복마다 팀원들의 피드백을 반영하여 아키텍처 미세 조정)
|
|
|
|
---
|
|
|
|
### 반복 10: 최종 최적안
|
|
|
|
**최종 선정**: **하이브리드 RAG 시스템 (개선안)**
|
|
|
|
**최종 아키텍처**:
|
|
|
|
```
|
|
Phase 1 (MVP - 4주):
|
|
├── JSON 기반 용어 사전 (50개 핵심 조직 용어)
|
|
├── Claude API 직접 연동
|
|
├── 간단한 키워드 매칭
|
|
└── 수동 큐레이션 프로세스
|
|
|
|
Phase 2 (기본 RAG - 6주):
|
|
├── PostgreSQL + pgvector 확장
|
|
├── 조직 문서 100개 임베딩
|
|
├── OpenAI text-embedding-3-small 사용 (비용 절감)
|
|
├── 기본 벡터 검색 + Claude API 연동
|
|
└── 자동 배치 수집 파이프라인
|
|
|
|
Phase 3 (고도화 - 8주):
|
|
├── Qdrant 도입 (성능 개선)
|
|
├── 하이브리드 검색 (키워드 + 벡터)
|
|
├── 자동 품질 검증 시스템
|
|
├── 사용자 피드백 루프
|
|
└── 외부 문서 자동 크롤링
|
|
```
|
|
|
|
---
|
|
|
|
## 6단계: Architectural Decision Records (ADR)
|
|
|
|
### ADR-001: 벡터 데이터베이스 선택
|
|
|
|
**결정**: Phase 1-2는 PostgreSQL + pgvector, Phase 3에서 Qdrant로 전환
|
|
|
|
**컨텍스트**:
|
|
- 초기에는 데이터량이 적어 pgvector로 충분
|
|
- 관련회의록 기능은 Azure AI Search 사용 (별도 독립)
|
|
- 용어집은 정확한 키워드 매칭이 중요하여 PostgreSQL 적합
|
|
- 단계적 접근으로 리스크 분산
|
|
|
|
**대안 고려**:
|
|
1. **PostgreSQL+pgvector** ✅:
|
|
- 기존 DB 활용, 트랜잭션 보장, 학습 곡선 낮음
|
|
- 소규모에 적합, 비용 $0 (기존 DB)
|
|
|
|
2. **Azure AI Search (초기 도입)**:
|
|
- 고성능 검색, Semantic Ranking, 관리형 서비스
|
|
- 소규모에 과도, 비용 $250/월
|
|
|
|
3. **Qdrant (self-hosted)**:
|
|
- 전문 Vector DB, 고성능, 오픈소스
|
|
- 운영 부담, 학습 곡선 높음, 비용 $500/월
|
|
|
|
4. **Pinecone (managed)**:
|
|
- 관리형 서비스, 쉬운 사용, 고성능
|
|
- 비용 높음 ($70-200/월), 한국어 지원 부족
|
|
|
|
**결정 근거**:
|
|
- **Phase 1-2**: pgvector의 단순성 및 비용 효율성 우선
|
|
- **Phase 3 조건**: 용어 500개 이상 OR 성능 이슈 OR 관리 복잡도 증가
|
|
- **Phase 3 옵션 A**: Azure AI Search (terms-index) 마이그레이션 ($250/월 추가 비용 없음, 관련회의록과 공유)
|
|
- **Phase 3 옵션 B**: 현상 유지 (독립 운영)
|
|
- **비용 효율성**: pgvector 무료 vs Azure AI Search 통합시 $0 추가 vs Qdrant $500/월
|
|
|
|
**결과**:
|
|
- 초기 인프라 비용 절감 (PostgreSQL 활용)
|
|
- 검증된 기술 스택 사용으로 팀 학습 부담 감소
|
|
- 관련회의록과 독립적으로 운영하여 장애 격리
|
|
- Phase 4에서 조건 충족시 Azure AI Search 통합 옵션 보유
|
|
|
|
---
|
|
|
|
### ADR-002: 임베딩 모델 선택
|
|
|
|
**결정**: OpenAI text-embedding-3-small (Phase 1-2), text-embedding-3-large (Phase 3)
|
|
|
|
**컨텍스트**:
|
|
- 한국어/영어 혼용 문서 처리 필요
|
|
- 비용과 성능의 균형 필요
|
|
- 임베딩 차원수와 정확도 트레이드오프
|
|
|
|
**대안 고려**:
|
|
1. **OpenAI text-embedding-3-small**:
|
|
- 1536 차원, $0.02/1M tokens
|
|
- 적절한 정확도, 낮은 비용
|
|
|
|
2. **OpenAI text-embedding-3-large**:
|
|
- 3072 차원, $0.13/1M tokens
|
|
- 최고 정확도, 높은 비용
|
|
|
|
3. **Cohere embed-multilingual-v3.0**:
|
|
- 1024 차원, $0.10/1M tokens
|
|
- 다국어 특화, 중간 비용
|
|
|
|
**결정 근거**:
|
|
- Phase 1-2: small 모델로 MVP 검증 (월 1,000,000 토큰 = $20)
|
|
- Phase 3: 사용자 피드백 기반으로 large 모델 전환 고려
|
|
- OpenAI 에코시스템 통일 (Claude 대안으로 GPT 활용 가능)
|
|
|
|
**결과**:
|
|
- 초기 월 $20-50 임베딩 비용
|
|
- 필요 시 모델 업그레이드 가능한 구조
|
|
- 다국어 지원 검증 필요 (한국어 테스트)
|
|
|
|
---
|
|
|
|
### ADR-003: 용어 수집 전략
|
|
|
|
**결정**: 수동 큐레이션 (Phase 1) → 반자동 (Phase 2) → 자동 (Phase 3)
|
|
|
|
**Phase 1 - 수동 큐레이션**:
|
|
```json
|
|
{
|
|
"terms": [
|
|
{
|
|
"id": "term-001",
|
|
"name": "API Gateway",
|
|
"category": "기술-아키텍처",
|
|
"definition": "클라이언트와 백엔드 서비스 사이의 단일 진입점",
|
|
"context": "우리 시스템에서는 AWS API Gateway를 사용하여...",
|
|
"synonyms": ["게이트웨이", "API 게이트웨이"],
|
|
"source": "internal",
|
|
"confidence": 1.0,
|
|
"created_at": "2025-01-15",
|
|
"updated_at": "2025-01-15"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Phase 2 - 반자동 수집**:
|
|
```python
|
|
# 배치 수집 스크립트
|
|
def collect_documents():
|
|
sources = [
|
|
ConfluenceAPI(url="...", token="..."),
|
|
SharePointAPI(site_url="...", token="..."),
|
|
GoogleDriveAPI(folder_id="...", token="...")
|
|
]
|
|
|
|
for source in sources:
|
|
documents = source.fetch_recent_documents(days=7)
|
|
for doc in documents:
|
|
terms = extract_terms(doc.content)
|
|
# 관리자 승인 대기열에 추가
|
|
await add_to_approval_queue(terms)
|
|
```
|
|
|
|
**Phase 3 - 자동 수집**:
|
|
- ML 기반 자동 승인 (신뢰도 > 0.9)
|
|
- 주간 배치로 신규 용어 자동 추가
|
|
- 품질 모니터링 대시보드
|
|
|
|
**결정 근거**:
|
|
- 초기 품질 보장 (수동 검증)
|
|
- 점진적 자동화로 관리 부담 감소
|
|
- 조직 특화 용어의 정확도 우선
|
|
|
|
---
|
|
|
|
### ADR-004: Claude API 연동 구조
|
|
|
|
**결정**: RAG context + Structured prompt
|
|
|
|
**API 요청 구조**:
|
|
```json
|
|
{
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"max_tokens": 1024,
|
|
"temperature": 0.3,
|
|
"system": "당신은 전문 용어를 회의 맥락에 맞춰 설명하는 AI 어시스턴트입니다. 2-3문장으로 간결하게 설명하세요.",
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "=== 회의 정보 ===\n회의 제목: API 설계 리뷰\n참석자: 김민준(PO), 이준호(BE), 박서연(AI)\n시간: 2025-01-15 14:00\n\n=== 회의 내용 (STT 전사) ===\n민준: 이번 프로젝트에서 API Gateway를 도입하려고 하는데...\n준호: REST API 설계는 이미 완료했고, 인증은 JWT로...\n서연: AI 서비스와의 연동은 비동기로 처리하면...\n\n=== 관련 문서 (RAG 검색 결과) ===\n[문서 1] API Gateway 설계 가이드 (2024-12-01)\n- API Gateway는 마이크로서비스 아키텍처에서 단일 진입점 역할\n- 요청 라우팅, 인증/인가, Rate limiting 기능 제공\n- AWS API Gateway 사용 시 Lambda 통합 가능\n\n[문서 2] 사내 기술 스택 표준 (2024-11-15)\n- API Gateway: AWS API Gateway 권장\n- 인증: JWT 토큰 기반 (만료 시간 1시간)\n\n=== 질문 ===\n용어: API Gateway\n\n위 회의 맥락에 맞춰 'API Gateway'를 2-3문장으로 설명해주세요."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**응답 처리**:
|
|
```json
|
|
{
|
|
"id": "msg_01ABC...",
|
|
"type": "message",
|
|
"role": "assistant",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "API Gateway는 클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점으로, 요청 라우팅, 인증, Rate limiting을 담당합니다. 이 회의에서는 AWS API Gateway 도입을 논의하고 있으며, JWT 기반 인증과 Lambda 통합을 통해 AI 서비스를 비동기로 연동하려는 계획입니다. 사내 기술 스택 표준에 따라 AWS API Gateway 사용이 권장됩니다."
|
|
}
|
|
],
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"usage": {
|
|
"input_tokens": 523,
|
|
"output_tokens": 87
|
|
}
|
|
}
|
|
```
|
|
|
|
**최적화 전략**:
|
|
1. **캐싱**: Redis에 (용어 + 회의 맥락 해시) → 설명 저장 (TTL 24시간)
|
|
2. **Rate limiting**: 사용자당 분당 10회, 회의당 시간당 100회
|
|
3. **Fallback**: API 실패 시 RAG 문서 직접 반환
|
|
4. **비용 관리**: 월 예산 $500 초과 시 알림 (input 500K tokens 기준)
|
|
|
|
**결정 근거**:
|
|
- Claude의 장문 이해 능력 활용 (200K tokens)
|
|
- Structured prompt로 일관된 응답 품질
|
|
- RAG context로 정확도 향상
|
|
- 캐싱으로 중복 호출 방지 (비용 절감)
|
|
|
|
---
|
|
|
|
### ADR-005: 데이터베이스 스키마 설계
|
|
|
|
**결정**: 정규화된 관계형 스키마 + JSON 메타데이터
|
|
|
|
**스키마 구조**:
|
|
```sql
|
|
-- 용어 마스터 테이블
|
|
CREATE TABLE terms (
|
|
term_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
term_name VARCHAR(200) NOT NULL,
|
|
normalized_name VARCHAR(200) NOT NULL, -- 소문자, 공백 제거
|
|
category VARCHAR(50), -- '기술-아키텍처', '비즈니스-전략' 등
|
|
source_type VARCHAR(20) CHECK (source_type IN ('internal', 'external')),
|
|
is_company_specific BOOLEAN DEFAULT false,
|
|
|
|
-- 용어 정보
|
|
definition TEXT NOT NULL,
|
|
context TEXT, -- 회사 내 사용 맥락
|
|
synonyms JSONB, -- ["게이트웨이", "API GW"]
|
|
related_terms JSONB, -- [{"term_id": "...", "relation": "related"}]
|
|
|
|
-- 메타데이터
|
|
usage_count INTEGER DEFAULT 0,
|
|
confidence_score DECIMAL(3,2), -- 0.00 ~ 1.00
|
|
last_used_at TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES users(user_id),
|
|
|
|
-- 인덱스
|
|
INDEX idx_normalized_name (normalized_name),
|
|
INDEX idx_category (category),
|
|
INDEX idx_source_type (source_type),
|
|
INDEX idx_usage_count (usage_count DESC),
|
|
UNIQUE INDEX uniq_normalized_name (normalized_name, source_type)
|
|
);
|
|
|
|
-- 용어-문서 매핑 (RAG용)
|
|
CREATE TABLE term_documents (
|
|
mapping_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
term_id UUID REFERENCES terms(term_id) ON DELETE CASCADE,
|
|
|
|
-- 문서 정보
|
|
document_id VARCHAR(200) NOT NULL, -- 외부 시스템 ID (Confluence, SharePoint)
|
|
document_title VARCHAR(500),
|
|
document_url TEXT,
|
|
document_type VARCHAR(50), -- 'confluence', 'sharepoint', 'gdrive'
|
|
|
|
-- 관련성 정보
|
|
relevance_score DECIMAL(3,2), -- 0.00 ~ 1.00
|
|
excerpt TEXT, -- 용어가 등장하는 문맥 (최대 500자)
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
INDEX idx_term_id (term_id),
|
|
INDEX idx_document_id (document_id),
|
|
INDEX idx_relevance_score (relevance_score DESC)
|
|
);
|
|
|
|
-- 벡터 임베딩 메타데이터
|
|
CREATE TABLE term_vectors (
|
|
vector_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
term_id UUID REFERENCES terms(term_id) ON DELETE CASCADE,
|
|
|
|
-- 임베딩 정보
|
|
embedding_model VARCHAR(50), -- 'text-embedding-3-small'
|
|
embedding_dimension INTEGER, -- 1536
|
|
vector_store_type VARCHAR(20), -- 'pgvector', 'qdrant'
|
|
vector_store_key VARCHAR(200), -- 벡터 DB 내 키
|
|
|
|
-- pgvector 사용 시 직접 저장
|
|
embedding vector(1536), -- pgvector 확장 타입
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
INDEX idx_term_id (term_id),
|
|
INDEX idx_embedding_model (embedding_model)
|
|
);
|
|
|
|
-- 용어 사용 이력 (분석용)
|
|
CREATE TABLE term_usage_logs (
|
|
log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
term_id UUID REFERENCES terms(term_id) ON DELETE CASCADE,
|
|
|
|
-- 사용 컨텍스트
|
|
meeting_id UUID REFERENCES meetings(meeting_id),
|
|
user_id UUID REFERENCES users(user_id),
|
|
action VARCHAR(20), -- 'view', 'search', 'feedback'
|
|
|
|
-- 피드백 정보 (선택)
|
|
feedback_rating INTEGER CHECK (feedback_rating BETWEEN 1 AND 5),
|
|
feedback_comment TEXT,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
INDEX idx_term_id_created (term_id, created_at DESC),
|
|
INDEX idx_meeting_id (meeting_id),
|
|
INDEX idx_user_id (user_id)
|
|
);
|
|
```
|
|
|
|
**데이터 예시**:
|
|
```sql
|
|
INSERT INTO terms (term_name, normalized_name, category, source_type, is_company_specific, definition, context, synonyms, confidence_score) VALUES
|
|
(
|
|
'API Gateway',
|
|
'api gateway',
|
|
'기술-아키텍처',
|
|
'internal',
|
|
true,
|
|
'클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점으로, 요청 라우팅, 인증, Rate limiting을 담당합니다.',
|
|
'우리 시스템에서는 AWS API Gateway를 사용하며, Lambda와 통합하여 서버리스 아키텍처를 구현합니다. API 설계 리뷰 회의(2024-09-28)에서 공식 채택되었습니다.',
|
|
'["게이트웨이", "API GW", "에이피아이 게이트웨이"]'::jsonb,
|
|
0.95
|
|
);
|
|
```
|
|
|
|
**결정 근거**:
|
|
- 정규화로 데이터 일관성 보장
|
|
- JSONB로 유연한 메타데이터 저장
|
|
- 인덱스로 검색 성능 최적화
|
|
- 사용 이력 로그로 품질 개선 데이터 확보
|
|
|
|
---
|
|
|
|
### ADR-006: API 엔드포인트 설계
|
|
|
|
**결정**: RESTful API + GraphQL (Phase 3)
|
|
|
|
**Phase 1-2: REST API**
|
|
```
|
|
=== 용어 추출 ===
|
|
POST /api/v1/terms/extract
|
|
Request:
|
|
{
|
|
"meeting_id": "uuid",
|
|
"transcript": "회의 전사 텍스트...",
|
|
"language": "ko",
|
|
"options": {
|
|
"include_external": true,
|
|
"confidence_threshold": 0.7
|
|
}
|
|
}
|
|
|
|
Response:
|
|
{
|
|
"terms": [
|
|
{
|
|
"term_id": "uuid",
|
|
"name": "API Gateway",
|
|
"category": "기술-아키텍처",
|
|
"confidence": 0.95,
|
|
"is_company_specific": true,
|
|
"mention_count": 3,
|
|
"positions": [142, 456, 789]
|
|
}
|
|
],
|
|
"extraction_time_ms": 1234,
|
|
"total_terms": 12
|
|
}
|
|
|
|
=== 용어 설명 조회 ===
|
|
GET /api/v1/terms/{term_id}/explanation
|
|
Query params:
|
|
- meeting_id (optional): 회의 맥락 포함
|
|
- include_rag (optional): RAG 문서 포함 여부
|
|
- max_context_docs (optional): 최대 문서 수 (기본 3)
|
|
|
|
Response:
|
|
{
|
|
"term": {
|
|
"term_id": "uuid",
|
|
"name": "API Gateway",
|
|
"definition": "...",
|
|
"category": "기술-아키텍처",
|
|
"is_company_specific": true
|
|
},
|
|
"explanation": {
|
|
"text": "API Gateway는 클라이언트와 백엔드...",
|
|
"context": "이 회의에서는 AWS API Gateway 도입을...",
|
|
"generated_by": "claude-sonnet-4.5",
|
|
"cached": false
|
|
},
|
|
"related_documents": [
|
|
{
|
|
"title": "API 설계 가이드",
|
|
"url": "https://confluence.../123",
|
|
"relevance_score": 0.92,
|
|
"excerpt": "..."
|
|
}
|
|
],
|
|
"related_terms": [
|
|
{
|
|
"term_id": "uuid",
|
|
"name": "Microservice",
|
|
"relation": "related"
|
|
}
|
|
]
|
|
}
|
|
|
|
=== 용어 검색 (벡터 유사도) ===
|
|
POST /api/v1/terms/search
|
|
Request:
|
|
{
|
|
"query": "서비스 간 통신",
|
|
"filters": {
|
|
"category": ["기술-아키텍처"],
|
|
"source_type": "internal",
|
|
"is_company_specific": true
|
|
},
|
|
"top_k": 5,
|
|
"search_type": "hybrid" // 'keyword', 'vector', 'hybrid'
|
|
}
|
|
|
|
Response:
|
|
{
|
|
"results": [
|
|
{
|
|
"term_id": "uuid",
|
|
"name": "API Gateway",
|
|
"similarity_score": 0.87,
|
|
"definition": "...",
|
|
"relevance_reason": "키워드 매칭 + 벡터 유사도"
|
|
}
|
|
],
|
|
"search_time_ms": 234,
|
|
"total_results": 12
|
|
}
|
|
|
|
=== 용어 피드백 ===
|
|
POST /api/v1/terms/{term_id}/feedback
|
|
Request:
|
|
{
|
|
"meeting_id": "uuid",
|
|
"user_id": "uuid",
|
|
"rating": 5, // 1-5
|
|
"comment": "매우 도움되었습니다",
|
|
"feedback_type": "helpful" // 'helpful', 'inaccurate', 'irrelevant'
|
|
}
|
|
|
|
Response:
|
|
{
|
|
"feedback_id": "uuid",
|
|
"message": "피드백이 등록되었습니다"
|
|
}
|
|
|
|
=== 관리자 API ===
|
|
POST /api/v1/admin/terms
|
|
PUT /api/v1/admin/terms/{term_id}
|
|
DELETE /api/v1/admin/terms/{term_id}
|
|
GET /api/v1/admin/terms/pending // 승인 대기 용어
|
|
POST /api/v1/admin/terms/{term_id}/approve
|
|
```
|
|
|
|
**Phase 3: GraphQL 추가**
|
|
```graphql
|
|
query GetTermWithContext($termId: ID!, $meetingId: ID) {
|
|
term(id: $termId) {
|
|
id
|
|
name
|
|
definition
|
|
category
|
|
isCompanySpecific
|
|
|
|
explanation(meetingId: $meetingId) {
|
|
text
|
|
context
|
|
generatedBy
|
|
cached
|
|
}
|
|
|
|
relatedDocuments(limit: 3) {
|
|
title
|
|
url
|
|
relevanceScore
|
|
excerpt
|
|
}
|
|
|
|
relatedTerms {
|
|
id
|
|
name
|
|
relation
|
|
}
|
|
|
|
usageStats {
|
|
totalViews
|
|
averageRating
|
|
lastUsedAt
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**결정 근거**:
|
|
- REST API: 간단한 CRUD, 캐싱 용이
|
|
- GraphQL: 복잡한 관계 조회, Over-fetching 방지
|
|
- 단계적 도입으로 학습 곡선 완화
|
|
|
|
---
|
|
|
|
## 7단계: 데이터 소스별 수집 전략
|
|
|
|
### 조직 문서 수집
|
|
|
|
**1. Confluence API 연동**
|
|
```python
|
|
from atlassian import Confluence
|
|
|
|
class ConfluenceCollector:
|
|
def __init__(self, url, username, api_token):
|
|
self.confluence = Confluence(
|
|
url=url,
|
|
username=username,
|
|
password=api_token
|
|
)
|
|
|
|
def collect_documents(self, space_key, days=7):
|
|
"""최근 7일간 업데이트된 문서 수집"""
|
|
cql = f'space = {space_key} AND lastModified >= now("-{days}d") ORDER BY lastModified DESC'
|
|
results = self.confluence.cql(cql, limit=100)
|
|
|
|
documents = []
|
|
for page in results['results']:
|
|
doc = {
|
|
'document_id': page['id'],
|
|
'title': page['title'],
|
|
'url': page['_links']['webui'],
|
|
'content': self.confluence.get_page_by_id(page['id'], expand='body.storage')['body']['storage']['value'],
|
|
'updated_at': page['lastModified'],
|
|
'type': 'confluence'
|
|
}
|
|
documents.append(doc)
|
|
|
|
return documents
|
|
|
|
def extract_terms_from_doc(self, document):
|
|
"""문서에서 용어 추출"""
|
|
# HTML 파싱
|
|
soup = BeautifulSoup(document['content'], 'html.parser')
|
|
text = soup.get_text()
|
|
|
|
# NER 기반 용어 추출
|
|
terms = self.ner_extractor.extract(text)
|
|
|
|
# TF-IDF 기반 중요 키워드
|
|
keywords = self.tfidf_extractor.extract(text, top_n=20)
|
|
|
|
# Claude API로 맥락 기반 용어 추출
|
|
claude_terms = self.claude_extractor.extract(text)
|
|
|
|
# 통합 및 중복 제거
|
|
all_terms = self.merge_and_deduplicate(terms, keywords, claude_terms)
|
|
|
|
return all_terms
|
|
```
|
|
|
|
**2. SharePoint Graph API 연동**
|
|
```python
|
|
from microsoft_graph import GraphAPI
|
|
|
|
class SharePointCollector:
|
|
def __init__(self, tenant_id, client_id, client_secret):
|
|
self.graph = GraphAPI(tenant_id, client_id, client_secret)
|
|
|
|
def collect_documents(self, site_id, library_name, days=7):
|
|
"""SharePoint 문서 라이브러리에서 최근 문서 수집"""
|
|
delta_url = f'/sites/{site_id}/drives/{library_name}/root/delta'
|
|
results = self.graph.get(delta_url, params={'$filter': f'lastModifiedDateTime ge {days}daysAgo'})
|
|
|
|
documents = []
|
|
for item in results['value']:
|
|
if item['file']: # 파일인 경우
|
|
content = self.graph.download_file(item['@microsoft.graph.downloadUrl'])
|
|
|
|
doc = {
|
|
'document_id': item['id'],
|
|
'title': item['name'],
|
|
'url': item['webUrl'],
|
|
'content': self.extract_text_from_file(content, item['file']['mimeType']),
|
|
'updated_at': item['lastModifiedDateTime'],
|
|
'type': 'sharepoint'
|
|
}
|
|
documents.append(doc)
|
|
|
|
return documents
|
|
|
|
def extract_text_from_file(self, content, mime_type):
|
|
"""파일 타입에 따라 텍스트 추출"""
|
|
if mime_type == 'application/pdf':
|
|
return self.pdf_extractor.extract(content)
|
|
elif mime_type in ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']:
|
|
return self.docx_extractor.extract(content)
|
|
elif mime_type in ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']:
|
|
return self.excel_extractor.extract(content)
|
|
else:
|
|
return content.decode('utf-8')
|
|
```
|
|
|
|
**3. Google Drive API 연동**
|
|
```python
|
|
from google_drive_api import DriveAPI
|
|
|
|
class GoogleDriveCollector:
|
|
def __init__(self, credentials_file):
|
|
self.drive = DriveAPI(credentials_file)
|
|
|
|
def collect_documents(self, folder_id, days=7):
|
|
"""Google Drive 폴더에서 최근 문서 수집"""
|
|
query = f"'{folder_id}' in parents and modifiedTime > '{days}daysAgo' and mimeType != 'application/vnd.google-apps.folder'"
|
|
results = self.drive.files().list(q=query, pageSize=100).execute()
|
|
|
|
documents = []
|
|
for file in results.get('files', []):
|
|
# Google Docs는 export, 일반 파일은 download
|
|
if file['mimeType'] == 'application/vnd.google-apps.document':
|
|
content = self.drive.export_doc(file['id'], 'text/plain')
|
|
else:
|
|
content = self.drive.download_file(file['id'])
|
|
|
|
doc = {
|
|
'document_id': file['id'],
|
|
'title': file['name'],
|
|
'url': file['webViewLink'],
|
|
'content': content,
|
|
'updated_at': file['modifiedTime'],
|
|
'type': 'google_drive'
|
|
}
|
|
documents.append(doc)
|
|
|
|
return documents
|
|
```
|
|
|
|
**수집 스케줄**:
|
|
```yaml
|
|
# Airflow DAG 예시
|
|
schedule_interval: "0 2 * * *" # 매일 새벽 2시
|
|
|
|
tasks:
|
|
- task_id: collect_confluence
|
|
python_callable: collect_confluence_documents
|
|
retries: 3
|
|
|
|
- task_id: collect_sharepoint
|
|
python_callable: collect_sharepoint_documents
|
|
retries: 3
|
|
|
|
- task_id: collect_google_drive
|
|
python_callable: collect_google_drive_documents
|
|
retries: 3
|
|
|
|
- task_id: extract_terms
|
|
python_callable: extract_terms_from_documents
|
|
depends_on: [collect_confluence, collect_sharepoint, collect_google_drive]
|
|
|
|
- task_id: generate_embeddings
|
|
python_callable: generate_and_store_embeddings
|
|
depends_on: [extract_terms]
|
|
|
|
- task_id: quality_check
|
|
python_callable: validate_term_quality
|
|
depends_on: [generate_embeddings]
|
|
```
|
|
|
|
### 외부 문서 수집
|
|
|
|
**1. GitHub 기술 문서 크롤링**
|
|
```python
|
|
import requests
|
|
from github import Github
|
|
|
|
class GitHubDocCollector:
|
|
def __init__(self, access_token):
|
|
self.github = Github(access_token)
|
|
|
|
def collect_readme_files(self, repo_list):
|
|
"""인기 오픈소스 프로젝트의 README 수집"""
|
|
documents = []
|
|
|
|
for repo_name in repo_list:
|
|
repo = self.github.get_repo(repo_name)
|
|
readme = repo.get_readme()
|
|
|
|
doc = {
|
|
'document_id': f'github-{repo.id}',
|
|
'title': f'{repo.name} README',
|
|
'url': readme.html_url,
|
|
'content': readme.decoded_content.decode('utf-8'),
|
|
'type': 'github',
|
|
'category': 'external-tech'
|
|
}
|
|
documents.append(doc)
|
|
|
|
return documents
|
|
|
|
# 수집 대상 저장소 예시
|
|
TECH_REPOS = [
|
|
'kubernetes/kubernetes',
|
|
'docker/docker',
|
|
'facebook/react',
|
|
'tensorflow/tensorflow',
|
|
'pytorch/pytorch'
|
|
]
|
|
```
|
|
|
|
**2. API 문서 수집 (Swagger/OpenAPI)**
|
|
```python
|
|
class APIDocCollector:
|
|
def collect_swagger_docs(self, swagger_url_list):
|
|
"""공개 API 문서 수집"""
|
|
documents = []
|
|
|
|
for url in swagger_url_list:
|
|
response = requests.get(url)
|
|
swagger_spec = response.json()
|
|
|
|
# Swagger 스펙에서 용어 추출
|
|
terms = self.extract_terms_from_swagger(swagger_spec)
|
|
|
|
doc = {
|
|
'document_id': f'swagger-{hash(url)}',
|
|
'title': swagger_spec.get('info', {}).get('title', 'API Documentation'),
|
|
'url': url,
|
|
'content': self.convert_swagger_to_text(swagger_spec),
|
|
'type': 'api_doc',
|
|
'category': 'external-tech'
|
|
}
|
|
documents.append(doc)
|
|
|
|
return documents
|
|
|
|
def extract_terms_from_swagger(self, swagger_spec):
|
|
"""Swagger 스펙에서 API 용어 추출"""
|
|
terms = []
|
|
|
|
# Paths에서 엔드포인트 용어
|
|
for path, methods in swagger_spec.get('paths', {}).items():
|
|
for method, details in methods.items():
|
|
if 'summary' in details:
|
|
terms.append({
|
|
'name': details['summary'],
|
|
'definition': details.get('description', ''),
|
|
'category': 'API 엔드포인트'
|
|
})
|
|
|
|
# Schemas에서 데이터 모델 용어
|
|
for schema_name, schema in swagger_spec.get('components', {}).get('schemas', {}).items():
|
|
terms.append({
|
|
'name': schema_name,
|
|
'definition': schema.get('description', ''),
|
|
'category': 'Data Model'
|
|
})
|
|
|
|
return terms
|
|
```
|
|
|
|
**3. 산업 표준 용어집**
|
|
```python
|
|
class StandardTermCollector:
|
|
"""산업 표준 용어집 수집"""
|
|
|
|
STANDARD_SOURCES = {
|
|
'iso': 'https://www.iso.org/obp/ui/',
|
|
'ieee': 'https://www.ieee.org/standards/',
|
|
'w3c': 'https://www.w3.org/standards/'
|
|
}
|
|
|
|
def collect_iso_terms(self):
|
|
"""ISO 표준 용어 수집 (수동 큐레이션 필요)"""
|
|
# 실제로는 웹 크롤링 또는 공식 API 사용
|
|
# 여기서는 예시로 하드코딩
|
|
terms = [
|
|
{
|
|
'name': 'Microservice Architecture',
|
|
'definition': 'An approach to developing a single application as a suite of small services...',
|
|
'source': 'ISO/IEC 29148',
|
|
'category': 'Architecture Pattern',
|
|
'type': 'external'
|
|
}
|
|
]
|
|
return terms
|
|
```
|
|
|
|
---
|
|
|
|
## 8단계: 구현 예시 코드
|
|
|
|
### 전체 파이프라인 통합
|
|
|
|
```python
|
|
# main_pipeline.py
|
|
import asyncio
|
|
from collectors import ConfluenceCollector, SharePointCollector, GoogleDriveCollector
|
|
from extractors import TermExtractor, VectorEmbedder
|
|
from storage import PostgreSQLStore, QdrantStore
|
|
from claude_client import ClaudeAPIClient
|
|
|
|
class TermManagementPipeline:
|
|
def __init__(self, config):
|
|
self.config = config
|
|
|
|
# 수집기 초기화
|
|
self.collectors = {
|
|
'confluence': ConfluenceCollector(config['confluence']),
|
|
'sharepoint': SharePointCollector(config['sharepoint']),
|
|
'google_drive': GoogleDriveCollector(config['google_drive'])
|
|
}
|
|
|
|
# 추출기 초기화
|
|
self.term_extractor = TermExtractor()
|
|
self.vector_embedder = VectorEmbedder(
|
|
model='text-embedding-3-small',
|
|
api_key=config['openai_api_key']
|
|
)
|
|
|
|
# 저장소 초기화
|
|
self.postgres = PostgreSQLStore(config['postgres'])
|
|
self.vector_store = QdrantStore(config['qdrant']) if config.get('use_qdrant') else None
|
|
|
|
# Claude API 클라이언트
|
|
self.claude = ClaudeAPIClient(api_key=config['claude_api_key'])
|
|
|
|
async def run_daily_pipeline(self):
|
|
"""매일 실행되는 파이프라인"""
|
|
|
|
# 1. 문서 수집
|
|
print("📥 1단계: 문서 수집 중...")
|
|
all_documents = []
|
|
for source_name, collector in self.collectors.items():
|
|
try:
|
|
docs = await collector.collect_recent_documents(days=1)
|
|
all_documents.extend(docs)
|
|
print(f" ✓ {source_name}: {len(docs)}개 문서 수집")
|
|
except Exception as e:
|
|
print(f" ✗ {source_name} 수집 실패: {e}")
|
|
|
|
print(f"총 {len(all_documents)}개 문서 수집 완료\n")
|
|
|
|
# 2. 용어 추출
|
|
print("🔍 2단계: 용어 추출 중...")
|
|
all_terms = []
|
|
for doc in all_documents:
|
|
terms = await self.term_extractor.extract_terms(doc)
|
|
all_terms.extend(terms)
|
|
|
|
print(f" ✓ {len(all_terms)}개 용어 추출 완료\n")
|
|
|
|
# 3. 중복 제거 및 정제
|
|
print("🧹 3단계: 용어 정제 중...")
|
|
unique_terms = self.term_extractor.deduplicate_terms(all_terms)
|
|
validated_terms = await self.validate_terms(unique_terms)
|
|
|
|
print(f" ✓ {len(validated_terms)}개 유효 용어 (중복 제거: {len(all_terms) - len(validated_terms)}개)\n")
|
|
|
|
# 4. 벡터 임베딩 생성
|
|
print("🧮 4단계: 벡터 임베딩 생성 중...")
|
|
embeddings = await self.vector_embedder.generate_embeddings(validated_terms)
|
|
|
|
print(f" ✓ {len(embeddings)}개 벡터 생성 완료\n")
|
|
|
|
# 5. 데이터베이스 저장
|
|
print("💾 5단계: 데이터베이스 저장 중...")
|
|
await self.postgres.save_terms(validated_terms)
|
|
|
|
if self.vector_store:
|
|
await self.vector_store.upsert_vectors(embeddings)
|
|
else:
|
|
await self.postgres.save_vectors(embeddings)
|
|
|
|
print(" ✓ 저장 완료\n")
|
|
|
|
# 6. 품질 검증
|
|
print("✅ 6단계: 품질 검증 중...")
|
|
quality_report = await self.validate_quality(validated_terms)
|
|
|
|
print(f" ✓ 정확도: {quality_report['accuracy']}%")
|
|
print(f" ✓ 신뢰도 > 0.8: {quality_report['high_confidence_ratio']}%")
|
|
print(f" ✓ 조직 특화 용어: {quality_report['company_specific_count']}개\n")
|
|
|
|
return {
|
|
'documents_collected': len(all_documents),
|
|
'terms_extracted': len(validated_terms),
|
|
'quality_report': quality_report
|
|
}
|
|
|
|
async def validate_terms(self, terms):
|
|
"""용어 유효성 검증"""
|
|
validated = []
|
|
|
|
for term in terms:
|
|
# 1. 길이 검증 (2-200자)
|
|
if not (2 <= len(term['name']) <= 200):
|
|
continue
|
|
|
|
# 2. 신뢰도 임계값 (0.7 이상)
|
|
if term.get('confidence', 0) < 0.7:
|
|
continue
|
|
|
|
# 3. 중복 체크
|
|
if await self.postgres.term_exists(term['normalized_name']):
|
|
continue
|
|
|
|
validated.append(term)
|
|
|
|
return validated
|
|
|
|
async def validate_quality(self, terms):
|
|
"""품질 지표 계산"""
|
|
total = len(terms)
|
|
high_confidence = sum(1 for t in terms if t.get('confidence', 0) > 0.8)
|
|
company_specific = sum(1 for t in terms if t.get('is_company_specific', False))
|
|
|
|
return {
|
|
'accuracy': round(high_confidence / total * 100, 2) if total > 0 else 0,
|
|
'high_confidence_ratio': round(high_confidence / total * 100, 2) if total > 0 else 0,
|
|
'company_specific_count': company_specific
|
|
}
|
|
|
|
# 실행
|
|
if __name__ == '__main__':
|
|
config = load_config('config.yaml')
|
|
pipeline = TermManagementPipeline(config)
|
|
|
|
# 비동기 실행
|
|
result = asyncio.run(pipeline.run_daily_pipeline())
|
|
|
|
print("\n" + "="*50)
|
|
print("📊 파이프라인 실행 완료")
|
|
print("="*50)
|
|
print(f"수집된 문서: {result['documents_collected']}개")
|
|
print(f"추출된 용어: {result['terms_extracted']}개")
|
|
print(f"품질 점수: {result['quality_report']['accuracy']}%")
|
|
```
|
|
|
|
---
|
|
|
|
## 9단계: Claude API 요청/응답 JSON 구조
|
|
|
|
### 용어 설명 요청
|
|
|
|
```json
|
|
{
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"max_tokens": 1024,
|
|
"temperature": 0.3,
|
|
"top_p": 0.95,
|
|
"system": "당신은 전문 용어를 회의 맥락에 맞춰 설명하는 AI 어시스턴트입니다. 다음 규칙을 따르세요:\n1. 2-3문장으로 간결하게 설명\n2. 회의 맥락을 반영하여 실용적인 정보 제공\n3. 관련 문서 정보가 있으면 활용\n4. 기술 용어는 비전공자도 이해할 수 있게 설명",
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": "=== 회의 정보 ===\n회의 제목: Q4 회의록 작성 가이드 배포\n참석자: 김민준(PO), 이준호(BE), 박서연(AI), 최유진(FE)\n시간: 2024-10-01 14:00\n\n=== 회의 내용 (STT 전사) ===\n민준: 이번 분기 회의록 시스템 개발을 위해 먼저 API Gateway 구조부터 설계해야 할 것 같습니다.\n준호: 네, 저희가 마이크로서비스 아키텍처를 채택했으니 API Gateway가 필수겠네요. RESTful API로 설계하는 게 좋을까요?\n서연: AI 서비스와 연동할 때는 비동기 처리가 중요할 것 같아요. Claude API 호출 시간이 좀 걸리거든요.\n유진: 프론트엔드에서는 실시간으로 용어 설명을 보여줘야 하는데, API Gateway에서 캐싱을 지원하면 좋겠어요.\n\n=== 관련 문서 (RAG 검색 결과) ===\n[문서 1] API 설계 리뷰 회의록 (2024-09-28, 관련도 95%)\n제목: API Gateway 아키텍처 결정\n내용: \"RESTful API 설계 원칙과 보안 정책 확정. AWS API Gateway 채택 결정. JWT 토큰 기반 인증, Rate limiting 적용. Lambda 통합으로 서버리스 아키텍처 구현.\"\n\n[문서 2] 사내 기술 스택 가이드 (2024-08-15, 관련도 78%)\n제목: 마이크로서비스 표준 아키텍처\n내용: \"API Gateway는 클라이언트와 백엔드 서비스 사이의 단일 진입점. 요청 라우팅, 인증/인가, 로깅, Rate limiting 기능 제공. 회사 표준은 AWS API Gateway 사용.\"\n\n[문서 3] 신제품 개발 킥오프 회의록 (2024-09-15, 관련도 65%)\n제목: 1분기 신제품 개발 방향성\n내용: \"협업 도구 시장 분석 및 차별화 전략 수립. 기술 스택으로 마이크로서비스 아키텍처 선정, API Gateway 패턴 적용 예정.\"\n\n=== 질문 ===\n용어: API Gateway\n\n위 회의 맥락에 맞춰 'API Gateway'를 2-3문장으로 설명해주세요. 이 회의에서 API Gateway가 어떤 역할을 하는지 포함해주세요."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Claude API 응답
|
|
|
|
```json
|
|
{
|
|
"id": "msg_01XyZ123AbC456",
|
|
"type": "message",
|
|
"role": "assistant",
|
|
"content": [
|
|
{
|
|
"type": "text",
|
|
"text": "API Gateway는 클라이언트와 백엔드 마이크로서비스 사이의 단일 진입점으로, 요청 라우팅, 인증/인가, Rate limiting, 로깅 등을 담당합니다. 이 회의에서는 회의록 시스템 개발을 위해 AWS API Gateway를 도입하기로 했으며, Claude AI 서비스 연동 시 비동기 처리와 캐싱 기능을 활용하여 실시간 용어 설명 기능을 구현할 계획입니다. 사내 표준 아키텍처에 따라 JWT 인증과 Lambda 통합을 통한 서버리스 구조로 설계됩니다."
|
|
}
|
|
],
|
|
"model": "claude-sonnet-4-5-20250929",
|
|
"stop_reason": "end_turn",
|
|
"stop_sequence": null,
|
|
"usage": {
|
|
"input_tokens": 523,
|
|
"output_tokens": 147
|
|
}
|
|
}
|
|
```
|
|
|
|
### 에러 응답 처리
|
|
|
|
```json
|
|
{
|
|
"type": "error",
|
|
"error": {
|
|
"type": "rate_limit_error",
|
|
"message": "Rate limit exceeded. Please try again later."
|
|
}
|
|
}
|
|
```
|
|
|
|
**에러 핸들링 코드**:
|
|
```python
|
|
class ClaudeAPIClient:
|
|
async def explain_term(self, term, context, rag_docs):
|
|
"""용어 설명 요청 with 에러 핸들링"""
|
|
|
|
max_retries = 3
|
|
retry_delay = 1 # 초
|
|
|
|
for attempt in range(max_retries):
|
|
try:
|
|
response = await self.call_claude_api(term, context, rag_docs)
|
|
|
|
# 캐시 저장
|
|
await self.cache.set(
|
|
key=self.generate_cache_key(term, context),
|
|
value=response['content'][0]['text'],
|
|
ttl=86400 # 24시간
|
|
)
|
|
|
|
return {
|
|
'explanation': response['content'][0]['text'],
|
|
'cached': False,
|
|
'tokens_used': response['usage']['input_tokens'] + response['usage']['output_tokens']
|
|
}
|
|
|
|
except RateLimitError as e:
|
|
if attempt < max_retries - 1:
|
|
await asyncio.sleep(retry_delay * (2 ** attempt)) # Exponential backoff
|
|
continue
|
|
else:
|
|
# Fallback: RAG 문서 직접 반환
|
|
return {
|
|
'explanation': self.generate_fallback_explanation(rag_docs),
|
|
'cached': False,
|
|
'error': 'rate_limit_exceeded'
|
|
}
|
|
|
|
except Exception as e:
|
|
logging.error(f"Claude API 호출 실패: {e}")
|
|
return {
|
|
'explanation': self.generate_fallback_explanation(rag_docs),
|
|
'cached': False,
|
|
'error': str(e)
|
|
}
|
|
|
|
def generate_fallback_explanation(self, rag_docs):
|
|
"""API 실패 시 Fallback 설명 생성"""
|
|
if rag_docs:
|
|
# RAG 문서에서 가장 관련성 높은 부분 추출
|
|
best_doc = max(rag_docs, key=lambda d: d['relevance_score'])
|
|
return f"{best_doc['excerpt']}\n\n(출처: {best_doc['title']})"
|
|
else:
|
|
return "죄송합니다. 현재 이 용어에 대한 설명을 생성할 수 없습니다. 잠시 후 다시 시도해주세요."
|
|
```
|
|
|
|
---
|
|
|
|
## 10단계: 최종 권장사항
|
|
|
|
### 추천 구현 순서
|
|
|
|
**Week 1-2: Phase 1 - JSON 기반 MVP**
|
|
- [ ] JSON 용어 사전 파일 생성 (50개 핵심 용어)
|
|
- [ ] 간단한 키워드 매칭 구현
|
|
- [ ] Claude API 연동 (RAG 없이 프롬프트만)
|
|
- [ ] 기본 UI 구현 (용어 하이라이트, 설명 모달)
|
|
|
|
**Week 3-4: 데이터 수집 자동화**
|
|
- [ ] Confluence API 연동
|
|
- [ ] SharePoint 또는 Google Drive 연동 (우선순위에 따라 선택)
|
|
- [ ] 배치 수집 스크립트 구현
|
|
- [ ] 관리자 승인 UI
|
|
|
|
**Week 5-6: Phase 2 - 기본 RAG**
|
|
- [ ] PostgreSQL + pgvector 설정
|
|
- [ ] OpenAI embedding API 연동
|
|
- [ ] 벡터 검색 구현
|
|
- [ ] Claude API + RAG context 통합
|
|
|
|
**Week 7-8: 품질 개선**
|
|
- [ ] 사용자 피드백 시스템
|
|
- [ ] 품질 지표 대시보드
|
|
- [ ] A/B 테스트 (키워드 매칭 vs RAG)
|
|
- [ ] 성능 최적화 (캐싱, 인덱싱)
|
|
|
|
**Week 9-10: Phase 3 - 고도화 (선택)**
|
|
- [ ] Qdrant 도입 (필요 시)
|
|
- [ ] 하이브리드 검색
|
|
- [ ] 자동 품질 검증
|
|
- [ ] 외부 문서 크롤링
|
|
|
|
### 예상 비용 (월간)
|
|
|
|
| 항목 | Phase 1 | Phase 2 | Phase 3 |
|
|
|------|---------|---------|---------|
|
|
| **인프라** |
|
|
| PostgreSQL (RDS) | $50 | $100 | $150 |
|
|
| Redis (ElastiCache) | $30 | $50 | $50 |
|
|
| Qdrant | - | - | $500 |
|
|
| **API 사용료** |
|
|
| OpenAI Embedding | - | $20 | $50 |
|
|
| Claude API | $100 | $300 | $500 |
|
|
| **기타** |
|
|
| 저장공간 (S3) | $10 | $20 | $30 |
|
|
| **총계** | **$190/월** | **$490/월** | **$1,280/월** |
|
|
|
|
### 성공 지표 (KPI)
|
|
|
|
1. **사용성**
|
|
- 용어 조회율: 회의당 평균 3회 이상
|
|
- 설명 유용성 평가: 4.0/5.0 이상
|
|
- 응답 시간: 평균 2초 이하
|
|
|
|
2. **정확도**
|
|
- 용어 추출 정확도: 85% 이상
|
|
- 설명 적합성: 사용자 피드백 80% 긍정
|
|
- False positive rate: 10% 이하
|
|
|
|
3. **비즈니스**
|
|
- 신규 회의 중 기능 사용률: 60% 이상
|
|
- 월 활성 사용자: 전체의 50% 이상
|
|
- 회의록 작성 시간 단축: 20% 이상
|
|
|
|
### 리스크 및 완화 전략
|
|
|
|
| 리스크 | 영향도 | 완화 전략 |
|
|
|--------|--------|----------|
|
|
| Claude API 비용 급증 | 높음 | 캐싱 강화, 월 예산 한도 설정, Fallback 메커니즘 |
|
|
| 조직 용어 정확도 낮음 | 높음 | 수동 큐레이션 우선, 피드백 루프, 정기 품질 감사 |
|
|
| 응답 시간 느림 | 중간 | 3-tier 캐싱, 벡터 DB 최적화, CDN 활용 |
|
|
| 데이터 수집 실패 | 중간 | Retry 로직, 여러 소스 분산, 수동 백업 |
|
|
| 사용자 채택률 낮음 | 중간 | UX 개선, 온보딩 교육, 사용 인센티브 |
|
|
|
|
---
|
|
|
|
## 최종 결론
|
|
|
|
**선정된 최적안**: 하이브리드 RAG 시스템 (단계적 접근)
|
|
|
|
**핵심 장점**:
|
|
1. ✅ 조직 특화 용어의 높은 정확도 (JSON 큐레이션)
|
|
2. ✅ 확장 가능한 아키텍처 (RAG 시스템)
|
|
3. ✅ 합리적인 비용 구조 ($190/월 시작)
|
|
4. ✅ 명확한 구현 경로 (3-phase)
|
|
5. ✅ 차별화된 맥락 기반 설명
|
|
|
|
**다음 단계**:
|
|
1. Week 1-2에 MVP 구현 시작
|
|
2. 50개 핵심 용어 큐레이션
|
|
3. Claude API 연동 및 테스트
|
|
4. 베타 사용자 10명 초대하여 피드백 수집
|
|
|
|
---
|
|
|
|
**작성일**: 2025-10-28
|
|
**최종 업데이트**: 2025-10-28 (아키텍처 최적안 반영)
|
|
**작성자**: 회의록 개선 프로젝트 팀
|
|
**버전**: 1.1
|
|
**승인자**: 김민준 (Product Owner), 홍길동 (Architect)
|
|
|
|
**관련 문서**:
|
|
- **아키텍처 최적안 결정**: `design/아키텍처_최적안_결정.md`
|
|
- **관련회의록 구현방안**: `design/구현방안-관련자료.md` |