🧊 LLM wiki 가이드북 Part 2
1 / 1
Part 2

쌓은 지식을 어떻게 찾아내나

LLM wiki + GraphRAG·하이브리드 검색을 처음부터 끝까지 — 원리는 직관적으로

Part 1에서 우리는 지식을 어떻게 쌓고 정리하는지 봤습니다. 그런데 노트가 수천 장 쌓이면, 정작 필요한 한 장을 어떻게 찾아낼까요? 우리 /search는 /knowledge-manager(자료를 정리해 주는 AI)가 노트에 달아둔 [[링크]]·태그를 지식 그래프(개념을 점, 관계를 선으로 이은 지도)로 바꾸고, 그 그래프 + 의미로 찾는 검색 + 단어로 찾는 검색을 한데 섞어(하이브리드) 답을 찾습니다. 이 파트는 그 안의 개념을 하나도 건너뛰지 않고 — 왜 필요한지, 어떻게 작동하는지, 숫자로는 어떻게 되는지 — 풀어 보여줍니다.
이 파트에서 배우는 것
  • 검색 한 번에 무슨 일이 벌어지는지 (큰 그림)
  • 의미로 찾기(임베딩) vs 단어로 찾기(BM25), 그리고 둘을 합치는 법(RRF)
  • 지식 그래프와 GraphRAG가 평범한 검색과 무엇이 다른지
  • 좋은 검색인지 숫자로 증명하는 법 — 그리고 실제 벤치마크 결과
읽는 법: 위 목차에서 아무 데나 눌러 뛰어도 되고, 그냥 쭉 내려 읽어도 됩니다. 용어가 처음이면 각 절 맨 위 비유만 읽어도 큰 그림이 잡혀요.
큰 그림

검색 한 번에 무슨 일이 벌어지나

그림 2-1. 검색 한 번의 전체 흐름 — 질문 → 의미·단어·그래프 → RRF → 리랭커 → Top-5
그림 2-1. 검색 한 번의 전체 흐름 — 질문 → 의미·단어·그래프 → RRF → 리랭커 → Top-5
이 장 한 줄: /search "MCP가 뭐야?" 한 줄이 답이 되기까지, 네 갈래로 찾아 → 공정하게 합치고 → 정밀 심사해 → Top-5를 냅니다. 다음 장들이 이 흐름의 단어를 하나씩 풉니다.
질문"MCP가 뭐야?"
→
4채널 검색의미·키워드·분해·엔티티
→
RRF 융합순위를 합산
→
리랭커정밀 재심사
→
Top-5+ 신뢰도

검색이라고 하면 보통 "단어가 들어간 문서 찾기"를 떠올립니다. 하지만 좋은 검색은 그보다 훨씬 많은 일을 합니다. 같은 뜻을 다른 단어로 쓴 글도 찾아야 하고("반려견"으로 물어도 "강아지" 글), 흔한 단어에 묻힌 핵심 문서를 위로 끌어올려야 하고, 여러 방식이 추천한 결과를 하나로 합쳐야 합니다. 우리 /search는 이걸 다섯 단계로 합니다.

  1. 네 갈래로 동시에 찾기. ㉠뜻으로(의미검색) ㉡단어 그대로(키워드검색) ㉢질문을 작은 질문으로 쪼개서 ㉣개념(엔티티) 매칭. 한 갈래만 쓰면 놓치는 걸 서로 메웁니다.
  2. 공정하게 합치기. 네 갈래가 각자 추천한 순위표를 RRF(순위 융합)로 합칩니다. 점수 척도가 제각각이어도 "순위"만 쓰니 안전합니다.
  3. 정밀 심사. 합쳐서 추린 상위 후보만 리랭커가 질문과 한 묶음으로 정독해 다시 줄세웁니다. 1차 서류전형 → 2차 면접.
  4. 결과 내기. 최종 Top-5 문서 + 신뢰도 4단계(high/medium/low/very_low). 여기까지가 검색의 일입니다.
  5. (선택) 답변 만들기. 원하면 그 Top-5를 근거로 LLM이 자연어 답까지 합성(기본 OFF). 이게 RAG의 'G(생성)' 부분 — 마지막 장에서.
읽는 법 — 3~11장이 위 단어들(RAG·임베딩·BM25·RRF·리랭커·그래프·지표)을 한 장에 하나씩 깊게 풉니다. 12장은 "왜 이 도구를 골랐나(+더 나은 대안)". 13~14장은 실제 24개 질문 검색 결과. 개념이 급하지 않으면 목차에서 바로 벤치마크로 건너뛰어도 됩니다.
미리 정직하게 — 그래프의 재료([[링크]]·태그)는 /knowledge-manager(AI)가 자료를 정리하며 만든 것입니다(직접 손으로 단 게 아닙니다). 런타임 인덱서는 그 AI가 만든 링크를 규칙대로(rule-based) 그래프 DB로 옮기기만 합니다(이 단계엔 LLM 없음). 한편 "인덱싱 때 LLM이 관계를 새로 추출"·"커뮤니티 LLM 요약" 같은 마이크로소프트식 GraphRAG의 일부는 아직 미작동이라 "GraphRAG 계열"로 부릅니다(8·9장에서 자세히).
개념 01

RAG — 오픈북 시험의 원리

한 줄: AI가 답하기 전에 관련 문서를 먼저 검색해서 그걸 근거로 답하게 하는 방식. 머릿속 기억이 아니라 "펴 놓은 책"을 보고 답한다.
🤔 왜 필요한가

거대 언어모델(LLM)은 학습할 때 본 지식을 신경망 가중치 안에 욱여넣습니다. 이걸 파라메트릭 메모리(parametric memory, 모델 속 기억)라고 합니다. 문제는 셋입니다. ①내 개인 지식(내 vault 메모)은 학습에 없었으니 모름. ②지식이 옛날 것이라 최신을 모름. ③근거 출처를 못 대니 그럴듯하게 지어내기 쉬움(환각, hallucination). 모델을 다시 학습시키는 건 비싸고 느립니다.

RAG(검색증강생성, Retrieval-Augmented Generation)는 이 셋을 한 번에 푸는 아이디어입니다. 답하기 전에 외부에서 관련 문서를 검색해 와서, 그 문서를 질문과 함께 모델에 넣어 줍니다. 모델은 "기억"이 아니라 "눈앞의 자료"를 보고 답합니다.

💡 비유 — 오픈북 시험. 암기 시험은 머릿속에 든 것만 쓸 수 있습니다(파라메트릭). RAG는 오픈북 시험입니다. 답을 쓰기 전에 교과서에서 관련 페이지를 펴 놓고, 그걸 보면서 답을 적습니다. 모르는 내용도 자료에 있으면 정확히, 출처까지 대며 답할 수 있습니다.

⚙️ 어떻게 작동하나 — R·A·G 세 글자
  1. R (Retrieval, 검색): 질문과 관련된 문서를 외부 저장소에서 찾는다. ← 이 가이드북의 거의 전부가 바로 이 단계 이야기입니다(우리 /search).
  2. A (Augmented, 증강): 찾아온 문서를 질문에 "붙여서" 모델에게 줄 입력을 만든다. ("아래 자료를 참고해 답하라: [문서1][문서2]… 질문: …")
  3. G (Generation, 생성): 모델이 그 자료를 근거로 자연어 답을 쓴다.
💪 강점과 한계

최신·개인 지식을 반영하고, 출처를 제시해 환각을 줄이며, 재학습 없이 지식만 갈아끼울 수 있습니다. 다만 답 품질이 검색 품질에 종속됩니다. 검색이 엉뚱한 문서를 가져오면 모델은 그 위에 그럴듯한 틀린 답을 씁니다("garbage in, garbage out"). 그래서 RAG의 핵심은 사실 '생성'보다 '검색'입니다 — 이 가이드북이 검색에 집중하는 이유입니다.

우리 적용 — /search는 우리 vault에 대한 RAG의 R(검색)입니다. G(생성)는 옵션으로 켜고 끕니다(기본 OFF). 즉 평소엔 "관련 문서 Top-5"를 돌려주고, 원할 때만 그걸 LLM이 자연어 답으로 합성합니다. (논문 원전: Lewis 외 2020, arXiv:2005.11401.)
흔한 오해 — "RAG = 챗봇에 검색 붙인 것"이 아닙니다. RAG는 검색 결과를 모델 입력에 넣는 구조 자체를 말합니다. 검색이 약하면 RAG도 약합니다. 그래서 좋은 RAG = 좋은 검색기 + 정직한 모델.
개념 02

임베딩 & Dense 검색 — 의미를 좌표로

그림 2-2. 임베딩 — 의미를 좌표로, 비슷한 뜻은 가까이 모인다
그림 2-2. 임베딩 — 의미를 좌표로, 비슷한 뜻은 가까이 모인다
한 줄: 문장을 수백 개 숫자(벡터)로 바꿔 "의미 지도" 위 한 점으로 찍는다. 뜻이 가까우면 점도 가깝다 → 단어가 달라도 의미로 검색.
🤔 왜 필요한가

키워드 검색만으로는 "반려견 키우는 법"을 물었을 때 "강아지 기르기" 글을 못 찾습니다. 글자가 다르니까요. 사람은 두 문장이 같은 뜻인 걸 압니다. 컴퓨터도 그렇게 하려면 의미를 비교 가능한 형태로 바꿔야 합니다. 그게 임베딩입니다.

⚙️ 어떻게 작동하나

임베딩(embedding)은 문장을 고정 길이 숫자 배열(벡터)로 바꾼 결과입니다. 우리 모델은 한 문장을 384개 숫자로 만듭니다. 이 숫자들은 사람이 정한 게 아니라, 신경망이 방대한 글을 학습하며 "비슷한 맥락에 쓰이는 문장은 비슷한 숫자가 되도록" 스스로 익힌 결과입니다.

💡 비유 — 의미 지도. 모든 문장을 거대한 지도 위 한 점으로 찍는다고 상상하세요. "강아지"와 "반려견"은 글자는 달라도 지도상 바로 옆 동네에 찍힙니다. "강아지"와 "세금 신고서"는 지도 반대편에 찍힙니다. 질문도 점으로 찍은 뒤, 그 점에서 가까운 글들을 찾는 게 의미(Dense) 검색입니다.

"가깝다"는 보통 코사인 유사도로 잽니다. 두 벡터가 가리키는 방향이 얼마나 비슷한지를 봅니다(크기가 아니라 방향). 같은 방향이면 1.0, 직각이면 0, 반대면 -1.

cos(질문, 문서) = (질문·문서) / (|질문| × |문서|)두 벡터의 내적을 각자의 길이로 나눈 값 = 방향의 일치도. 1에 가까울수록 의미가 가깝다.
📐 'Dense(밀집)'라는 이름

이 벡터를 Dense(밀집) 벡터라 부릅니다. 384칸이 거의 전부 0이 아닌 값으로 빽빽이 차 있기 때문입니다. 다음 장에 나올 BM25의 'Sparse(희소)' 벡터(대부분 0)와 정확히 대비됩니다 — 이 둘의 차이가 하이브리드 검색의 출발점입니다.

💪 강점과 한계

말바꿈·동의어·번역에 강합니다("자동차"↔"승용차"↔"car"). 다만 정확한 고유명사·코드·아주 드문 용어에는 의외로 약합니다(임베딩이 그 단어를 뭉뚱그려 비슷한 것들과 섞어버림). 긴 문서는 한 점으로 압축하며 디테일이 뭉개집니다.

우리 적용 — 로컬 모델 paraphrase-multilingual-MiniLM-L12-v2로 노트·엔티티를 384차원 벡터로 만듭니다. LLM이 아니라 작고 빠른 전용 모델이라 무료·즉시·다국어(한/영)입니다. 노트는 제목·태그·본문 앞 500자를 임베딩합니다. (왜 이 모델인지, 더 좋은 건 없는지는 12장에서 깊게 다룹니다. 논문 계보: Karpukhin 외 2020 DPR, arXiv:2004.04906.)
흔한 오해 — "임베딩 = ChatGPT 같은 LLM"이 아닙니다. 임베딩 모델은 글을 숫자 벡터로 바꾸기만 하는 작은 전용 모델로, 답을 생성하지 않습니다. 그래서 빠르고 쌉니다.
개념 03

Sparse & BM25 — 단어를 정직하게 세기

한 줄: 의미가 아니라 단어 그대로 매칭하되, "많이 나옴(TF)·희귀함(IDF)·문서 길이"를 똑똑하게 보정해 점수를 매기는 표준 공식. 검색의 50년 주력.
🤔 왜 필요한가

"이 문서가 이 질문에 얼마나 맞나"를 단어로 답하는 가장 오래된 질문입니다. Ctrl+F는 단어가 "있나/없나"만 봅니다. 하지만 우리는 얼마나 관련 있나를 점수로 줄세워야 합니다. 그 점수 공식의 사실상 표준이 BM25입니다(검색엔진·엘라스틱서치 등이 다 씁니다).

BM25는 순진한 방법이 왜 실패하는지를 짚으며 세 번 고쳐나가면 가장 잘 이해됩니다.

1️⃣ TF — 단어가 많이 나오면? (단, '포화')

첫 직관: 질문 단어가 문서에 많이 나올수록 관련 높다(TF, Term Frequency). 맞습니다. 그런데 함정이 있습니다 — "강의 강의 강의 강의…"를 30번 도배한 문서가 3번 자연스럽게 쓴 문서보다 10배 관련 높을까요? 아니죠.

그래서 BM25는 TF를 포화(saturation)시킵니다. 처음 몇 번은 점수가 쑥 오르지만, 곧 천장에 수렴해 더 나와도 거의 안 오릅니다.

포화된 TF = TF / (TF + k1)k1 ≈ 1.2. TF가 1→3일 땐 점수가 크게 오르지만, 8→30일 땐 거의 그대로. "충분히 나왔으면 그만"이라는 상식을 수식으로.
2️⃣ IDF — 흔한 단어는 변별력이 없다

둘째 문제: "그리고", "방법" 같은 단어는 거의 모든 문서에 있습니다. 이런 흔한 단어가 많이 나온다고 관련 높은 게 아닙니다. 반대로 "가나다정밀" 같은 희귀한 단어가 들어있으면 그 문서는 거의 확실히 관련 있습니다. (예시에 쓰인 기업명 ‘가나다정밀’은 설명을 위한 가상의 이름입니다)

그래서 IDF(역문서빈도)로 단어마다 가중치를 줍니다 — 전체 문서 중 그 단어가 나오는 문서가 적을수록 가치↑.

IDF(단어) ≈ log( 전체 문서 수 / 그 단어가 든 문서 수 )"그리고"(거의 모든 문서) → log(1에 가까움) → ≈ 0(무시). "가나다정밀"(5개 문서뿐) → 큰 값. 희귀할수록 정보량이 크다.
3️⃣ 길이 정규화 — 긴 문서가 유리하면 안 된다

셋째 문제: 5,000단어짜리 긴 문서는 짧은 문서보다 모든 단어를 더 많이 담습니다. 그냥 두면 긴 문서가 무조건 유리해집니다. 그래서 BM25는 문서 길이를 평균 길이와 비교해 보정합니다(파라미터 b≈0.75). 평균보다 긴 문서는 TF 점수를 깎고, 짧은 문서는 살려줍니다.

🧮 셋을 합치면
점수(문서) = Σ질문 단어 [ IDF(단어) × 포화·길이보정된 TF ]질문의 각 단어마다 (희귀도 × 적당히-나온-정도)를 구해 전부 더한다. 희귀한 핵심 단어가 적당한 밀도로 든 짧은 문서가 이긴다.
📐 숫자로 끝까지 — "단어 많이"가 왜 1등이 아닌가

질문: 가나다정밀 강의. 두 문서를 비교합니다.

문서길이"가나다정밀""강의"
A 짧은 강의 노트200 단어3회2회
B 거대 종합 MOC3,000 단어8회12회

순진한 셈이면 B 압승(8+12 > 3+2). BM25는 세 보정을 겁니다:

① IDF — "가나다정밀"은 전체 5개 문서에만 → 큰 값(예 ≈ 6.2). "강의"는 500개 문서에 흔함 → 작은 값(예 ≈ 0.7). 즉 "강의"가 12번 나와도 점수에 거의 기여 못 함. ② 포화 — "가나다정밀" 8회의 포화 TF = 8/(8+1.2)=0.87, 3회 = 3/(3+1.2)=0.71. 8회가 3회의 2.6배가 아니라 1.2배뿐. ③ 길이 — B는 3,000단어(평균의 ~5배)라 TF 점수에 페널티. A는 짧아 살아남음. → 핵심 단어 점수: A ≈ 6.2 × 0.71 × (길이보너스) , B ≈ 6.2 × 0.87 × (길이페널티)

결과: 희귀 핵심 단어("가나다정밀")의 밀도가 높고 짧은 문서 A가 더 높게 나올 수 있습니다. "단어를 많이 담은 문서"가 아니라 "핵심 단어를 군더더기 없이 담은 문서"가 이깁니다.

📐 'Sparse(희소)'라는 이름

BM25식 검색을 Sparse(희소) 검색이라 부릅니다. 문서를 "사전의 모든 단어 = 한 칸"인 거대한 벡터로 본다면, 한 문서엔 그중 몇 칸만 켜지고 나머지는 전부 0이라서 텅 빈(희소) 벡터가 되기 때문입니다. 앞 장 Dense(밀집, 거의 다 채워짐)와 정반대입니다.

💪 강점과 한계

정확한 고유명사·제품명·코드·드문 전문용어에 매우 강합니다(임베딩이 약한 바로 그 지점). 하지만 동의어·말바꿈에는 약합니다 — "반려견"으로 찾으면 "강아지"만 쓴 문서를 못 찾습니다. 그래서 다음 장의 하이브리드(Dense+Sparse)가 필요합니다.

우리 적용 — SQLite의 FTS5 trigram 채널(4채널 중 가중치 0.4로 가장 큼)입니다. trigram은 글자를 3개씩 잘라 색인하는 방식인데, 한국어처럼 띄어쓰기·형태소가 까다로운 글에서 부분 문자열 매칭에 유리합니다. 다만 trigram은 2글자 미만(예 "AI", "팀")은 색인 못 해, 코드가 그런 짧은 토큰엔 LIKE 보조 검색을 둡니다. (코드: graphrag_core.py 검증 — 손석희. 원전: Robertson & Zaragoza 2009.)
흔한 오해 — "BM25 = TF-IDF"가 아닙니다. TF-IDF는 단순히 (빈도 × 희귀도)지만, BM25는 거기에 TF 포화와 문서 길이 정규화를 더한 것이 핵심 차별점입니다. 이 둘이 없으면 도배 문서·긴 문서가 부당하게 이깁니다.
개념 04

ANN & HNSW — 수만 점에서 빨리 찾기

한 줄: 의미 검색에서 "가장 가까운 점"을 다 비교하면 느리다. 근사(ANN)로 거의 가까운 점을 훨씬 빨리 찾는 기법. 단 우리는 규모가 작아 안 씁니다(정직).
🤔 왜 필요한가

2장의 의미 검색을 다시 떠올리면, 질문 벡터에서 가장 가까운 문서 벡터를 찾아야 합니다. 가장 정확하게 하려면 전부 하나씩 비교(brute-force)합니다 — 우리 엔티티 7,281개면 질문마다 7,281번 비교. 이건 우리 규모에선 순식간이지만, 벡터가 수백만~수십억 개인 대형 서비스에선 한 번 검색에 수 초가 걸립니다.

⚙️ ANN과 HNSW

ANN(근사 최근접 이웃, Approximate Nearest Neighbor): "정확히 1등"을 포기하는 대신 "거의 1등"을 훨씬 빠르게 찾는 기법들의 총칭입니다. 약간의 정확도를 속도와 맞바꿉니다.

HNSW(계층적 탐색 가능한 작은 세계 그래프): 가장 널리 쓰이는 ANN 인덱스입니다. 점들을 여러 층의 지름길 그래프로 연결해 둡니다. 위층은 듬성듬성(멀리 점프), 아래층은 촘촘(정밀 탐색). 검색은 맨 위층에서 대충 가까운 곳으로 점프 → 한 층 내려가 더 좁히기 → … → 맨 아래층에서 정밀 탐색으로 끝냅니다.

💡 비유 — 고속도로 → 골목. 다른 도시 목적지에 갈 때 모든 길을 보지 않습니다. 고속도로(위층)로 대략의 지역까지 간 뒤, 국도(중간층)로 동네를 좁히고, 골목(아래층)에서 정확한 집을 찾습니다. 지하철 급행 → 완행 환승과 같습니다.

덕분에 비교 횟수가 전체(N)에서 로그(log N) 수준으로 줄어, 수백만 점에서도 밀리초 안에 찾습니다.

💪 강점과 한계

대규모에서 압도적으로 빠릅니다. 하지만 근사라서 가끔 진짜 1등을 놓칩니다(속도↔정확도 trade-off). 또 인덱스를 메모리에 올리고 관리하는 운영 부담이 있습니다.

우리 적용 — 미사용 (정직). 우리 규모(노트 ~3,700·엔티티 ~7,300)에선 그냥 전부 정확 비교(exact cosine)가 충분히 빠릅니다(검색 p50 ~138ms). 근사 인덱스를 쓰면 오히려 정확도만 잃고 복잡도만 늡니다. "대규모 ANN 인덱스를 쓴다"는 우리에 해당하지 않습니다. HNSW는 개념으로만 알아두면 됩니다. (원전: Malkov & Yashunin 2018, arXiv:1603.09320.)
흔한 오해 — "HNSW = 정확 검색"이 아닙니다. 이름 그대로 근사(approximate)입니다. 정확함이 필요하고 규모가 작으면(우리처럼) brute-force가 더 정확하고 단순합니다.
개념 05

하이브리드 & RRF — 공정하게 합치기

그림 2-3. RRF — 여러 검색의 순위를 공정하게 하나로 합치기
그림 2-3. RRF — 여러 검색의 순위를 공정하게 하나로 합치기
한 줄: 의미검색(Dense)과 키워드검색(Sparse)은 약점이 정반대 → 같이 돌린다. 그런데 점수 척도가 달라 그냥 못 더한다 → 순위(rank)만으로 합치는 RRF.
🤔 왜 합치나

2~3장에서 봤듯 Dense와 Sparse는 약점이 정확히 반대입니다. 한쪽이 놓치는 걸 다른 쪽이 잡습니다. 그래서 둘(실제로는 네 채널)을 같이 돌려 결과를 합치는 게 하이브리드 검색입니다.

질문 유형Dense(의미)Sparse(BM25)
"반려견" → "강아지" 글강함약함
"가나다정밀" 정확 매칭약함강함
코드·제품명·드문 용어약함강함
번역·말바꿈강함약함
🧩 합치는 게 왜 어려운가

두 검색의 점수 척도가 완전히 다릅니다. 의미 유사도는 0~1, BM25는 0~수십. 그냥 더하면 BM25가 항상 이깁니다. 점수를 정규화(0~1로 스케일)하는 방법도 있지만, 한 채널에 이상치 하나만 있어도 전체가 흔들립니다.

⚙️ RRF — 점수 말고 순위만

RRF(역순위 융합, Reciprocal Rank Fusion)의 발상은 단순하고 강력합니다. 점수는 버리고 순위만 쓴다. 각 채널에서 k등인 문서에게 1/(60+k)점을 주고, 채널들끼리 더합니다.

RRF(문서) = Σ채널 1 / (60 + 그 채널에서의 순위)1등 → 1/61 ≈ 0.0164, 2등 → 1/62, … 뒤로 갈수록 완만히 감소. 점수 척도가 달라도 "순위"는 공통 언어라 안전하게 합쳐진다.
💡 비유 — 평론가 합의. 영화를 여러 평론가가 매겼습니다. 누구는 박하게(최고 6점), 누구는 후하게(최고 10점) 줍니다. 점수를 그냥 더하면 후한 평론가가 결과를 지배합니다. 그래서 점수는 버리고 각자의 "1등·2등·3등"만 모아 종합 순위를 냅니다. 이게 공정합니다.

왜 상수가 60일까요? 1등과 2등의 점수 차가 지나치게 벌어지지 않게 완충하는 역할입니다(작으면 1등이 과하게 지배). 또 새 채널을 끼워 넣어도 기존 순위가 안 망가집니다 — 각 채널이 독립적으로 순위만 내면 되니까요.

📐 숫자로 — "여러 채널에서 고루 상위"가 "한 채널 1등"을 이긴다
문서DenseSparse분해엔티티RRF 합
X 두루 상위2등1등5등3등0.064
Y 한 채널만 1등1등———0.016
X = 1/(60+2) + 1/(60+1) + 1/(60+5) + 1/(60+3) = 0.0161 + 0.0164 + 0.0154 + 0.0159 ≈ 0.0638 Y = 1/(60+1) = 0.0164 (다른 채널엔 안 떴으니 0)

한 채널에서만 1등인 Y보다, 여러 채널이 동시에 추천한 X가 약 4배 높습니다. "여러 관점이 합의한 문서"를 신뢰하는 것 — 이게 RRF의 본질입니다.

🛠️ 우리의 4채널

우리는 두 개가 아니라 네 채널을 RRF로 합칩니다. 각 채널에 가중치를 곱해 합산합니다.

채널무엇으로 찾나가중치
Dense 의미문장 의미 벡터(MiniLM)0.30
Sparse 키워드FTS5/BM25 어휘0.40
Decomposed 분해질문을 작은 질문들로 쪼개 검색0.15
Entity 엔티티그래프 엔티티 벡터 매칭0.15
우리 적용 — 4채널 RRF, k=60. 코드와 1:1로 정확히 일치합니다(검증 완료). 이후 LIKE 보조검색·커뮤니티 가산을 거쳐 다음 장 리랭커로 넘어갑니다. (원전: Cormack 외 2009, SIGIR.)
흔한 오해 — "RRF = 점수 평균"이 아닙니다. RRF는 점수를 아예 안 보고 순위만 씁니다. 이게 서로 다른 척도의 검색기를 안전하게 섞는 비결입니다.
개념 06

리랭커 — 마지막 정밀 심사

한 줄: 빠른 1차 검색이 추린 후보 몇 개를, 질문과 문서를 한 묶음으로 같이 읽는 정밀 모델로 다시 줄세운다. 느리지만 정확 → 소수 후보에만.
🤔 왜 한 번 더 거르나

2장의 임베딩 검색은 빠릅니다. 비결은 질문과 문서를 각자 따로 벡터로 만들어 두고(미리 계산) 비교하기 때문입니다. 이런 방식을 bi-encoder(두 개를 따로 인코딩)라 합니다. 빠른 대신, 질문과 문서가 서로를 보며 판단하지 못해 미묘한 관련성을 놓칩니다.

⚙️ Cross-encoder — 함께 읽기

리랭커(reranker)는 보통 cross-encoder입니다. 질문과 문서를 하나로 이어 붙여 한 모델에 같이 넣고, "이 둘이 얼마나 맞는지"를 직접 점수 냅니다. 질문과 문서가 서로를 참고하며 판단하니 훨씬 정밀합니다.

bi-encoder (1차 검색)cross-encoder (리랭커)
방식질문·문서 따로 벡터화질문+문서 같이 입력
속도빠름(미리 계산)느림(매번 계산)
정밀도보통높음
쓰는 곳전체에서 1차 후보 추리기추려진 소수만 재정렬
💡 비유 — 서류전형 → 면접. 수천 명을 다 면접할 순 없습니다. 1차로 서류(임베딩·BM25, 빠름)로 대량을 거르고, 통과한 소수만 면접(cross-encoder, 정밀)으로 최종 줄세웁니다. 비싼 정밀 심사를 꼭 필요한 후보에만 쓰는 거죠.

💪 강점과 한계

1차 검색이 대충 끌어올린 후보의 순서를 크게 개선합니다(논문 기준 MRR@10 +27%). 하지만 느려서 전체에는 못 씁니다. 또 1차 검색이 애초에 못 끌어올린 문서는 리랭커도 살릴 수 없습니다(없는 후보는 못 고름).

우리 적용 — 4채널 RRF 결과를 BAAI/bge-reranker-base cross-encoder가 재채점한 뒤, 커뮤니티·중심성 보강을 거쳐 Top-5를 냅니다. (원전: Nogueira & Cho 2019, arXiv:1901.04085.)
정직한 실험 일화 — 더 큰 다국어 리랭커 bge-reranker-v2-m3로 바꿔봤더니(이전 R10 실험), 오히려 top-1 정확도가 8→7로 퇴행해 폐기했습니다. "더 큰 모델 = 항상 더 좋음"이 아니라는 산 증거입니다. 12장에서 재실험 가치를 다시 따집니다.
개념 07

지식 그래프 & 커뮤니티

그림 2-4. 지식 그래프 — 점(개념)·선(관계), 색으로 묶인 커뮤니티
그림 2-4. 지식 그래프 — 점(개념)·선(관계), 색으로 묶인 커뮤니티
한 줄: 개념을 점(엔티티), 관계를 선(relation)으로 이은 지도. 우리는 이 선을 AI(/knowledge-manager)가 자료를 정리하며 단 [[링크]]·태그에서 가져온다 — 지식 정리와 검색이 한 AI 파이프라인.
🤔 왜 그래프인가

지금까지(2~7장)는 "질문과 비슷한 문서 찾기"였습니다. 하지만 어떤 질문은 관계를 묻습니다 — "X가 무엇과 연결돼 있지?", "이 주제들이 어떻게 이어지지?". 문서를 따로따로 보면 답이 안 나옵니다. 지식 그래프는 개념·인물·문서를 점(엔티티)으로, 그 사이 연결을 선(관계)으로 그려 "이어짐"을 직접 다룹니다.

🏛️ 그래프의 뼈대 — 개념틀(TBox) + 사실(ABox)

지식 그래프는 두 층입니다. TBox(개념틀)는 "세상에 어떤 종류가 있고 어떻게 연결될 수 있나"를 정한 설계도예요(예: '사람'·'프로젝트'가 있고, '사람—참여—프로젝트' 연결이 가능하다). ABox(사실)는 그 틀에 담긴 실제 데이터고요(예: '재경—참여—패스트캠 강의'). 합치면 TBox(틀) + ABox(사실) = 지식 그래프입니다.

우리 예시(참고용 실값): 우리 그래프의 설계도(config)는 14가지 개념 종류 · 13가지 관계 · 7개 규칙(공리)으로 짜여 있어요. 이 숫자는 우리 시스템의 예시일 뿐입니다 — 여러분 도메인에 맞게 정하면 돼요(회사 자료라면 '부서'·'제품'·'고객' 같은 종류로).
⚙️ 우리는 선을 어디서 얻나 — 두 단계로 나눠 보기

여기가 가장 흔히 오해하는 지점입니다. ① 링크를 "만드는" 단계(지식 정리)와 ② 링크를 "그래프로 옮기는" 단계(인덱싱)를 꼭 나눠야 합니다.

  1. ① 링크 저작 = AI가 한다. 자료를 /knowledge-manager(LLM 에이전트)로 정리하면, AI가 내용을 읽고 관련 노트끼리 [[링크]]를 걸고 #태그를 답니다. 즉 "무엇이 무엇과 연결되나"(그래프의 구조)를 AI가 정합니다. (사용자가 손으로 위키링크를 다는 게 아닙니다.)
  2. ② 인덱싱 = 규칙(rule)이 한다. 런타임 인덱서(entity_extractor.py)는 그 AI가 달아둔 링크·태그를 정해진 규칙대로 그래프 DB로 옮깁니다 — [[위키링크]]→cites, #태그→belongs_to, 같은 문장 동시등장→co_occurs. 이 옮기는 단계엔 LLM이 전혀 없습니다.
💡 비유 — AI 사서가 그린 관계도를, 기계가 그대로 받아쓰기. 관계도(어디가 어디로 연결되나)는 AI(/knowledge-manager)가 그립니다. 인덱서는 그 관계도를 한 글자도 안 바꾸고 DB로 받아쓰기만 합니다. 그래서 "인덱싱은 rule-based"는 맞지만, "그래프 구조를 사람·규칙이 만들었다"는 틀립니다 — 구조를 만든 건 AI입니다.
실측(2026-06-07) — 엔티티 7,281개 · 관계 15,010개(cites 13,800 + belongs_to 1,210) + 동시등장 5,551(co_occurs) · 커뮤니티 9,100개. 모두 confidence 1.0/0.9/0.7의 규칙 기반 전사(轉寫) — 단, 그 재료인 링크·태그는 AI(KM ingest)의 산출물입니다.
👥 커뮤니티 탐지 & Louvain

그래프에는 촘촘히 연결된 점 무리가 자연스레 생깁니다. 이걸 자동으로 묶는 게 커뮤니티 탐지이고, 가장 널리 쓰는 알고리즘이 Louvain입니다(모듈러리티라는 "안은 빽빽, 밖은 성김" 지표를 최적화). 우리는 4계층(C0~C3)으로 묶습니다.

💡 비유 — SNS 동아리. 서로 팔로우·댓글을 많이 주고받는 사람들이 자연스레 '동아리'로 묶이는 것과 같습니다. 알고리즘이 "누가 누구와 빽빽이 이어졌나"만 보고 무리를 찾아냅니다.

검색에서는 "이 커뮤니티에 속한 문서"라는 신호를 가산점으로 씁니다(관련 주제 묶음을 함께 끌어올림).

흔한 오해 — 우리의 강한 그래프(엔티티·관계·커뮤니티)는 실재하지만, "LLM이 각 커뮤니티를 요약해 전역 질문에 답한다"는 부분은 아직 미작동입니다(다음 장). 그래프가 있다 ≠ MS GraphRAG의 모든 기능이 있다.
개념 08

GraphRAG Local / Global — 우리의 정직한 위치

한 줄: GraphRAG에는 이웃을 보는 Local과 전체를 요약·종합하는 Global(Map-Reduce)이 있다. 우리는 Local 쪽 구조는 갖췄지만 Global은 아직 placeholder → "GraphRAG 계열".
⚙️ 두 가지 질문, 두 가지 방식

마이크로소프트가 2024년 정리한 GraphRAG는 질문을 두 종류로 나눕니다.

  1. Local(국소) 질문 — "X가 무엇과 연결됐지?" 특정 엔티티의 이웃을 그래프에서 탐색해 답합니다. 범위가 좁고 구체적.
  2. Global(전역) 질문 — "내 지식 전체의 큰 주제는?" 이건 문서 몇 개로 안 됩니다. 먼저 커뮤니티마다 LLM이 요약을 만들고(Map), 그 요약들을 다시 종합해(Reduce) 답합니다. 이 Map-Reduce 요약이 MS GraphRAG의 시그니처입니다.
💡 비유 — 동네 길 묻기 vs 인구 추세 묻기. Local은 "이 동네에서 약국이 어디?"(한 곳만 보면 됨). Global은 "우리나라 인구 추세는?"(지역별로 집계 → 전국 합산해야 답이 나옴). 후자가 Map-Reduce입니다.

🧭 우리는 어디까지 왔나 (정직)

우리는 그래프(엔티티·관계·커뮤니티)와 Local 탐색 구조는 실제로 갖췄습니다. 단, MS GraphRAG의 시그니처 중 인덱싱 시점의 LLM 작업은 아직 placeholder(빈 껍데기)입니다 — ①인덱서가 글을 다시 읽어 LLM으로 관계를 추출하는 부분(우리 인덱서는 그 대신 AI가 ingest 때 달아둔 링크·태그를 규칙으로 옮김), ②커뮤니티를 LLM이 문장으로 요약하는 부분(현재 요약은 "구성원 나열" 자동 라벨 9,100개 = LLM 요약 0건), ③전역 Map-Reduce 종합. 주의: 그래프의 링크 자체는 AI(KM ingest)가 만든 것이고, "LLM이 없다"는 인덱싱·요약 단계에 한정된 이야기입니다.

그래서 "GraphRAG 계열"이라 부릅니다. "MS GraphRAG와 동등"이라고 하면 과장입니다. 실재(강점): AI(KM ingest)가 만든 고품질 링크·태그 그래프 + 4채널 하이브리드 + 리랭커. 인덱싱 단계 미작동: 인덱스-시점 LLM 관계추출·커뮤니티 LLM 요약·전역 Map-Reduce. 이 정직한 구분이 이 가이드북 전체의 원칙입니다. (원전: Edge 외(MS) 2024, arXiv:2404.16130.)
왜 굳이 정직하게? 우리 벤치(13~14장)가 보여주듯, 약한 기능을 "있다"고 쓰면 그 위에 잘못된 기대가 쌓입니다. 갖춘 것과 아닌 것을 명확히 해야 다음에 무엇을 보강할지(12·15장)가 보입니다.
개념 09

평가 지표 — 숫자로 증명하기

한 줄: "검색이 잘 됐다"를 느낌이 아니라 숫자로 증명한다. hit@5(성공/실패)·precision@5(추천이 깨끗한가)·MRR(정답을 얼마나 위에 올렸나)·coverage(빈손 아닌가)를 같이 본다.
⚙️ 네 가지 지표, 각각 다른 질문
  1. hit@5 — 상위 5개 안에 정답이 하나라도 들어갔나(예/아니오). 24개 질문 중 몇 개 성공인지로 봅니다(우리 = 10/24). "찾았나/못 찾았나"의 기본 척도.
  2. precision@5 — 상위 5개 추천 중 정답(gold) 비율. 2개가 정답이면 2/5 = 0.4. "추천 5개가 얼마나 깨끗한가."
  3. MRR(평균 역순위) — 첫 정답이 몇 등에 나오나 → 1/등수의 평균. 1등이면 1.0, 3등이면 0.33. "정답을 얼마나 위로 올렸나."
  4. coverage — 검색이 결과를 하나라도 돌려준 비율(우리 = 1.0, 한 번도 빈손 아님). ⚠️ 주의: "정답을 맞췄나"는 coverage가 아니라 hit@5가 봅니다. 둘은 다릅니다.
📐 숫자로 — 우리 실제 질문으로 MRR 계산
질문첫 정답 등수MRR 기여 = 1/등수
Q01 GraphRAG1등1 / 1 = 1.00
Q12 프롬프트 설계 영향2등1 / 2 = 0.50
Q09 Anthropic AI Safety3등1 / 3 = 0.33
Q04 Claude Code 스킬못 찾음0
이 넷만 평균 = (1.00 + 0.50 + 0.33 + 0) / 4 = 0.46 24개 전체 평균 = 우리 MRR 0.307 (못 찾은 질문이 0으로 들어가 평균을 끌어내림) precision@5도 같은 식: Q01은 top5 중 2개 정답 → 0.4 / 전체 평균 = 0.108

한 지표만 보면 안 됩니다. 같은 "정답 1개 찾음"이라도 1등에 올렸으면(MRR 1.0) 5등에 올린 것(MRR 0.2)보다 훨씬 나은 검색입니다. hit@5는 이 차이를 못 봅니다 — 그래서 함께 읽습니다.

우리 적용 — 13장(벤치 A)에서 이 지표로 검색기를, 14장(벤치 B)에서 답변 품질을 잽니다. 평가의 함정 하나: 모델은 모르는 수치를 자신있게 지어냅니다. 그래서 채점자에게 정답(ground truth)을 주입해 환각을 잡습니다(14장에서 실증).
종합 점수는? — 100점 루브릭. 개별 지표를 묶어 속도 40 + 품질 60 = 100점으로 환산하고, 통과선은 80점으로 잡았습니다. 우리 실제 점수는 보강하며 51.2 → 61.2까지 올랐지만 80엔 아직 미달이에요. 이 미달을 숨기지 않고 그대로 두는 게 정직한 벤치마크입니다 — "광고"가 아니라 "측정 도구"니까요.
설계 결정

왜 SQLite·MiniLM인가 + 더 좋은 대안

한 줄: 우리 규모에선 SQLite/FTS5 + MiniLM이 단순성·로컬·비용 면에서 합리적 baseline. 바꿀 가치는 저장소 교체가 아니라 임베딩 모델 A/B(BGE-M3 1순위)에 있다. (코드·공식 문서 근거 — 손석희 검증)
🗄️ 왜 SQLite / FTS5인가

우리 검색은 엔티티·관계·커뮤니티를 SQL로 join하면서, 동시에 이름·한국어명·설명을 빠르게 키워드 검색해야 합니다. SQLite는 서버가 필요 없고(in-process), 설정이 0이고, 트랜잭션을 지원하는 SQL 엔진이며 전체가 파일 하나(vault_graph.db, 현재 435MB)로 운용됩니다. 우리 규모에선 별도 검색 클러스터보다 "단일 DB + WAL + 읽기전용 서버"가 단순하고 안전합니다.

키워드 채널은 SQLite의 FTS5 trigram입니다. 한국어처럼 띄어쓰기·형태소가 까다로운 글에서 3글자 단위 부분 매칭이 잘 듣습니다. 이름·설명·출처를 한 FTS 테이블로 묶고 id로 join해 동명이인 충돌을 피합니다. 다만 FTS5는 어휘 검색이라 관계·말바꿈·frontmatter 전용 별칭에는 약하고(그래서 Dense·그래프로 보강), 2글자 미만 토큰은 LIKE 보조가 필요합니다.

🧠 왜 MiniLM인가

paraphrase-multilingual-MiniLM-L12-v2는 문장을 384차원 벡터로 만드는 작은 다국어 모델입니다. 우리 인덱스는 노트 3,740 + 엔티티 7,278 벡터라, 384차원이면 전부 정확 비교(exact cosine)해도 충분히 작고 빠릅니다. API 호출이 없어 비용·지연·프라이버시 위험이 0입니다. 같은 모델로 노트와 엔티티를 모두 임베딩하고, 모델이 바뀌면 전체 재색인을 강제해 "서로 다른 의미공간이 섞이는 사고"를 막습니다. 다만 경량(384차원)이라 최신 다국어 모델보다 품질 천장이 낮고, 노트는 앞 500자만 보므로 긴 문서·관계 질의에서 신호가 약해집니다(벤치의 L1 약점·Q24 교차언어 miss가 그 신호).

🔍 더 좋은 건 없나 — 저장소
대안장점정직 판정
SQLite FTS5 (현재)embedded·단일파일·트랜잭션·SQL join+그래프를 한 DB에유지. 우리 규모에 최적의 단순성
TantivyRust 풀텍스트, BM25, 빠른 시작실익 낮음 — 별도 인덱스 동기화 부담
Postgres+pgvectorSQL+ACID+벡터를 한 서버에, HNSW조건부 — 멀티유저·10만+ 벡터면 유력. 지금은 운영비>실익
LanceDB로컬 임베디드 벡터DB유지 — 벡터만 바꿔선 L1 관계 문제 안 풀림
Qdrant/Chroma벡터DB, 메타 필터, 하이브리드유지 — 서비스 운영이 늚. QPS·멀티테넌트면 검토
OpenSearchBM25+k-NN 프로덕션 검색엔진유지 — 대규모·분산·검색팀 있을 때. 개인 vault엔 과함
🔍 더 좋은 건 없나 — 임베딩 모델 (★바꿀 가치 있는 축)
대안장점정직 판정
MiniLM (현재)384차원·로컬·무료·빠름·비용0유지 — baseline으로 적합
BAAI/bge-m31024차원·8192토큰·100+언어·dense/sparse/멀티벡터 한 모델바꿀 가치 1순위 A/B. 교차언어·L1 의미 recall 개선 후보(재색인 비용↑)
multilingual-e5-large다국어 E5, 1024차원2순위 A/B — 쿼리 prefix 등 적용 세부 필요
gte-multilingual-base75언어·8192컨텍스트·768차원2순위 A/B — 긴 문서·한국어 후보
jina-embeddings-v3다국어·8192·차원 축소 가능실험 후보 — 장문·다국어 강점
OpenAI/Cohere/Voyage고성능 API 임베딩조건부 — 품질↑지만 API 비용·외부전송·로컬원칙과 충돌

리랭커는 현 bge-reranker-base 유지가 기준점이고, bge-reranker-v2-m3는 과거 퇴행 이력이 있어 새 벤치로 재실험 후 판단합니다(7장 일화).

권장(정직) — "우리 규모에선 SQLite/FTS5 + MiniLM이 단순성·로컬·비용 면에서 합리적 baseline이고, 약점은 저장소 교체보다 다국어 임베딩/리랭커 A/B + 관계·gold-set 개선으로 다루는 게 맞다. 1순위 실험 = BGE-M3 임베딩, 2순위 = bge-reranker-v2-m3 재실험."
과장 금지 — 벤치의 L1 hit@5 0.2는 임베딩만의 문제가 아니라 관계 신호 + gold-set 협소 + frontmatter 교차언어 recall이 섞인 문제입니다. "강한 임베딩으로 바꾸면 해결"이라고 쓰면 과장입니다. 그래서 "1순위 A/B 실험감"으로만 적습니다.
벤치마크 A

검색이 정답 문서를 잘 찾나

한 줄: 24개 질문을 메모리·사전지식 없이 순수 검색으로(cold). 직접조회(L0)는 강하고(0.83), 관계(L1)가 최약점(0.2). MISS는 '진짜 갭'과 'gold가 좁은 가짜 miss'로 갈린다.
1.0coverage
10/24hit@5
0.307MRR
0.108precision@5
138ms속도 p50

난이도(레벨)별 — 어디가 강하고 약한가

레벨설명hit@5MRR
L0 직접조회"GraphRAG", "MCP" 같은 키워드0.830.72
L1 관계"reranker 재정렬 원리" 같은 개념0.200.13
L2 멀티홉"프롬프트 설계가 성능에 미치는 영향"0.400.14
L3 합성"내 지식 전체 핵심 주제 3가지"0.330.33

직접 키워드 조회(L0)는 아주 강함(0.83). 관계·개념(L1)이 최약점(0.2) — 12장에서 본 임베딩 보강의 1순위 타깃입니다.

실제 사례 — 무엇을 검색했고 어떻게 나왔나

"MCP"Q19 · L0재경님 발견 사례hit@5 ✓
왜 중요옵시디언 CLI로 MCP를 검색하면 vault에 946개가 매칭됩니다. CLI는 관련도 순위가 없어(경로·이름순) 정작 핵심 문서가 1,000개 밖으로 묻혀 못 찾았던 케이스 — 재경님이 직접 발견하신 문제.
검색 결과/search는 gold MCP-생태계-현재와-미래-MOC를 1등으로. hit@5 ✓ · MRR 1.0.
의미 순위가 "묻힘"을 푼다. CLI의 946개 더미에서 못 건지던 걸 /search가 정확히 1등으로 — 이 시스템의 존재 이유 그 자체.
"reranker 재정렬 원리"Q21 · L1'가짜 miss'hit@5 ✗
gold 목록Journey-13-Search-v2-4Channel-Server, Journey-16-…-CE-Mastery (우리가 정답으로 정해둔 노트)
실제 결과top5 = Reranker-검색-재정렬-기법, ettin-reranker-graphrag — 리랭커를 정확히 다룬 더 좋은 노트를 올림! 그런데 gold 목록에 없어 'miss'.
검색 실패가 아니라 gold가 좁았던 것. 답변(벤치 B)에서도 sonnet이 92점 최고. → 벤치 점수는 '검색 품질'과 'gold 정의 품질'을 분리해 읽어야.
"Embedding Vector Space Geometry"Q24 · L1진짜 갭hit@5 ✗
노림수영어 질문인데 정답 노트 임베딩과-벡터공간-기하학는 그 영어구가 frontmatter(aliases)에만 있고 본문은 한국어. = 메타데이터 색인 + 교차언어 이중 난이도(일부러 어렵게 낸 스트레스 테스트).
실제 결과top5 = Vector-Embeddings, Embedding-벡터-의미의-숫자화 — 관련은 있으나 정확 gold 아님. 진짜 retrieval 갭.
이건 진짜 보강 타깃. alias·frontmatter 색인 강화 + 강한 임베딩(12장 BGE-M3)이 노릴 갭. (그래도 답변은 sonnet 82·정확도 94.)
전체 24개 질문 결과표 펼치기 ▾
IDLv질문hit@5P@5MRR
Q01L0GraphRAG10.41
Q02L0프롬프트 엔지니어링10.40.33
Q03L0얼룩소 아카이브10.41
Q04L0Claude Code 스킬000
Q05L0김재경10.21
Q19L0MCP10.21
Q06L1얼룩소에서 AI에 대해 쓴 글000
Q07L1에이전트 팀 구성하는 방법000
Q08L1가나다정밀 마스터 강의 내용000
Q09L1Anthropic AI Safety 관련 연구10.20.33
Q10L1Obsidian 자동화 워크플로우000
Q20L1RAG와 GraphRAG의 차이10.21
Q21L1reranker 재정렬 원리000
Q22L1벡터 임베딩 의미 검색000
Q23L1agent orchestration patterns000
Q24L1Embedding Vector Space Geometry000
Q11L2AI가 민주주의에 미치는 영향 (내 글)000
Q12L2프롬프트 설계가 에이전트 성능에10.20.5
Q13L2Knowledge Manager에서 GraphRAG10.20.2
Q14L22026 AI 에이전트 트렌드·사례000
Q15L2얼룩소 플랫폼 분석·콘텐츠 전략000
Q16L3내 지식 핵심 주제 3가지000
Q17L3AI 연구→강의→실무 전체 여정000
Q18L3정치/사회 글쓰기와 AI 연구 연결10.21
정직 sanity — hit@5 10/24는 매칭을 느슨하게 해서 못 고치는 실신호(MISS 14건 중 13건이 상위에 gold 0회). 단 두 종류: ①진짜 retrieval 갭(Q24) ②gold가 좁아 생긴 '가짜 miss'(Q08·Q21은 검색이 다른 좋은 노트를 올림). 검색 품질과 gold 정의 품질을 분리해 읽어야 합니다.
벤치마크 B

haiku · sonnet · opus가 답하면

한 줄: 같은 검색을 세 모델이 답으로 만들 때 — sonnet이 sweet spot(정확·안전·검색거부 0). opus는 깊은 종합만 우위, 검색이 약하면 자신있게 날조한다.

모델 종합 점수 (24문항 평균)

티어answer정확도근거환각↓검색거부
haiku61.159.852.90.292
sonnet70.874.471.50.180
opus66.667.260.50.241

sonnet이 sweet spot — 정확도·근거·환각·안정성(검색거부 0회) 모두 최고이면서 opus보다 쌉니다. (환각↓ = 낮을수록 좋음)

난이도별 — 큰 모델이 항상 낫진 않다

레벨haikusonnetopus한 줄
L0 직접43.564.264.8sonnet=opus, sonnet이 저렴
L1 관계62.178.978.6sonnet 최강
L2 멀티홉77.867.439.6opus 붕괴(날조)
L3 합성656375opus 우위(깊은 종합)

실제 사례 — 모델이 어떻게 다르게 답하나

"AI가 민주주의에 미치는 영향 (내 글)"Q11 · L2opus 날조
검색(A)hit@5 ✗ — 관련 글을 top5에 못 올림(검색이 약한 질문).
답변(B)haiku 82점 · sonnet 15 · opus 10점(환각 0.9). 검색이 약하자 opus가 없는 내용을 자신있게 지어냄. haiku는 보수적으로 답해 오히려 높음.
"큰 모델이 항상 낫다"는 거짓. 검색이 약할 때 opus가 가장 위험(L2 통째 붕괴 39.6).
"GraphRAG"Q01 · L0opus 검색거부
검색(A)hit@5 ✓ · MRR 1.0 — 검색은 완벽.
답변(B)haiku 72 · sonnet 58 · opus 15 (검색거부) — opus가 "GraphRAG" 한 단어를 "질문이 너무 짧다"며 검색조차 안 함.
큰 모델일수록 짧은 키워드에 까탈스러움. 검색거부 0회인 sonnet이 "사용자 편의"에선 더 믿음직.
"김재경"Q05 · L0검색OK·답변빈약
검색(A)hit@5 ✓ — 검색은 정답 노트를 찾음.
답변(B)haiku 15 · sonnet 20 · opus 35 — 셋 다 낮음. 노트는 찾았지만 인물 정보가 여러 곳에 흩어져 한 답으로 합치기 어려움.
검색 성공 ≠ 답변 성공. retrieval(찾기)과 answer(답하기)는 별개 트랙 — 표가 질문별 병목을 분리해 보여줌.
전체 24개 질문 × 3모델 점수표 펼치기 ▾
IDLv질문haikusonnetopus
Q01L0GraphRAG725815✗
Q02L0프롬프트 엔지니어링5✗7282
Q03L0얼룩소 아카이브257289
Q04L0Claude Code 스킬728580
Q05L0김재경152035
Q19L0MCP727888
Q06L1얼룩소 AI 글788272
Q07L1에이전트 팀 구성628558
Q08L1가나다정밀 강의758278
Q09L1Anthropic AI Safety426872
Q10L1Obsidian 자동화627885
Q20L1RAG와 GraphRAG 차이728088
Q21L1reranker 재정렬789285
Q22L1벡터 임베딩 검색726882
Q23L1agent orchestration5✗7281
Q24L1Embedding Vector Space758285
Q11L2민주주의 영향 (내 글)821510
Q12L2프롬프트 설계 영향88900
Q13L2KM에서 GraphRAG728285
Q14L22026 에이전트 트렌드657278
Q15L2얼룩소 콘텐츠 전략827825
Q16L3핵심 주제 3가지657278
Q17L3AI 연구→강의→실무688279
Q18L3정치 글쓰기·AI 연결623568

✗ = 검색거부(검색 0회). 점수 0~100, 환각은 0~1(낮을수록 좋음).

핵심 발견 — 모델은 검색이 안 짚어준 수치를 '자신있게 틀리게' 말합니다(opus는 L2 통째 날조). 그래서 채점자에게 정답 수치(ground truth)를 주입해 이 환각을 잡았습니다. → RAG 답 품질 = 검색 품질 × 모델의 정직성.
논문

어디서 왔나 — 8편의 원전

한 줄: 이 가이드북의 모든 개념은 검증된 논문에 뿌리가 있다. 8편 전부 1차 출처(arXiv 초록·고전 원전) 직접 확인.
개념논문 · 저자 · 연도핵심 기여우리 적용 (정직)
RAGLewis 외, 2020
2005.11401
LLM(기억)+외부 검색(인덱스) 결합. RAG 원전./search=검색(R). 생성(G)은 opt-in
BM25Robertson & Zaragoza, 2009TF 포화·길이정규화·IDF 확률 랭킹.Sparse = FTS5 trigram(BM25 계열)
DenseKarpukhin 외, 2020
2004.04906
의미 벡터 검색. BM25 대비 +9~19%p.로컬 MiniLM-L12-v2 (학습방식은 다름)
HNSWMalkov & Yashunin, 2018
1603.09320
계층 그래프 근사 최근접(ANN).개념만 — 미사용(규모 작음)
RRFCormack 외, 2009점수 아닌 순위로 Σ1/(k+rank) 융합.4채널 핵심 1/(60+rank) — 코드 1:1 ✅
Cross-encoderNogueira & Cho, 2019
1901.04085
(질문,문서) 동시 입력 재정렬. MRR@10 +27%.리랭커 bge-reranker-base
GraphRAGEdge 외(MS), 2024
2404.16130
LLM 추출→커뮤니티 요약→Local/Global.계열. LLM추출·요약·Map-Reduce=placeholder → MS 동등 ❌
RAGASEs 외, 2023
2309.15217
정답 없이 faithfulness 자동평가.외부 미도입 — 자체 judge가 같은 정신
우리 실제 스택(코드 검증) — Sparse = SQLite FTS5 trigram · Dense = paraphrase-multilingual-MiniLM-L12-v2 · 리랭커 = BAAI/bge-reranker-base · RRF k=60 4채널. HNSW/faiss = 미사용.
개념 정확성 — ① BM25 ≠ 단순 TF-IDF(포화·길이정규화) · ② RRF = 점수 아닌 순위만 · ③ HNSW = 근사라 "정확검색" ❌.
마무리

보강 결과 & 한 장 요약

한 줄: 측정한 뒤 정직하게 — 가중치는 이미 최적(바꿔도 안 오름), LLM 답변층은 코드 완성·opt-in. 진짜 다음 레버는 임베딩 A/B + frontmatter 색인 + 답변합성 켜기.
✅ 보강 실현됨 (2026-06-16) — 이 가이드북이 가리킨 레버를 실제로 당겼습니다
  • →임베딩 A/B (BGE-M3) → 라이브 적용 완료. 우리 24문항 벤치 정답률 18 → 23/24 (소형 MiniLM → 다국어에 강한 bge-m3 + 채널 합산 방식 개선). 라이브 검색에 이미 켜져 동작 중.
  • →gold-set 재검토 → 위에서 예고한 그대로 Q07·Q08·Q21은 검색이 옳고 우리가 적어둔 정답이 좁았던 것(교정). 단 Q09 한 개는 교정해도 못 잡은 진짜 약점으로 정직하게 남겼습니다(정답 끼워맞춰 24 만들기 ❌).
  • →과적합 아님 증명 → 24문항과 겹치지 않는 48개 독립 질문으로도 측정 → 9→15 동반 상승(하나도 안 깎임). "벤치 하나로 전체 시스템 못 잡는다"를 광범위 검증으로 해소.
자세한 과정·정직한 한계는 맨 위 탭의 짝꿍 가이드 「검색 벤치 — 18에서 23으로」에서. 근거 raw = gr_goldfix_24q.json·broadval-48q.

(a) 자동 튜닝 (autoresearch)

한 변수만 바꿔 좋아지면 keep·나빠지면 버리는 자동 루프(autoresearch)를 119라운드 돌렸습니다. 결과: 현 가중치가 이미 최적 — baseline(hit@5 10/24·MRR 0.307)을 못 넘었어요. 합성점수만 높고 hit@5를 잃은 후보는 거부 = 정직한 negative result.

(b) LLM 답변합성

코드 완료 · 기본 OFF(opt-in). provider를 교체 가능한 구조로 — claude -p는 6/15부터 별도 과금이라 폐기, codex_cli 주력. 어느 경로가 막혀도 기본 검색은 멀쩡.

LLM은 어디에 있나 (정확히) — ①그래프 재료(링크·태그) 저작 = AI(/knowledge-manager ingest). ②인덱싱(링크→DB 전사) = 규칙(LLM 0). ③커뮤니티=Louvain · 임베딩=MiniLM(소형 전용 모델). ④인덱스-시점 LLM 관계추출·커뮤니티 LLM 요약·Map-Reduce = 미작동. ⑤검색 답변합성 = opt-in. "그래프 구축에 LLM 0"이 아니라 "구조는 AI가 만들고, 인덱싱 전사는 규칙"이 정확합니다.

진짜 다음 레버 (벤치가 가리킨 것)

레버왜
임베딩 A/B (BGE-M3 1순위)L1 관계·교차언어 약점의 후보 (단 "모델만으로 해결"은 과장 — 12장)
gold-set 재검토Q08·Q21처럼 검색은 좋은데 gold가 좁아 'miss'로 찍힌 건 벤치를 고치는 문제
frontmatter/alias 색인Q24 같은 진짜 갭(교차언어·메타데이터-only)을 잡는 retrieval 보강
답변합성 켜기 · 기본 sonnet검색 Top-5를 자연어 답으로(게이트). 모델 기본값 = sonnet

한 장 요약

우리 /search = GraphRAG 계열 — AI(/knowledge-manager)가 만든 [[링크]]·태그를 규칙으로 옮긴 지식 그래프 + 4채널 하이브리드. MS의 인덱스-시점 LLM 추출·요약·Map-Reduce는 placeholder → "동등"은 과장, "계열"은 사실.

하이브리드 = 의미(dense)+키워드(BM25/FTS5)+질문분해+엔티티를 RRF(순위 융합)로 합치고 cross-encoder로 재정렬해 Top-5. HNSW는 우리 규모엔 불필요.

벤치(24문항·3모델): 검색은 직접조회(L0) 강·관계(L1) 약. 답변은 sonnet sweet spot(정확·안전), opus는 깊은 종합만·검색 약하면 날조.

도구 선택: 우리 규모엔 SQLite/FTS5 + MiniLM 유지가 합리적. 바꿀 가치는 저장소가 아니라 임베딩 모델 A/B(BGE-M3).

메타 교훈: 지식을 정리하는 AI 파이프라인(/knowledge-manager)이 남긴 링크·태그가 그대로 검색 그래프의 엣지가 된다 — 정리와 검색이 한 흐름 / 평가엔 ground-truth 앵커가 필수(모델은 모르면 자신있게 지어낸다).

🧊 우리 /search 뜯어보기 — GraphRAG·하이브리드 검색 가이드북
근거: 벤치 aktofu-bench-table.md · 논문 domain-konan-papers.md · 스택분석 sonseokhee-stack-rationale-alternatives.md · live vault_graph.db 2026-06-07 KST

여기까지 — 그리고 다음

검색의 속을 다 열어봤습니다. 의미 + 단어 + 그래프를 섞어 순위를 매기고, 리랭커로 마지막 정밀 심사를 한 뒤 Top-5를 내놓는다 — 이게 우리 /search입니다.

🧊 잠깐, 메타 한 줄

지금 읽고 있는 이 가이드북도 바로 그 LLM wiki + GraphRAG + 봇 에이전트로 만들어졌습니다. 노트로 쌓은 지식을 /search로 찾고, 여러 AI 봇이 나눠 쓰고 그려서요. Part 3에서 그 봇들이 실제로 어떻게 도는지 보여드릴게요.

→ Part 3: 이 검색을 봇 에이전트들이 실제로 어떻게 쓰는가 — vault·Discord·여러 봇이 한 몸처럼 도는 원리.