# 맥락기반 용어설명 구현방안 ## 문서 정보 - **작성일**: 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 | 하이브리드형 로드맵으로 최종 승인 | 전체 팀 | --- **문서 끝**