From 34dbe84151ad932d86e2faafa5c30a7afb9fbc6d Mon Sep 17 00:00:00 2001 From: hiondal Date: Mon, 20 Oct 2025 16:56:51 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A7=A5=EB=9D=BD=EA=B8=B0=EB=B0=98=EC=9A=A9?= =?UTF-8?q?=EC=96=B4=EC=84=A4=EB=AA=85=20=EA=B5=AC=ED=98=84=EB=B0=A9?= =?UTF-8?q?=EC=95=88=20=EC=9E=91=EC=84=B1=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 전체 팀원 토의를 통한 하이브리드형(단계별 확장) 최적안 도출 - 데이터 수집/정제/벡터라이징 전략 수립 - Claude API 호출 구조 설계 (프롬프트, JSON 요청/응답) - Phase 1-3 단계별 구현 로드맵 (2주/4주/6주) - 성능 목표: 응답시간 5초→3초→2초, 정확도 70%→85%→90% - 비용 최적화: Redis 캐싱으로 60% 절감 ($45→$18/월) - 기술 스택: OpenAI Embedding + Pinecone + Claude 3.5 + Redis - 하이브리드 검색: 벡터 70% + 키워드 30% - 품질 검증 기준 및 운영 모니터링 전략 포함 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- design/구현방안-맥락기반용어설명.md | 976 ++++++++++++++++++++++++++++ 1 file changed, 976 insertions(+) create mode 100644 design/구현방안-맥락기반용어설명.md diff --git a/design/구현방안-맥락기반용어설명.md b/design/구현방안-맥락기반용어설명.md new file mode 100644 index 0000000..6032fd1 --- /dev/null +++ b/design/구현방안-맥락기반용어설명.md @@ -0,0 +1,976 @@ +# 맥락기반 용어설명 구현방안 + +## 문서 정보 +- **작성일**: 2025-01-20 +- **작성자**: AI Specialist 박서연, Backend Developer 이준호/이동욱, Architect 홍길동 +- **버전**: 2.0 (하이브리드형 - 단계별 확장 방식) +- **상태**: 최종 승인 + +--- + +## 목차 +1. [개요](#개요) +2. [아키텍처 설계](#아키텍처-설계) +3. [데이터 수집 및 정제](#데이터-수집-및-정제) +4. [벡터라이징 전략](#벡터라이징-전략) +5. [Claude API 호출 구조](#claude-api-호출-구조) +6. [단계별 구현 로드맵](#단계별-구현-로드맵) +7. [성능 및 비용 최적화](#성능-및-비용-최적화) +8. [품질 검증 기준](#품질-검증-기준) +9. [운영 및 모니터링](#운영-및-모니터링) + +--- + +## 개요 + +### 목적 +회의록 작성자가 업무 지식이 없어도, AI가 **맥락에 맞는 실용적인 용어 설명**을 자동으로 제공하여 정확한 회의록 작성을 지원합니다. + +### 핵심 차별화 포인트 +- ❌ 단순 용어 정의 (Wikipedia 스타일) +- ✅ **조직 내 실제 사용 맥락** 제공 +- ✅ **관련 회의록 및 프로젝트 연결** +- ✅ **과거 논의 요약** (언제, 누가, 어떻게 사용했는지) + +### 관련 유저스토리 +- **UFR-RAG-010**: 전문용어 자동 감지 +- **UFR-RAG-020**: 맥락 기반 용어 설명 생성 + +--- + +## 아키텍처 설계 + +### 전체 아키텍처 (최종 목표) + +``` +┌─────────────────────────────────────────────────────────┐ +│ 회의록 작성 중 │ +│ (전문용어 "RAG" 감지) │ +└──────────────────┬──────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ RAG 서비스 (Node.js) │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ 1. 용어 감지 엔진 │ │ +│ │ - 용어 사전 매칭 (Trie 자료구조) │ │ +│ │ - 신뢰도 계산 (0-100%) │ │ +│ └───────────────────────────────────────────────────┘ │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ 2. Redis 캐시 조회 │ │ +│ │ Key: term:{용어명}:{회의ID} │ │ +│ │ TTL: 자주 쓰이는 용어 7일, 드문 용어 1일 │ │ +│ └───────────────────────────────────────────────────┘ │ +│ ▼ (캐시 미스) │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ 3. 벡터 검색 (Pinecone) │ │ +│ │ - Query Embedding (OpenAI text-embedding-3) │ │ +│ │ - 하이브리드 검색 (벡터 + 키워드) │ │ +│ │ - Top 5 관련 문서 추출 │ │ +│ └───────────────────────────────────────────────────┘ │ +│ ▼ │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ 4. Claude API 호출 │ │ +│ │ - 프롬프트: System + User + Few-shot │ │ +│ │ - 응답: JSON {definition, context, related} │ │ +│ └───────────────────────────────────────────────────┘ │ +│ ▼ │ +│ ┌───────────────────────────────────────────────────┐ │ +│ │ 5. 응답 캐싱 (Redis) │ │ +│ │ - 다음 요청 시 즉시 반환 │ │ +│ └───────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ 사용자에게 설명 표시 │ +│ - 간단한 정의 (1-2문장) │ +│ - 맥락 기반 설명 │ +│ - 관련 회의록 링크 (최대 3개) │ +│ - 과거 사용 사례 │ +└─────────────────────────────────────────────────────────┘ +``` + +### 기술 스택 + +| 계층 | 기술 | 선택 이유 | +|------|------|-----------| +| **임베딩 모델** | OpenAI text-embedding-3-large | 높은 정확도 (1536 차원), 안정적 API | +| **벡터 DB** | Pinecone | 관리형 서비스, 빠른 검색, Kubernetes 호환 | +| **LLM** | Claude 3.5 Sonnet | 긴 컨텍스트, 한국어 성능 우수, JSON 응답 안정적 | +| **캐시** | Redis | 빠른 응답, TTL 지원, 분산 캐시 가능 | +| **메시지 큐** | RabbitMQ | 배치 작업 비동기 처리 | +| **오케스트레이션** | Kubernetes | 스케일링, 배포 자동화 | + +--- + +## 데이터 수집 및 정제 + +### 1. 데이터 수집 범위 + +#### Phase 1 (2주): 회의록만 +``` +회의록 DB (Meeting 서비스) + ├─ meeting_id + ├─ title + ├─ content (Markdown) + ├─ participants + ├─ date + └─ project_id +``` + +#### Phase 2 (4주): 위키 추가 +``` +사내 위키 (Confluence, Notion 등) + ├─ page_id + ├─ title + ├─ content + ├─ author + ├─ last_updated + └─ tags +``` + +#### Phase 3 (6주): 프로젝트 문서 + 이메일 +``` +프로젝트 문서 (Google Drive, SharePoint) + ├─ doc_id + ├─ title + ├─ content + ├─ project_id + └─ created_at + +이메일 (Outlook, Gmail) + ├─ email_id + ├─ subject + ├─ body (HTML → Plain Text 변환) + ├─ sender + └─ date +``` + +### 2. 데이터 정제 파이프라인 + +```mermaid +graph LR + A[원본 수집] --> B[전처리] + B --> C[메타데이터 추가] + C --> D[벡터화] + D --> E[Pinecone 저장] + + B --> B1[불용어 제거] + B --> B2[토큰화] + B --> B3[정규화] + + C --> C1[날짜] + C --> C2[참석자/작성자] + C --> C3[프로젝트] + C --> C4[부서] +``` + +#### 전처리 상세 + +**1) 불용어 제거** +```python +STOPWORDS = [ + '그', '저', '것', '수', '등', '들', '및', '때문', '위해', '통해', + '하지만', '그러나', '따라서', '또한', '즉', '예를 들어' +] + +def remove_stopwords(text): + tokens = text.split() + return ' '.join([t for t in tokens if t not in STOPWORDS]) +``` + +**2) 토큰화 (한국어)** +```python +from konlpy.tag import Okt + +okt = Okt() + +def tokenize_korean(text): + return okt.morphs(text, stem=True) +``` + +**3) 정규화** +```python +import re + +def normalize(text): + # 이메일 제거 + text = re.sub(r'\S+@\S+', '[EMAIL]', text) + # URL 제거 + text = re.sub(r'http\S+', '[URL]', text) + # 특수문자 제거 (단, -_ 유지) + text = re.sub(r'[^\w\s-_]', '', text) + # 공백 정리 + text = re.sub(r'\s+', ' ', text) + return text.strip() +``` + +### 3. 메타데이터 설계 + +```json +{ + "id": "doc_12345", + "content": "RAG 시스템은 Retrieval-Augmented Generation의 약자로...", + "metadata": { + "source": "meeting", // meeting | wiki | doc | email + "title": "프로젝트 회의", + "date": "2025-01-20T14:00:00Z", + "participants": ["김민준", "박서연", "이준호"], + "project_id": "proj_001", + "project_name": "회의록 시스템", + "department": "개발팀", + "tags": ["RAG", "AI", "회의록"], + "language": "ko" + } +} +``` + +--- + +## 벡터라이징 전략 + +### 1. Chunking 전략 + +**목표**: 회의록/문서를 의미 있는 단위로 분할하여 검색 정확도 향상 + +```python +def chunk_text(text, chunk_size=500, overlap=50): + """ + 텍스트를 chunk로 분할 + + Args: + text: 원본 텍스트 + chunk_size: 청크 크기 (토큰 수) + overlap: 청크 간 중복 크기 + + Returns: + List[str]: 청크 리스트 + """ + tokens = tokenize_korean(text) + chunks = [] + + for i in range(0, len(tokens), chunk_size - overlap): + chunk = tokens[i:i + chunk_size] + chunks.append(' '.join(chunk)) + + return chunks +``` + +**Chunking 전략 비교** + +| 방식 | 크기 | Overlap | 장점 | 단점 | +|------|------|---------|------|------| +| **고정 크기** | 500 토큰 | 50 토큰 | 단순, 빠름 | 문맥 끊김 가능 | +| **문단 기반** | 가변 | 0 | 자연스러운 구분 | 크기 불균등 | +| **문장 기반** | 가변 | 1 문장 | 의미 보존 | 너무 작을 수 있음 | +| **하이브리드** | 500 토큰 | 50 토큰 + 문단 경계 | 균형잡힘 | 복잡함 | + +**선택**: **하이브리드 방식** (Phase 2 이후 적용) + +### 2. Embedding 생성 + +```python +import openai + +def generate_embedding(text, model="text-embedding-3-large"): + """ + OpenAI API로 임베딩 생성 + + Returns: + List[float]: 1536 차원 벡터 + """ + response = openai.embeddings.create( + input=text, + model=model + ) + return response.data[0].embedding +``` + +**비용 계산**: +- text-embedding-3-large: $0.00013 / 1K tokens +- 예상 월 비용: 500 회의록 × 2K tokens × $0.00013 = $0.13 + +### 3. Pinecone 저장 + +```python +import pinecone + +# 초기화 +pinecone.init(api_key="YOUR_API_KEY", environment="us-west1-gcp") +index = pinecone.Index("meeting-rag") + +def upsert_to_pinecone(doc_id, embedding, metadata): + """ + Pinecone에 벡터 저장 + """ + index.upsert(vectors=[{ + "id": doc_id, + "values": embedding, + "metadata": metadata + }]) +``` + +**Pinecone 설정**: +- Index: meeting-rag +- Dimension: 1536 +- Metric: cosine +- Replicas: 1 (Phase 1), 2 (Phase 3, HA) +- Pods: p1.x1 (Phase 1), p1.x2 (Phase 2+) + +--- + +## Claude API 호출 구조 + +### 1. 프롬프트 설계 + +#### System Prompt +``` +당신은 조직 내 전문용어를 쉽게 설명하는 전문가입니다. +- 사내 회의록, 위키, 프로젝트 문서를 기반으로 실용적인 설명을 제공합니다. +- 단순 정의가 아닌, 조직에서 실제로 어떻게 사용되는지 맥락을 포함합니다. +- 과거 논의 내용을 요약하여 제공합니다. + +응답 형식은 반드시 JSON으로 작성하세요: +{ + "definition": "간단한 정의 (1-2문장)", + "context": "이 회의에서의 의미 (맥락 기반 설명)", + "usage_examples": ["실제 사용 사례 1", "사용 사례 2"], + "related_projects": ["관련 프로젝트 1", "프로젝트 2"], + "past_discussions": [ + {"date": "2025-01-15", "meeting": "프로젝트 회의", "summary": "RAG 시스템 도입 결정"} + ], + "references": ["doc_id_1", "doc_id_2", "doc_id_3"] +} +``` + +#### User Prompt (Few-shot Learning) +``` +아래는 검색된 관련 문서들입니다: + +--- +문서 1 (회의록, 2025-01-15): +제목: 프로젝트 회의 +내용: RAG 시스템을 도입하기로 결정했습니다. Retrieval-Augmented Generation은 문서 검색과 생성을 결합한 AI 기술입니다... + +문서 2 (위키, 2025-01-10): +제목: AI 기술 가이드 +내용: RAG는 벡터 DB를 활용하여 관련 문서를 찾고, LLM이 이를 기반으로 답변을 생성하는 방식입니다... + +문서 3 (프로젝트 문서, 2025-01-05): +제목: 회의록 시스템 설계서 +내용: 맥락 기반 용어 설명 기능에 RAG 시스템을 적용합니다... +--- + +현재 회의 맥락: +- 회의: "주간 스크럼" +- 날짜: 2025-01-20 +- 참석자: 김민준, 박서연, 이준호 +- 프로젝트: "회의록 시스템" + +용어: "RAG" + +위 정보를 바탕으로 "RAG"에 대한 설명을 JSON 형식으로 작성해주세요. + +예시: +{ + "definition": "Retrieval-Augmented Generation의 약자로, 문서 검색과 AI 생성을 결합한 기술입니다.", + "context": "우리 팀은 회의록 시스템에 RAG를 적용하여 과거 회의록과 사내 문서를 검색하고, 맥락에 맞는 용어 설명을 자동 생성합니다.", + "usage_examples": [ + "회의 중 전문용어가 나오면 RAG 시스템이 관련 문서를 찾아 설명을 제공합니다", + "신입사원도 업무 지식 없이 정확한 회의록을 작성할 수 있습니다" + ], + "related_projects": ["회의록 시스템", "AI 자동화 프로젝트"], + "past_discussions": [ + {"date": "2025-01-15", "meeting": "프로젝트 회의", "summary": "RAG 시스템 도입 결정"}, + {"date": "2025-01-10", "meeting": "기술 세미나", "summary": "RAG 아키텍처 소개"} + ], + "references": ["doc_12345", "doc_12346", "doc_12347"] +} +``` + +### 2. API 호출 코드 + +```typescript +import Anthropic from '@anthropic-ai/sdk'; + +const anthropic = new Anthropic({ + apiKey: process.env.CLAUDE_API_KEY, +}); + +interface TermExplanation { + definition: string; + context: string; + usage_examples: string[]; + related_projects: string[]; + past_discussions: Array<{ + date: string; + meeting: string; + summary: string; + }>; + references: string[]; +} + +async function explainTerm( + term: string, + relatedDocs: any[], + meetingContext: any +): Promise { + + const systemPrompt = `당신은 조직 내 전문용어를 쉽게 설명하는 전문가입니다...`; + + const userPrompt = buildUserPrompt(term, relatedDocs, meetingContext); + + const response = await anthropic.messages.create({ + model: 'claude-3-5-sonnet-20241022', + max_tokens: 2000, + temperature: 0.3, // 일관된 응답을 위해 낮은 temperature + system: systemPrompt, + messages: [ + { + role: 'user', + content: userPrompt + } + ] + }); + + // JSON 파싱 + const content = response.content[0].text; + const jsonMatch = content.match(/\{[\s\S]*\}/); + + if (!jsonMatch) { + throw new Error('Invalid JSON response from Claude'); + } + + return JSON.parse(jsonMatch[0]); +} + +function buildUserPrompt(term: string, docs: any[], context: any): string { + const docsSummary = docs.map((doc, idx) => { + return `문서 ${idx + 1} (${doc.metadata.source}, ${doc.metadata.date}): +제목: ${doc.metadata.title} +내용: ${doc.content.substring(0, 500)}...`; + }).join('\n\n'); + + return `아래는 검색된 관련 문서들입니다: + +--- +${docsSummary} +--- + +현재 회의 맥락: +- 회의: "${context.meeting_title}" +- 날짜: ${context.date} +- 참석자: ${context.participants.join(', ')} +- 프로젝트: "${context.project_name}" + +용어: "${term}" + +위 정보를 바탕으로 "${term}"에 대한 설명을 JSON 형식으로 작성해주세요. + +예시: +{ + "definition": "...", + "context": "...", + ... +}`; +} +``` + +### 3. API 요청/응답 예시 + +#### 요청 (Request) +```json +{ + "model": "claude-3-5-sonnet-20241022", + "max_tokens": 2000, + "temperature": 0.3, + "system": "당신은 조직 내 전문용어를 쉽게 설명하는 전문가입니다...", + "messages": [ + { + "role": "user", + "content": "아래는 검색된 관련 문서들입니다...\n용어: \"RAG\"" + } + ] +} +``` + +#### 응답 (Response) +```json +{ + "id": "msg_01ABC123", + "type": "message", + "role": "assistant", + "content": [ + { + "type": "text", + "text": "{\n \"definition\": \"Retrieval-Augmented Generation의 약자로, 문서 검색과 AI 생성을 결합한 기술입니다.\",\n \"context\": \"우리 팀은 회의록 시스템에 RAG를 적용하여 과거 회의록과 사내 문서를 검색하고, 맥락에 맞는 용어 설명을 자동 생성합니다.\",\n \"usage_examples\": [\n \"회의 중 전문용어가 나오면 RAG 시스템이 관련 문서를 찾아 설명을 제공합니다\",\n \"신입사원도 업무 지식 없이 정확한 회의록을 작성할 수 있습니다\"\n ],\n \"related_projects\": [\"회의록 시스템\", \"AI 자동화 프로젝트\"],\n \"past_discussions\": [\n {\"date\": \"2025-01-15\", \"meeting\": \"프로젝트 회의\", \"summary\": \"RAG 시스템 도입 결정\"},\n {\"date\": \"2025-01-10\", \"meeting\": \"기술 세미나\", \"summary\": \"RAG 아키텍처 소개\"}\n ],\n \"references\": [\"doc_12345\", \"doc_12346\", \"doc_12347\"]\n}" + } + ], + "model": "claude-3-5-sonnet-20241022", + "stop_reason": "end_turn", + "usage": { + "input_tokens": 1250, + "output_tokens": 320 + } +} +``` + +--- + +## 단계별 구현 로드맵 + +### Phase 1: 기본 기능 (2주) + +**목표**: 회의록 기반 최소 기능 구현 및 사용자 테스트 + +#### 구현 범위 +- [x] 회의록 DB 연동 +- [x] 용어 감지 엔진 (Trie 자료구조) +- [x] OpenAI Embedding API 연동 +- [x] Pinecone 벡터 검색 +- [x] Claude API 호출 (기본 프롬프트) +- [x] UI: 점선 밑줄 하이라이트, 바텀 시트 툴팁 + +#### 성능 목표 +- 응답 시간: **5초 이내** +- 용어 감지 정확도: **70% 이상** +- 관련 문서 정확도: **60% 이상** + +#### 제약 사항 +- 캐시 없음 (모든 요청 실시간 처리) +- 회의록만 검색 (위키, 문서, 이메일 미포함) + +#### 배포 전략 +- Beta 테스트: 20명 (개발팀 10명, 기획팀 5명, 경영지원팀 5명) +- 피드백 수집: Google Forms 설문 + 주간 인터뷰 + +--- + +### Phase 2: 성능 개선 (4주) + +**목표**: 캐시 도입 + 위키 추가 + 하이브리드 검색 + +#### 구현 범위 +- [x] Redis 캐시 레이어 + - TTL: 자주 쓰이는 용어 7일, 드문 용어 1일 + - Cache Warming: 상위 50개 용어 사전 캐싱 +- [x] 사내 위키 연동 (Confluence, Notion) +- [x] 하이브리드 검색 (벡터 + 키워드) + - 벡터 유사도: 70% 가중치 + - 키워드 매칭: 30% 가중치 +- [x] 프롬프트 최적화 (Few-shot learning) + +#### 성능 목표 +- 응답 시간: **3초 이내** (캐시 히트 시 0.5초) +- 용어 감지 정확도: **85% 이상** +- 관련 문서 정확도: **75% 이상** +- 캐시 히트율: **60% 이상** + +#### 배포 전략 +- Beta 테스트 확대: 50명 +- A/B 테스트: 캐시 vs 캐시 없음, 하이브리드 vs 벡터 단독 + +--- + +### Phase 3: 고도화 (6주) + +**목표**: 전체 데이터 통합 + 시맨틱 필터링 + 부서별 커스터마이징 + +#### 구현 범위 +- [x] 프로젝트 문서 연동 (Google Drive, SharePoint) +- [x] 이메일 연동 (Outlook, Gmail) +- [x] 시맨틱 필터링 + - 부서별 용어 우선순위 + - 프로젝트별 문맥 가중치 +- [x] 2단계 캐싱 + - L1: Redis (Hot data, TTL 7일) + - L2: CDN (Static explanations, TTL 30일) +- [x] 용어 추천 시스템 + - "이 용어를 사전에 추가할까요?" 제안 + +#### 성능 목표 +- 응답 시간: **2초 이내** (캐시 히트 시 0.3초) +- 용어 감지 정확도: **90% 이상** +- 관련 문서 정확도: **80% 이상** +- 캐시 히트율: **80% 이상** + +#### 배포 전략 +- 전사 배포 (200명+) +- 부서별 용어 사전 큐레이션 워크숍 + +--- + +## 성능 및 비용 최적화 + +### 1. 캐싱 전략 + +#### Redis 캐시 구조 +``` +Key: term:{term_name}:{meeting_id} +Value: JSON (TermExplanation) +TTL: + - 자주 쓰이는 용어 (요청 >10회/월): 7일 + - 드문 용어 (요청 <10회/월): 1일 +``` + +#### Cache Warming +```python +# 매일 새벽 2시 실행 +def cache_warming(): + # 상위 50개 빈도 높은 용어 + top_terms = get_top_terms(limit=50) + + for term in top_terms: + # 최근 회의 맥락으로 미리 캐싱 + recent_meetings = get_recent_meetings(limit=5) + for meeting in recent_meetings: + explanation = explain_term(term, meeting) + cache_key = f"term:{term}:{meeting.id}" + redis.setex(cache_key, ttl=7*24*3600, value=json.dumps(explanation)) +``` + +### 2. 하이브리드 검색 + +```python +def hybrid_search(query, top_k=5): + """ + 벡터 검색 + 키워드 검색 결합 + """ + # 1. 벡터 검색 (70% 가중치) + query_embedding = generate_embedding(query) + vector_results = pinecone_index.query( + vector=query_embedding, + top_k=top_k * 2, # 2배수 조회 + include_metadata=True + ) + + # 2. 키워드 검색 (30% 가중치) + keyword_results = elasticsearch.search( + index="meetings", + body={ + "query": { + "multi_match": { + "query": query, + "fields": ["title^3", "content", "tags^2"] + } + } + }, + size=top_k * 2 + ) + + # 3. 점수 결합 (Normalized) + combined_scores = {} + + for match in vector_results.matches: + combined_scores[match.id] = match.score * 0.7 + + for hit in keyword_results['hits']['hits']: + doc_id = hit['_id'] + if doc_id in combined_scores: + combined_scores[doc_id] += hit['_score'] * 0.3 + else: + combined_scores[doc_id] = hit['_score'] * 0.3 + + # 4. 상위 k개 반환 + sorted_results = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True) + return sorted_results[:top_k] +``` + +### 3. Claude API 비용 절감 + +#### 비용 구조 +``` +Claude 3.5 Sonnet: +- Input: $3 / 1M tokens +- Output: $15 / 1M tokens + +월 예상 비용 (500 회의록, 평균 10회 용어 설명): +- 총 요청: 5,000회 +- 평균 Input: 1,500 tokens/요청 +- 평균 Output: 300 tokens/요청 + +비용 = (5000 * 1500 * $3 / 1M) + (5000 * 300 * $15 / 1M) + = $22.5 + $22.5 + = $45/월 + +캐시 적용 시 (60% 히트율): + = $45 * 0.4 = $18/월 +``` + +#### Rate Limiting +```typescript +import { RateLimiter } from 'limiter'; + +const limiter = new RateLimiter({ + tokensPerInterval: 60, // 분당 60회 + interval: 'minute' +}); + +async function callClaudeWithRateLimit(prompt: string) { + await limiter.removeTokens(1); + return await anthropic.messages.create({...}); +} +``` + +--- + +## 품질 검증 기준 + +### 1. 자동 검증 + +#### 용어 감지 정확도 +```python +def calculate_term_detection_accuracy(): + """ + 테스트 세트: 100개 회의록, 200개 용어 + """ + test_data = load_test_data("term_detection_test.json") + + correct = 0 + total = len(test_data) + + for sample in test_data: + detected_terms = detect_terms(sample.content) + expected_terms = sample.expected_terms + + # F1 Score 계산 + precision = len(set(detected_terms) & set(expected_terms)) / len(detected_terms) + recall = len(set(detected_terms) & set(expected_terms)) / len(expected_terms) + f1 = 2 * (precision * recall) / (precision + recall) + + correct += f1 + + return (correct / total) * 100 +``` + +#### 설명 품질 평가 +```python +def evaluate_explanation_quality(): + """ + 사람 평가 + 자동 평가 결합 + """ + test_cases = load_test_cases("explanation_quality.json") + + scores = [] + + for case in test_cases: + explanation = explain_term(case.term, case.context) + + # 자동 평가 (1-5점) + auto_score = 0 + + # 1) 정의 포함 여부 (1점) + if len(explanation.definition) > 10: + auto_score += 1 + + # 2) 맥락 설명 포함 여부 (1점) + if len(explanation.context) > 20: + auto_score += 1 + + # 3) 사용 사례 포함 여부 (1점) + if len(explanation.usage_examples) >= 1: + auto_score += 1 + + # 4) 관련 문서 연결 여부 (1점) + if len(explanation.references) >= 1: + auto_score += 1 + + # 5) 과거 논의 포함 여부 (1점) + if len(explanation.past_discussions) >= 1: + auto_score += 1 + + scores.append(auto_score) + + return sum(scores) / len(scores) +``` + +### 2. 사람 평가 + +#### 평가 기준 +| 항목 | 배점 | 기준 | +|------|------|------| +| **정확성** | 30점 | 용어 정의가 정확한가? | +| **맥락 적합성** | 30점 | 현재 회의 맥락과 관련성이 높은가? | +| **실용성** | 20점 | 실제 업무에 도움이 되는가? | +| **가독성** | 10점 | 이해하기 쉬운가? | +| **완성도** | 10점 | 관련 문서, 과거 논의 포함 여부 | + +#### 평가 프로세스 +1. 매 Sprint 종료 시 20개 샘플 평가 +2. 평가자: Beta 테스터 10명 (무작위 선정) +3. 목표 점수: 80점 이상 + +--- + +## 운영 및 모니터링 + +### 1. 성능 메트릭 + +#### Prometheus 메트릭 +```typescript +import { Counter, Histogram, Gauge } from 'prom-client'; + +// 요청 수 +const requestCounter = new Counter({ + name: 'rag_requests_total', + help: 'Total number of RAG requests', + labelNames: ['status', 'cache_hit'] +}); + +// 응답 시간 +const responseTimeHistogram = new Histogram({ + name: 'rag_response_time_seconds', + help: 'RAG response time in seconds', + buckets: [0.5, 1, 2, 3, 5] +}); + +// 캐시 히트율 +const cacheHitRate = new Gauge({ + name: 'rag_cache_hit_rate', + help: 'Cache hit rate percentage' +}); + +// Claude API 비용 +const apiCostCounter = new Counter({ + name: 'claude_api_cost_usd', + help: 'Estimated Claude API cost in USD' +}); +``` + +#### Grafana 대시보드 +``` +┌────────────────────────────────────────────┐ +│ RAG 시스템 성능 모니터링 │ +├────────────────────────────────────────────┤ +│ [ 실시간 요청 수 ] [ 평균 응답 시간 ] │ +│ 125 req/min 2.3s │ +├────────────────────────────────────────────┤ +│ [ 캐시 히트율 ] [ Claude API 비용 ] │ +│ 65% $18/월 │ +├────────────────────────────────────────────┤ +│ [ 용어 감지 정확도 ] [ 설명 품질 점수 ] │ +│ 88% 85/100 │ +└────────────────────────────────────────────┘ +``` + +### 2. 알림 설정 + +#### Alertmanager 규칙 +```yaml +groups: + - name: rag_alerts + rules: + - alert: HighResponseTime + expr: rag_response_time_seconds > 5 + for: 5m + labels: + severity: warning + annotations: + summary: "RAG 응답 시간 초과 (>5초)" + + - alert: LowCacheHitRate + expr: rag_cache_hit_rate < 50 + for: 10m + labels: + severity: info + annotations: + summary: "캐시 히트율 낮음 (<50%)" + + - alert: ClaudeAPIError + expr: increase(rag_requests_total{status="error"}[5m]) > 10 + labels: + severity: critical + annotations: + summary: "Claude API 오류 급증" +``` + +### 3. 로깅 전략 + +```typescript +import winston from 'winston'; + +const logger = winston.createLogger({ + level: 'info', + format: winston.format.json(), + transports: [ + new winston.transports.File({ filename: 'rag-error.log', level: 'error' }), + new winston.transports.File({ filename: 'rag-combined.log' }) + ] +}); + +// 로그 예시 +logger.info('Term explanation generated', { + term: 'RAG', + meeting_id: 'meeting_12345', + response_time_ms: 2300, + cache_hit: false, + related_docs_count: 5, + claude_tokens: { input: 1500, output: 320 } +}); +``` + +--- + +## 부록 + +### A. API 명세서 + +#### POST /api/rag/explain +**요청**: +```json +{ + "term": "RAG", + "meeting_id": "meeting_12345", + "context": { + "meeting_title": "주간 스크럼", + "date": "2025-01-20T14:00:00Z", + "participants": ["김민준", "박서연"], + "project_name": "회의록 시스템" + } +} +``` + +**응답**: +```json +{ + "term": "RAG", + "explanation": { + "definition": "Retrieval-Augmented Generation의 약자로...", + "context": "우리 팀은 회의록 시스템에 RAG를 적용하여...", + "usage_examples": ["..."], + "related_projects": ["..."], + "past_discussions": [...], + "references": ["doc_12345"] + }, + "metadata": { + "response_time_ms": 2300, + "cache_hit": false, + "related_docs_count": 5, + "confidence_score": 0.92 + } +} +``` + +### B. 배치 작업 스케줄 + +| 작업 | 주기 | 시간 | 설명 | +|------|------|------|------| +| 회의록 벡터화 | 실시간 | - | 회의 종료 후 즉시 | +| 위키 동기화 | 매일 | 새벽 2시 | Confluence API 호출 | +| 캐시 워밍 | 매일 | 새벽 3시 | 상위 50개 용어 캐싱 | +| 용어 사전 갱신 | 주간 | 일요일 새벽 1시 | 신규 용어 자동 추가 | +| 성능 리포트 생성 | 주간 | 월요일 오전 9시 | 주간 성능 분석 | + +--- + +## 변경 이력 + +| 버전 | 날짜 | 변경 내용 | 작성자 | +|------|------|-----------|--------| +| 1.0 | 2025-01-20 | 초기 구현방안 작성 | 박서연, 이준호, 홍길동 | +| 2.0 | 2025-01-20 | 하이브리드형 로드맵으로 최종 승인 | 전체 팀 | + +--- + +**문서 끝**