# 맥락기반 용어설명 구현방안

## 문서 정보
- **작성일**: 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<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)
```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 | 하이브리드형 로드맵으로 최종 승인 | 전체 팀 |

---

**문서 끝**
