- 아키텍처_최적안_결정.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>
61 KiB
맥락기반 용어설명 데이터 확보 및 Claude AI 연동 아키텍처 결정 문서
1단계: 각자의 생각
민준 (Product Owner)
비즈니스 관점에서 용어 데이터는 두 가지 소스가 핵심입니다.
- 조직 문서: 내부 업무 매뉴얼, 정책, 프로젝트 문서가 차별화의 핵심
- 외부 기술 문서: 범용 기술 용어는 보조적으로 활용
데이터 품질이 서비스 차별화의 핵심이므로, 초기에는 작은 규모로 시작해도 정확도가 높아야 합니다. MVP에서는 핵심 조직 문서 100개 정도로 시작하고, 점진적으로 확장하는 전략이 필요합니다.
서연 (AI Specialist)
전문용어 처리 파이프라인을 4단계로 제안합니다:
-
수집 (Collection)
- 조직문서: SharePoint, Confluence, Google Drive API 연동
- 외부문서: 공개 API 문서, GitHub 기술문서
-
추출 (Extraction)
- NER(Named Entity Recognition) 기반 기술용어 추출
- TF-IDF + 도메인 사전 기반 조직 특화 용어 추출
- Claude API를 활용한 맥락 기반 용어 추출
-
정제 (Refinement)
- 중복 제거: Fuzzy matching으로 유사 용어 통합
- 품질 검증: 인간 피드백 루프(HITL) 구축
- 메타데이터 태깅: 카테고리, 출처, 신뢰도 점수
-
벡터라이징 (Vectorization)
- 임베딩 모델: OpenAI text-embedding-3-large 또는 Cohere embed-multilingual-v3.0
- 벡터 DB: Pinecone 또는 Qdrant (관리형 vs 자체 호스팅)
- 청크 전략:
- 용어 정의: 단일 청크 (256 토큰)
- 문맥 정보: 슬라이딩 윈도우 (512 토큰, 128 오버랩)
Claude API 연동 구조:
{
"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. 데이터베이스 스키마
-- 용어 마스터 테이블
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 도입
- 자동 수집 파이프라인 구축
- 하이브리드 검색 (키워드 + 벡터)
- 피드백 루프 및 품질 개선
인프라 구성:
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)
사용자 경험 관점에서 고려사항:
-
실시간 용어 감지 UI
- STT 텍스트 스트리밍 중 용어 하이라이트
- 1초 이내 반응 속도 보장
- 로딩 스피너 대신 skeleton UI
-
용어 설명 모달
- 빠른 프리뷰: 2-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) │
└──────────────────────────────────────────────┘
주요 아키텍처 결정:
- 벡터 DB 선택: Qdrant (자체 호스팅) - 비용 절감, 커스터마이징 용이
- 임베딩 모델: OpenAI text-embedding-3-large - 다국어 지원, 높은 정확도
- 캐싱 전략: 3-tier (Browser → Redis → Vector DB)
- 확장성: 마이크로서비스 분리로 독립적 스케일링 가능
도현 (QA Engineer)
품질 보증 관점:
-
데이터 품질 검증
- 용어 추출 정확도: 85% 이상
- 용어 설명 적합성: 사용자 피드백 4.0/5.0 이상
- False positive rate: 10% 이하
-
성능 테스트 기준
- 용어 추출: 1000자 텍스트 기준 < 2초
- RAG 검색: < 500ms
- Claude API 응답: < 3초
- 동시 사용자 100명 부하 테스트
-
테스트 시나리오
- 다양한 도메인 용어 (IT, 비즈니스, 법률, 의료)
- 약어 및 동음이의어 처리
- 긴 문맥에서의 용어 추출
- 오프라인/저속 네트워크 환경
도그냥 (서비스 기획자)
사용자 시나리오 중심 접근:
핵심 사용 케이스:
- 신입 직원: 회의 중 모르는 약어 실시간 확인
- PM: 타부서 회의 참석 시 전문용어 이해
- 경영진: 기술 용어를 비즈니스 맥락으로 이해
차별화 요소:
- 단순 사전이 아닌 "이 회의에서의 의미" 제공
- 과거 회의록 맥락 자동 연결
- 개인화된 용어 학습 이력
MVP 검증 지표:
- 용어 설명 조회율: 회의당 평균 3회 이상
- 도움됨 비율: 80% 이상
- 재사용률: 동일 용어 2회 이상 조회 50%
주영 (DevOps)
운영 관점 인프라 설계:
CI/CD 파이프라인:
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 배포:
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 정적 용어 사전
현정 (콘텐츠 기획자)
콘텐츠 품질 관점:
-
용어 분류 체계
기술 용어 ├── 아키텍처 (API Gateway, Microservice, ...) ├── 프로그래밍 (REST, JWT, ...) └── 인프라 (Kubernetes, Docker, ...) 비즈니스 용어 ├── 전략 (MVP, PMF, ...) ├── 마케팅 (CAC, LTV, ...) └── 재무 (ARR, MRR, ...) 조직 내부 용어 ├── 프로젝트명 ├── 팀/부서명 └── 내부 프로세스 -
설명 작성 가이드
- 1문장: 핵심 정의
- 2문장: 회의 맥락
- 3문장: 관련 정보/링크
-
데이터 큐레이션 프로세스
- 주간 신규 용어 리뷰
- 월간 품질 감사
- 분기별 카테고리 재정비
지수 (Product Designer)
UX/UI 디자인 관점:
용어 표시 디자인 시스템:
용어 배지 스타일:
- 조직 용어: ⭐ 골드 배지
- 기술 용어: 🔧 블루 배지
- 비즈니스 용어: 💼 그린 배지
인터랙션:
- Hover: 1줄 미리보기 툴팁
- Click: 상세 설명 모달 (슬라이드업)
- Long press (모바일): 빠른 설명 팝업
접근성:
- 키보드 네비게이션 지원
- Screen reader 호환
- High contrast mode 지원
모바일 최적화:
- 스와이프로 용어 사전 열기
- 음성으로 용어 질문 (STT 연동)
- 오프라인 캐싱 (자주 사용 50개 용어)
2단계: 의견 종합 및 중복 제거
A. 데이터 수집 전략
- 초기(MVP): 수동 큐레이션 50-100개 핵심 조직 용어
- 자동화: Confluence, SharePoint, Google Drive API 배치 수집
- 외부 소스: GitHub 기술문서, 공개 API 문서, 산업 표준 용어집
B. 용어 추출 및 정제
- 추출 방법: NER, TF-IDF, Claude API 활용 맥락 추출
- 정제 프로세스: 중복 제거(Fuzzy matching), 품질 검증(HITL), 메타데이터 태깅
- 분류 체계: 기술/비즈니스/조직 내부 용어 3대 카테고리
C. 벡터라이징 및 저장
- 임베딩 모델: OpenAI text-embedding-3-large (다국어, 고정확도)
- 벡터 DB: Qdrant (자체 호스팅, 비용 효율적)
- 청크 전략: 용어 정의 256토큰, 문맥 512토큰(128 오버랩)
D. Claude API 연동
- 모델: claude-sonnet-4-5-20250929
- 프롬프트 구조: System message + 회의 전사 + 용어 + RAG context
- 최적화: Rate limiting, Response caching(Redis), Error handling
E. 시스템 아키텍처
- 마이크로서비스 구성: Meeting Service, AI Service 분리
- 데이터베이스: PostgreSQL(메인) + pgvector + Qdrant(벡터)
- 캐싱 전략: 3-tier (Browser → Redis → Vector DB)
F. 성능 및 품질 목표
- 응답 시간: 용어 추출 <2초, RAG 검색 <500ms, 전체 <3초
- 정확도: 추출 85% 이상, 사용자 만족도 4.0/5.0
- 확장성: 동시 사용자 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단계: 각 최적안 후보 평가
평가 기준 (가중치)
- 비즈니스 가치 (30%): 차별화, 사용자 만족도, ROI
- 기술적 실현 가능성 (25%): 개발 난이도, 리스크, 일정
- 확장성 (20%): 사용자/데이터 증가 대응
- 비용 효율성 (15%): 초기 투자, 운영 비용
- 유지보수성 (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)
선정 이유:
- 조직 특화 용어의 높은 정확도 보장 (JSON 큐레이션)
- 외부 용어의 확장성 확보 (RAG 시스템)
- 합리적인 비용 구조 ($35K 초기 + $5K/월)
- 명확한 아키텍처, 유지보수 가능
- 차별화 포인트 구현 가능
반복 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 적합
- 단계적 접근으로 리스크 분산
대안 고려:
-
PostgreSQL+pgvector ✅:
- 기존 DB 활용, 트랜잭션 보장, 학습 곡선 낮음
- 소규모에 적합, 비용 $0 (기존 DB)
-
Azure AI Search (초기 도입):
- 고성능 검색, Semantic Ranking, 관리형 서비스
- 소규모에 과도, 비용 $250/월
-
Qdrant (self-hosted):
- 전문 Vector DB, 고성능, 오픈소스
- 운영 부담, 학습 곡선 높음, 비용 $500/월
-
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)
컨텍스트:
- 한국어/영어 혼용 문서 처리 필요
- 비용과 성능의 균형 필요
- 임베딩 차원수와 정확도 트레이드오프
대안 고려:
-
OpenAI text-embedding-3-small:
- 1536 차원, $0.02/1M tokens
- 적절한 정확도, 낮은 비용
-
OpenAI text-embedding-3-large:
- 3072 차원, $0.13/1M tokens
- 최고 정확도, 높은 비용
-
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 - 수동 큐레이션:
{
"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 - 반자동 수집:
# 배치 수집 스크립트
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 요청 구조:
{
"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문장으로 설명해주세요."
}
]
}
]
}
응답 처리:
{
"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
}
}
최적화 전략:
- 캐싱: Redis에 (용어 + 회의 맥락 해시) → 설명 저장 (TTL 24시간)
- Rate limiting: 사용자당 분당 10회, 회의당 시간당 100회
- Fallback: API 실패 시 RAG 문서 직접 반환
- 비용 관리: 월 예산 $500 초과 시 알림 (input 500K tokens 기준)
결정 근거:
- Claude의 장문 이해 능력 활용 (200K tokens)
- Structured prompt로 일관된 응답 품질
- RAG context로 정확도 향상
- 캐싱으로 중복 호출 방지 (비용 절감)
ADR-005: 데이터베이스 스키마 설계
결정: 정규화된 관계형 스키마 + JSON 메타데이터
스키마 구조:
-- 용어 마스터 테이블
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)
);
데이터 예시:
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 추가
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 연동
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 연동
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 연동
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
수집 스케줄:
# 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 기술 문서 크롤링
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)
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. 산업 표준 용어집
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단계: 구현 예시 코드
전체 파이프라인 통합
# 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 구조
용어 설명 요청
{
"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 응답
{
"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
}
}
에러 응답 처리
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "Rate limit exceeded. Please try again later."
}
}
에러 핸들링 코드:
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)
-
사용성
- 용어 조회율: 회의당 평균 3회 이상
- 설명 유용성 평가: 4.0/5.0 이상
- 응답 시간: 평균 2초 이하
-
정확도
- 용어 추출 정확도: 85% 이상
- 설명 적합성: 사용자 피드백 80% 긍정
- False positive rate: 10% 이하
-
비즈니스
- 신규 회의 중 기능 사용률: 60% 이상
- 월 활성 사용자: 전체의 50% 이상
- 회의록 작성 시간 단축: 20% 이상
리스크 및 완화 전략
| 리스크 | 영향도 | 완화 전략 |
|---|---|---|
| Claude API 비용 급증 | 높음 | 캐싱 강화, 월 예산 한도 설정, Fallback 메커니즘 |
| 조직 용어 정확도 낮음 | 높음 | 수동 큐레이션 우선, 피드백 루프, 정기 품질 감사 |
| 응답 시간 느림 | 중간 | 3-tier 캐싱, 벡터 DB 최적화, CDN 활용 |
| 데이터 수집 실패 | 중간 | Retry 로직, 여러 소스 분산, 수동 백업 |
| 사용자 채택률 낮음 | 중간 | UX 개선, 온보딩 교육, 사용 인센티브 |
최종 결론
선정된 최적안: 하이브리드 RAG 시스템 (단계적 접근)
핵심 장점:
- ✅ 조직 특화 용어의 높은 정확도 (JSON 큐레이션)
- ✅ 확장 가능한 아키텍처 (RAG 시스템)
- ✅ 합리적인 비용 구조 ($190/월 시작)
- ✅ 명확한 구현 경로 (3-phase)
- ✅ 차별화된 맥락 기반 설명
다음 단계:
- Week 1-2에 MVP 구현 시작
- 50개 핵심 용어 큐레이션
- Claude API 연동 및 테스트
- 베타 사용자 10명 초대하여 피드백 수집
작성일: 2025-10-28 최종 업데이트: 2025-10-28 (아키텍처 최적안 반영) 작성자: 회의록 개선 프로젝트 팀 버전: 1.1 승인자: 김민준 (Product Owner), 홍길동 (Architect)
관련 문서:
- 아키텍처 최적안 결정:
design/아키텍처_최적안_결정.md - 관련회의록 구현방안:
design/구현방안-관련자료.md