---
id: rag-retrieval-pipeline
title: "RAG 검색 파이프라인"
category: "AI_and_ML"
status: "draft"
verification_status: "applied"
canonical_id: ""
aliases: ["RAG", "retrieval", "검색 증강 생성", "하이브리드 검색", "context budget", "rerank", "chunking", "orchestrator"]
duplicate_of: ""
source_trust_level: "A"
confidence_score: 0.92
created_at: 2026-06-13
updated_at: 2026-06-13
review_reason: ""
merge_history: []
tags: ["rag", "retrieval", "ai", "search", "embedding", "astraai"]
raw_sources: ["AstraAI/src/retrieval/index.ts", "AstraAI/src/retrieval/chunker.ts", "AstraAI/src/retrieval/scoring.ts"]
applied_in: ["AstraAI"]
github_commit: ""
---

# [[RAG 검색 파이프라인]]

## 🎯 한 줄 통찰 (One-line insight)
RAG 는 "질문에 답하기 전에 관련 지식을 찾아 컨텍스트에 넣는" 기법이며, AstraAI 의 오케스트레이터는 **질의 계획 → 다중 소스 병렬 검색 → 점수 정규화·재가중 → 토큰 예산 내 선택** 의 4단계로 brain 파일·5계층 메모리·최근 세션을 하나의 컨텍스트로 융합한다 [S1].

## 🧠 핵심 개념 (Core concepts)
1. **소스 융합(Fusion):** brain 파일(TF-IDF/하이브리드), 메모리 계층, 중기(최근 세션)를 각각 검색해 `RetrievalChunk[]` 로 모은다 [S1].
2. **점수 정규화:** 소스마다 점수 스케일이 달라, 소스별로 0~1 정규화 후 source 우선순위 가중치를 곱한다 [S1].
3. **재가중(Re-rank):** Actionability(현재 작업 상태 신호)와 Hierarchical(질의·문서 추상도 매칭)로 점수를 조정 [S1].
4. **토큰 예산(Context budget):** 모델 컨텍스트 한도 내에서 점수 높은 청크만 선택, 나머지는 drop [S1].
5. **섹션 청킹:** 긴 문서를 헤딩 경계로 쪼개 정밀도를 높이는 선택적 경로 [S2]. → [[TF-IDF 이중언어 스코어링]].

## 🧩 추출된 패턴 (Extracted patterns)
- **단계별 fusionLog:** 각 단계가 `fusionLog.push(...)` 로 무엇을 했는지 기록 — 검색이 왜 그 결과를 냈는지 추적·디버깅 가능 [S1].
- **`??` 로 의미 있는 0 보존:** `brainFileLimit ?? 8` — Knowledge Mix "모델 지식만" 모드가 명시적 0 을 보내면 검색을 건너뛴다(`|| 8` 이면 0이 8로 둔갑) [S1].
- **하이브리드 blend(sparse+dense):** TF-IDF 점수를 top 값으로 정규화하고 임베딩 cosine 과 `(1-α)·sparse + α·dense` 로 혼합. 벡터 없는 문서는 순수 TF-IDF 유지 [S1].
- **per-file cap:** 한 문서가 상위 슬롯을 독식하지 않게 파일당 청크 수를 3개로 제한 [S1].
- **운영 로그 제외:** 세션/메모리/회사 로그 폴더는 "지식"이 아니므로 검색에서 제외(`isOperationalPath`) — 노이즈·토큰 낭비 차단 [S1].
- **레슨 카드 가산:** 짧고 신호 강한 레슨 카드는 top-limit 밖이어도 추가로 끌어오고 1.4× 가중 [S1].

## 📖 세부 내용 (Details)
### 4단계 흐름 (`retrieve`)
```
① Query Planning  : tokenize → expandQuery(동의어 확장)
② Parallel Search : Brain(TF-IDF/하이브리드) + Memory 계층 + Medium-term(최근 세션)
③ Result Fusion   : normalizeScores(소스별 0~1 + source boost) → actionability/hierarchical re-rank
④ Context Budget  : selectWithinBudget(점수순, 토큰 한도 내) → lesson 청크 분리 추출
```
반환에는 선택/탈락 청크, 레슨 청크, 사용 토큰, fusionLog 가 포함된다 [S1].

### 하이브리드 검색의 스케일 함정 (주석에 기록된 실측 버그)
1. *모든* 후보를 maxTfidf 로 정규화해야 한다 — 벡터 있는 것만 0..1 로 줄이면 벡터 없는 후보의 raw 점수(≫1)가 상위를 독식해 blend 가 무효가 된다.
2. cosine 은 후보군 내 min-max 정규화 — 임베딩 모델은 무관 문서끼리도 cos 0.5~0.7 이 나와, 절대값 가산이 균일 노이즈로 sparse 정밀도를 흐린다 [S1].

### 성능 — mtime 인덱스
`getBrainTokenIndex` 는 파일 mtime 기준 영속 인덱스라, 변경 없는 파일은 재읽기·재토큰화하지 않는다. 큰 brain 에서 질의당 작업량이 O(전체 내용) → O(파일 수)로 떨어진다. 실제 디스크 읽기는 *선택된 파일* 의 발췌 추출 때만 발생 [S1].

### 평가 무결성
`rankBrainForEval` 은 프로덕션 `retrieve` 와 *동일한 scoring 경로*(`searchBrainFiles`)를 재사용한다 — recall@k/MRR 측정이 실제 검색 동작을 반영하도록 [S1].

## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)

| 검색 방식 | 장점 | 단점 | 언제 |
|---|---|---|---|
| TF-IDF (sparse) | 키워드 정확, 인덱스 가벼움, 설명가능 | 의미 유사 놓침 | 임베딩 엔진 없을 때 기본 |
| 임베딩 (dense) | 의미 유사 포착 | 무관 문서도 높은 cos, 비용 | 동의·환언 많은 질의 |
| 하이브리드 blend | 둘의 장점 결합 | 스케일 정규화 까다로움 | 임베딩 가용 시 권장 |
| 섹션 청크 | 긴 문서 정밀도↑ | 인덱스 크기↑ | 다주제 장문 brain |

## ⚖️ 모순 및 업데이트 (Contradictions & updates)
- **청크 vs 파일 단위:** 섹션 청킹은 정밀도를 높이지만 회귀 위험이 있어 파일 단위 경로와 분리(`chunkLevelRetrieval` 플래그)해 격리했다 — 점진 도입 전략.
- **재가중의 위험:** actionability/hierarchical 가중이 과하면 키워드 정합이 약한 문서가 떠오를 수 있다. 그래서 정규화 *후, 예산 선택 전* 에 적용해 영향 범위를 통제한다.

## 🛠️ 적용 사례 (Applied in summary)
- `AstraAI/src/retrieval/index.ts` — RetrievalOrchestrator 의 retrieve/searchBrainFiles/searchBrainChunks/normalizeScores 전체 [S1].
- `AstraAI/src/retrieval/chunker.ts` — 헤딩 경계 섹션 청킹(순수 함수) [S2].

## 💻 코드 패턴 (Code patterns)
```typescript
// 1) 의미 있는 0 보존 — Knowledge Mix "모델 지식만" 모드 (src/retrieval/index.ts)
const brainFileLimit = options.brainFileLimit ?? 8;   // ?? : 명시적 0 을 0으로 존중
const brainChunks = brainFileLimit > 0 ? this.searchBrainFiles(...) : [];

// 2) 소스별 정규화 + 우선순위 가중 (src/retrieval/index.ts)
for (const [, group] of groups) {
    const maxScore = Math.max(...group.map(c => c.score), 0.001);
    for (const c of group) c.score /= maxScore;        // 소스 내 0~1 정규화
}
const sourceBoost = { 'procedural-memory': 0.95, 'brain-memory': 0.9, 'episodic-memory': 0.7 /* ... */ };
for (const c of chunks) { c.score *= (sourceBoost[c.source] ?? 0.5); if (c.metadata.isLesson) c.score *= 1.4; }

// 3) 하이브리드 blend — 모든 후보를 같은 스케일로 (src/retrieval/index.ts)
const sparse = s.score / maxTfidf;
s.score = cos === null ? sparse : (1 - alpha) * sparse + alpha * ((cos - minCos) / span);
```

## ✅ 검증 상태 및 신뢰도
- **상태:** draft
- **검증 단계:** applied
- **출처 신뢰도:** A
- **신뢰 점수:** 0.92
- **중복 검사 결과:** 신규 생성 (New discovery)

## 🔗 지식 그래프 (Knowledge Graph)
- **상위/루트:** [[AstraAI 아키텍처 개요]]
- **관련 개념:** [[TF-IDF 이중언어 스코어링]], [[5계층 메모리 시스템]], [[Agent 오케스트레이터 분해]]
- **참조 맥락:** 로컬 LLM 이 검색 증강·컨텍스트 조립·점수 융합 코드를 설계할 때 참조.

## 📚 출처 (Sources)
- [S1] AstraAI/src/retrieval/index.ts — RetrievalOrchestrator(4단계, fusion, 하이브리드, 예산, 평가)
- [S2] AstraAI/src/retrieval/chunker.ts — 섹션 청킹 순수 함수

## 📝 변경 이력 (Change history)
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
