hgzero/design/구현방안-용어집.md
ondal fc2bcc9622 아키텍처 최적안 결정 및 ADR 작성
- 아키텍처_최적안_결정.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>
2025-10-28 09:50:08 +09:00

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`