데이터 컨텍스트 보강 설계 - 100-hours-a-week/KTB4-1st-wiki GitHub Wiki
단계 5. 데이터/컨텍스트 보강 설계 (RAG)
1. 대상 판단
과제의 5개 서비스 유형(텍스트/비전/음성/이미지·영상생성/기타) 중 바꾸까는 텍스트 서비스에 해당한다. 음성·이미지생성·영상생성 관련 항목은 해당 기능이 없어 대상에서 제외한다.
| 기능 | RAG 적용 여부 | 사유 |
|---|---|---|
| 4. 챗봇 | O | 우리가 직접 구축·관리하는 정책 문서를 임베딩·검색해 답변 근거로 사용하는, 전통적 정의에 부합하는 RAG |
| 1. 사진 등록 | 대상 제외 | Visual RAG처럼 이미지/영상 DB를 구축해 유사 이미지를 검색하는 구조가 아니라, 업로드된 사진 자체만 직접 분석함 |
| 3. 가격검색 | 대상 제외 | 외부 정보를 활용하긴 하나, 우리가 구축한 지식 소스가 아니라 Claude 내장 web_search 도구를 그대로 호출하는 것. 임베딩·인덱싱 등 이 단계가 요구하는 설계 요소 자체가 존재하지 않아 RAG로 분류하지 않음 |
| 5. 스마트검색 | 대상 제외 | 최적화 후 LLM 생성이 사라지고 순수 임베딩 유사도 랭킹만 남아 "검색 증강 생성"의 정의에 해당하지 않음. 다만 이 단계에서 확정한 임베딩 모델을 기능5에도 그대로 재사용할 예정(3번 참고) |
| 2, 6 | 대상 제외 | 검색 없이 검증/생성만 수행하는 기능 |
2. 기능4 — 챗봇 RAG
전체 데이터 흐름도
flowchart TD
A["사용자 질문"] --> B["임베딩 모델로 질문 임베딩"]
B --> C["정책 문서 12개 섹션 벡터 인덱스(ChromaDB)에서 검색"]
C --> D["상위 2개 섹션 추출 (top-k retrieval)"]
D --> E["system prompt(prompt caching) + 검색된 섹션 + 대화이력 구성"]
E --> F["Claude sonnet 호출"]
F --> G["answer, action 응답"]
데이터/지식 소스
- 소스: 정책 문서 12개 섹션(서비스 개요, 계정정책, 그룹정책 등). 우리가 직접 작성·관리하는 텍스트 지식 베이스.
- 선택 이유: 챗봇이 근거 없이 지어내는 답변(hallucination)을 막기 위해, 반드시 이 문서 안의 내용만 근거로 답하도록 강제. 문서에서 못 찾으면 "정확한 답변을 찾지 못했어요" + 1:1 문의 유도로 답한다. 내부 팀 메모 성격의 1개 섹션은 사용자 노출용이 아니므로 임베딩 대상에서 제외.
검색·임베딩·인덱싱 구현
- 임베딩 모델:
dragonkue/multilingual-e5-small-ko-v2(확정)intfloat/multilingual-e5-small을 한국어 질의-문서 쌍으로 파인튜닝한 경량 모델(약 118M 파라미터, ~470MB)- 선택 근거:
- STS(단순 문장유사도)가 아니라 "질문으로 관련 문서 찾기" 검색 태스크에 맞춰 파인튜닝됨
- CPU로만 서빙하는 환경이라, 대형 모델(BGE-M3 등 560M급)보다 지연시간·RAM 부담이 훨씬 적음 — CPU는 GPU와 달리 파라미터 수에 비례해 연산시간이 늘어나 대형 모델의 불리함이 더 크게 작용함
- 같은 계열의 소형 파인튜닝 모델이 자신보다 2배 큰 범용 모델(
multilingual-e5-base)을 한국어 벤치마크에서 앞선 사례가 있어, "작지만 한국어 특화 튜닝된 모델"의 실효성이 뒷받침됨 - 정책 문서 12개, 향후 기능5(스마트검색) 후보군도 최대 300개 수준으로 규모가 크지 않아 대형 모델의 강점(대용량 코퍼스, 8192토큰급 긴 문서)이 발휘될 상황이 아님
- 기능5(스마트검색)에도 동일 모델을 재사용할 계획 — 모델 이원화 없이 AI 서버 리소스 절약
- 인덱싱 방식: ChromaDB — 서버 기동 시 정책 문서 12개를 임베딩해 컬렉션에 저장. 코사인 유사도로 검색하도록
hnsw:space: cosine명시 설정(ChromaDB 기본값은 L2 거리라 별도 설정 필요). 인메모리 클라이언트로 운용하며, 문서량이 늘거나 서버 재시작마다 재계산 비용을 아끼고 싶으면PersistentClient로 디스크 영속화 전환 검토 - 검색 방식: 질문 임베딩으로 인덱스 검색 → 상위 2개 추출
- 접두사 규약: E5 계열 모델 특성상 문서에는
passage:, 질문에는query:접두사를 붙여야 함(누락 시 성능 저하)
모델 통합 방법 (프롬프트 구성)
import chromadb
embedder = SentenceTransformer('dragonkue/multilingual-e5-small-ko-v2')
chroma_client = chromadb.Client() # 인메모리. 영속 저장이 필요하면 PersistentClient(path=...)로 교체
collection = chroma_client.create_collection(
name="policy_sections",
metadata={"hnsw:space": "cosine"}, # 코사인 유사도로 검색하도록 명시 (기본값 L2 아님!)
)
def _build_section_index():
texts = [f"passage: {s['title']}\n{s['content']}" for s in POLICY_SECTIONS]
embeddings = embedder.encode(texts, normalize_embeddings=True).tolist()
collection.add(
ids=[str(i) for i in range(len(POLICY_SECTIONS))],
embeddings=embeddings,
documents=[s["content"] for s in POLICY_SECTIONS],
metadatas=[{"title": s["title"]} for s in POLICY_SECTIONS],
)
_build_section_index()
def retrieve_top_k(message: str, k: int = 2) -> str:
query_emb = embedder.encode([f"query: {message}"], normalize_embeddings=True).tolist()
results = collection.query(query_embeddings=query_emb, n_results=k)
titles = results["metadatas"][0]
contents = results["documents"][0]
return "\n\n".join(f"[{t['title']}]\n{c}" for t, c in zip(titles, contents))
system=[
{
"type": "text",
"text": BASE_RULES, # 역할·출력형식 등 고정 규칙
"cache_control": {"type": "ephemeral"}, # prompt caching 적용
},
{
"type": "text",
"text": f"[관련 정책 문서]\n{retrieved_chunk}\n\n[이전 대화]\n{history_text}",
},
],
messages=[{"role": "user", "content": message}],
- 고정 규칙(
BASE_RULES)은 매 요청 동일하므로 캐싱 대상, 검색된 문서·대화이력만 매번 교체
도입 전후 예상 효과와 검증 계획
| 지표 | Before(정책 12개 전체 삽입) | After(top-2 검색 + 캐싱) |
|---|---|---|
| 입력 토큰 사용량 | 높음(12개 섹션 전체) | 낮음(2개 섹션만) [측정 예정 — compare.py 결과 삽입] |
| 응답 지연시간 | 상대적으로 김 | 짧음 [측정 예정] |
| 정답률(키워드 매칭 기준) | 기준값 | Before 대비 유지 여부 확인 [측정 예정] |
- 검증 도구:
compare.py— baseline(전체 삽입) vs optimized(RAG+캐싱)를 동일 질문셋으로 반복 호출해 지연시간·토큰·정답률 비교
3. 종합 정리
바꾸까에서 이 단계의 요구사항(자체 구축 지식 소스 + 임베딩/인덱싱 설계)에 부합하는 사례는 기능4 챗봇 하나다. 기능3(가격검색)도 외부 정보를 검색해 답변에 반영한다는 점은 유사하지만, 우리가 구축·관리하는 지식 베이스가 아니라 Claude 내장
web_search도구를 그대로 호출하는 것이라 이 단계가 요구하는 임베딩·인덱싱 설계 대상에는 해당하지 않는다고 판단해 제외했다.임베딩 모델은
dragonkue/multilingual-e5-small-ko-v2, 인덱싱은 chroma로 확정했다. 정책 문서가 12개뿐이고 CPU로만 서빙하는 환경이라, 대형 다국어 모델·별도 벡터DB 서버보다 경량 모델 + 라이브러리 기반 인덱싱이 비용·지연시간 면에서 더 합리적이라고 판단했다. 이 모델은 향후 기능5(스마트검색)의 물건 임베딩에도 동일하게 재사용할 계획이다.