mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 16:06:23 +00:00
- 전체 팀원 토의를 통한 하이브리드형(단계별 확장) 최적안 도출 - 데이터 수집/정제/벡터라이징 전략 수립 - 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 <noreply@anthropic.com>
30 KiB
30 KiB
맥락기반 용어설명 구현방안
문서 정보
- 작성일: 2025-01-20
- 작성자: AI Specialist 박서연, Backend Developer 이준호/이동욱, Architect 홍길동
- 버전: 2.0 (하이브리드형 - 단계별 확장 방식)
- 상태: 최종 승인
목차
개요
목적
회의록 작성자가 업무 지식이 없어도, 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. 데이터 정제 파이프라인
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) 불용어 제거
STOPWORDS = [
'그', '저', '것', '수', '등', '들', '및', '때문', '위해', '통해',
'하지만', '그러나', '따라서', '또한', '즉', '예를 들어'
]
def remove_stopwords(text):
tokens = text.split()
return ' '.join([t for t in tokens if t not in STOPWORDS])
2) 토큰화 (한국어)
from konlpy.tag import Okt
okt = Okt()
def tokenize_korean(text):
return okt.morphs(text, stem=True)
3) 정규화
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. 메타데이터 설계
{
"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 전략
목표: 회의록/문서를 의미 있는 단위로 분할하여 검색 정확도 향상
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 생성
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 저장
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 호출 코드
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<TermExplanation> {
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)
{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 2000,
"temperature": 0.3,
"system": "당신은 조직 내 전문용어를 쉽게 설명하는 전문가입니다...",
"messages": [
{
"role": "user",
"content": "아래는 검색된 관련 문서들입니다...\n용어: \"RAG\""
}
]
}
응답 (Response)
{
"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주)
목표: 회의록 기반 최소 기능 구현 및 사용자 테스트
구현 범위
- 회의록 DB 연동
- 용어 감지 엔진 (Trie 자료구조)
- OpenAI Embedding API 연동
- Pinecone 벡터 검색
- Claude API 호출 (기본 프롬프트)
- UI: 점선 밑줄 하이라이트, 바텀 시트 툴팁
성능 목표
- 응답 시간: 5초 이내
- 용어 감지 정확도: 70% 이상
- 관련 문서 정확도: 60% 이상
제약 사항
- 캐시 없음 (모든 요청 실시간 처리)
- 회의록만 검색 (위키, 문서, 이메일 미포함)
배포 전략
- Beta 테스트: 20명 (개발팀 10명, 기획팀 5명, 경영지원팀 5명)
- 피드백 수집: Google Forms 설문 + 주간 인터뷰
Phase 2: 성능 개선 (4주)
목표: 캐시 도입 + 위키 추가 + 하이브리드 검색
구현 범위
- Redis 캐시 레이어
- TTL: 자주 쓰이는 용어 7일, 드문 용어 1일
- Cache Warming: 상위 50개 용어 사전 캐싱
- 사내 위키 연동 (Confluence, Notion)
- 하이브리드 검색 (벡터 + 키워드)
- 벡터 유사도: 70% 가중치
- 키워드 매칭: 30% 가중치
- 프롬프트 최적화 (Few-shot learning)
성능 목표
- 응답 시간: 3초 이내 (캐시 히트 시 0.5초)
- 용어 감지 정확도: 85% 이상
- 관련 문서 정확도: 75% 이상
- 캐시 히트율: 60% 이상
배포 전략
- Beta 테스트 확대: 50명
- A/B 테스트: 캐시 vs 캐시 없음, 하이브리드 vs 벡터 단독
Phase 3: 고도화 (6주)
목표: 전체 데이터 통합 + 시맨틱 필터링 + 부서별 커스터마이징
구현 범위
- 프로젝트 문서 연동 (Google Drive, SharePoint)
- 이메일 연동 (Outlook, Gmail)
- 시맨틱 필터링
- 부서별 용어 우선순위
- 프로젝트별 문맥 가중치
- 2단계 캐싱
- L1: Redis (Hot data, TTL 7일)
- L2: CDN (Static explanations, TTL 30일)
- 용어 추천 시스템
- "이 용어를 사전에 추가할까요?" 제안
성능 목표
- 응답 시간: 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
# 매일 새벽 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. 하이브리드 검색
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
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. 자동 검증
용어 감지 정확도
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
설명 품질 평가
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점 | 관련 문서, 과거 논의 포함 여부 |
평가 프로세스
- 매 Sprint 종료 시 20개 샘플 평가
- 평가자: Beta 테스터 10명 (무작위 선정)
- 목표 점수: 80점 이상
운영 및 모니터링
1. 성능 메트릭
Prometheus 메트릭
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 규칙
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. 로깅 전략
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
요청:
{
"term": "RAG",
"meeting_id": "meeting_12345",
"context": {
"meeting_title": "주간 스크럼",
"date": "2025-01-20T14:00:00Z",
"participants": ["김민준", "박서연"],
"project_name": "회의록 시스템"
}
}
응답:
{
"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 | 하이브리드형 로드맵으로 최종 승인 | 전체 팀 |
문서 끝