본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

멀티 에이전트

이 페이지에 묻기

멀티 에이전트 · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

MULTI · AGENT

멀티 에이전트

생성 수정

도구 실행·검색·기억·그래프 흐름·전문 에이전트의 협업을 구성하고 권한·평가·사람의 확인으로 통제합니다.

26개 문서 · 2일차 · 16 / 26

15차시 · 검색 품질 개선

지도 위치 : 2일차 · README 4장의 ③ 지식 층 — 지식 층의 마지막 칸, 실제 직원의 말투에도 찾아지게 만드는 자리 | 이전: 14차시 근거 기반 답변 | 다음: 16차시 멀티턴 대화와 세션 관리 키워드 : 하이브리드 검색, 리랭킹, 쿼리 재작성

이 차시를 다 읽으면

  1. 실사용 질문이 검색을 실패하게 만드는 유형(구어체 · 줄임말 · 사내 은어 · 번호)을 말할 수 있다.
  2. 질문-정답 청크 평가셋으로 Recall@k 를 측정하고, 개선 전에 측정부터 하는 이유를 설명할 수 있다.
  3. BM25와 의미 검색을 하이브리드 로 합치는 이유와 RRF의 직관을 설명할 수 있다.
  4. 리랭킹(교차 인코더)과 쿼리 재작성이 각각 무엇을 고치는지 구별할 수 있다.
  5. 개선을 한 번에 하나씩 적용하고, 그때마다 늘어나는 비용 · 지연을 함께 기록할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1⭐ 구문론 ↔ 의미론키워드 검색 (BM25) — 같은 글자의미 검색 (임베딩) — 가까운 뜻번호 · 은어 ↔ 바꿔 말한 표현⑧ 구문론 ↔ 의미론
2⭐ 하나 ↔ 여럿검색기 하나, 한 단계검색기 여럿을 합침, 두 단계(후보 → 재정렬)하이브리드 · 리랭킹⑤ 하나 ↔ 여럿
3증거 ↔ 주장Recall@k 표로 "나아졌다""체감상 좋아졌다"개선을 믿어도 되는가파생 축 (부모 ⑧)
4한 건의 비용 ↔ 전체 비용검색 한 번의 비용 · 지연단계를 더할 때마다 쌓이는 비용 · 지연개선의 대가파생 축 (부모 ⑤)

이 차시의 질문 — 13 · 14차시의 오피스봇은 "결혼하면 며칠 쉬어?"는 잘 찾았습니다. 그런데 실제 직원은 "육휴 쓰면 성과급 깎여?", "23조 뭐였지", "G포털 비번 초기화" 같은 말로 묻습니다. 문서는 공식어로, 질문은 입말로 쓰여 있습니다. 이 차시는 그 간격을 메우는 기법 셋을 다루되, 먼저 재고, 하나씩 바꾸고, 다시 재는 순서를 지킵니다.


1. 실사용 표현이 검색을 흔드는 방식

유형직원의 질문문서의 표현의미 검색키워드 검색
구어체"결혼하면 며칠 쉬어?"경조휴가 · 본인 결혼⭕❌
줄임말"육휴 쓰면 성과급 깎여?"육아휴직 · 성과급 지급 기준⚠️ 줄임말을 모를 수 있음❌
사내 은어"G포털 비번 초기화"그룹웨어 비밀번호 재설정❌ 모델이 모르는 말⚠️ 문서에 은어가 있으면 ⭕
번호"23조 뭐였지"제23조(연차휴가 신청)⚠️ 번호는 뜻이 약함⭕
대명사(앞 대화 뒤) "그거 며칠이야?"—❌ "그거"가 무엇인지 모름❌

⭐ 표를 세로로 읽으면, 한 가지 검색 방식이 모든 줄을 이기지 못합니다. 그래서 이 차시의 기법들은 서로를 대체하지 않고 약한 줄을 메웁니다.


2. ⭐ 측정 먼저 — Recall@k

2.1 평가셋과 지표

13 · 14차시까지는 질문 몇 개를 눈으로 확인했습니다. 개선을 시작하기 전에 고정된 평가셋 을 만듭니다(11차시의 회귀 테스트와 같은 원리).

#질문 (실제 직원 말투)유형정답 청크 id
1결혼하면 며칠 쉬어?구어체취업규칙#제24조#1
2육휴 쓰면 성과급 깎여?줄임말복리후생#성과급#2
3G포털 비번 초기화 어떻게 해?은어IT_FAQ#Q17
423조 뭐였지번호취업규칙#제23조#1
…(유형별로 고르게, 총 50~100개)

Recall@k — [검색 평가 지표]인데, [ 정답 청크가 검색 결과 상위 k개 안에 들어 있는 질문의 비율 ]이라는 점에서 답의 문장이 맞는지를 보는 답변 평가 지표와 구별된다. Recall@5 = 0.8이면 "질문 열 개 중 여덟 개는 정답 청크가 상위 다섯 안에 있다"는 뜻입니다.

def recall_at_k(evalset, search_fn, k=5):
    hit = sum(1 for q in evalset if q["answer_id"] in [c["id"] for c in search_fn(q["question"], k)])
    return hit / len(evalset)

🔍 읽는 포인트 : 정답 id가 상위 k개 안에 있으면 1, 없으면 0 — 그 평균입니다. 모델 호출 없이 계산되는 결정론적 숫자 입니다.

2.2 왜 검색만 따로 재나

14차시의 답이 틀렸을 때 원인은 둘 중 하나입니다 — 검색이 정답 청크를 못 가져왔거나 , 가져왔는데 생성이 잘못 썼거나 . Recall@k는 앞의 것만 따로 잽니다. 검색이 못 가져온 청크는 어떤 프롬프트로도 답에 들어갈 수 없으므로, 검색을 먼저 확인합니다.

2.3 결과표 양식

방법Recall@1Recall@5구어체줄임말은어번호평균 지연질문당 추가 비용
의미 검색만 (13차시)0
+ 하이브리드 (3절)
+ 리랭킹 (4절)
+ 쿼리 재작성 (5절)

(빈칸 양식 — 실습에서 채웁니다. 유형별 칸은 해당 유형 질문만의 Recall@5)


3. 하이브리드 검색 — BM25와 의미 검색 합치기

3.1 BM25

BM25 — [키워드 검색의 점수 방식]인데, [ 질문의 단어가 문서에 얼마나 자주 나오는지와, 그 단어가 전체 문서에서 얼마나 드문지(드물수록 가중)로 점수를 매긴다 ]는 점에서 뜻의 거리를 재는 임베딩 검색과 구별된다.

from rank_bm25 import BM25Okapi

bm25 = BM25Okapi([tokenize(c["text"]) for c in chunks])
scores = bm25.get_scores(tokenize(question))

🔍 읽는 포인트 : tokenize가 핵심입니다. ⚠️ 한국어는 "연차는 · 연차를 · 연차가"처럼 조사가 붙어 띄어쓰기로 자르면 같은 단어로 인식되지 않습니다. 형태소 분석기나 글자 조각(n-gram)으로 자르는 방법이 있고, 어느 쪽이 나은지는 평가셋으로 정합니다.

3.2 하이브리드와 RRF

하이브리드 검색 (Hybrid Search) — [검색 방식]인데, [ 키워드 검색과 의미 검색의 결과를 합쳐 하나의 순위로 만든다 ]는 점에서 한 가지 방식만 쓰는 검색과 구별된다.

문제는 두 검색의 점수 단위가 다르다 는 것입니다(BM25 점수 12.3과 코사인 유사도 0.78은 비교할 수 없음). 그래서 점수 대신 순위만 씁니다. 대표적인 방법이 RRF(Reciprocal Rank Fusion, 순위 역수 합) 입니다 — 각 목록에서의 순위 r에 대해 1 / (60 + r)을 더합니다.

청크의미 검색 순위BM25 순위RRF 점수 (k=60)최종
제23조131/61 + 1/63 ≈ 0.03231위
IT_FAQ#Q17511/65 + 1/61 ≈ 0.03182위
제24조2(없음)1/62 ≈ 0.01613위

⭐ 직관: 양쪽 목록에 다 올라온 청크가 위로 갑니다. 한쪽에서만 높은 청크도 사라지지 않고 남습니다. 60은 관례적으로 쓰는 값으로, 1위와 2위의 차이를 너무 크게 만들지 않는 역할을 합니다.

def rrf(rank_lists, k=60):
    scores = {}
    for ranks in rank_lists:                       # 예: [의미 검색 id 순위, BM25 id 순위]
        for r, cid in enumerate(ranks, start=1):
            scores[cid] = scores.get(cid, 0) + 1 / (k + r)
    return sorted(scores, key=scores.get, reverse=True)

🔍 읽는 포인트 : 순위 목록 여러 개를 받아 1/(k+순위)를 더하고 정렬합니다. 점수 단위를 맞출 필요가 없습니다.

⚠️ BM25 쪽에도 13차시의 권한 필터 (access_dept)를 똑같이 걸어야 합니다. 하이브리드를 붙이면서 한쪽 경로로 권한이 새는 일이 흔합니다.


4. 리랭킹 — 두 단계 검색

4.1 교차 인코더

교차 인코더 (Cross-encoder) — [검색 순위 모델]인데, [ 질문과 청크를 한 쌍으로 함께 읽고 관련도 점수를 낸다 ]는 점에서 질문과 청크를 따로 벡터로 바꿔 거리만 재는 임베딩 검색(bi-encoder)과 구별된다.

임베딩 검색 (따로 읽음)교차 인코더 (함께 읽음)
청크 벡터를 미리 만들어 둘 수 있나⭕ 적재 때 한 번 (13차시)❌ 질문이 올 때마다 쌍으로 계산
속도수천 개도 빠름느림 — 후보 수십 개가 한계
정확도대략적질문과 청크의 세부까지 비교해 더 정밀

4.2 두 단계로 나누기

청크 수천 개 ─[1단계: 하이브리드, 빠르고 넓게]─▶ 후보 30개 ─[2단계: 리랭커, 느리지만 정밀]─▶ 상위 5개 ─▶ 14차시 주입

리랭킹 (Reranking) — [검색 후처리]인데, [ 1단계 검색이 넓게 가져온 후보만 더 정밀한 모델로 다시 정렬한다 ]는 점에서 처음부터 전체를 한 번에 정렬하는 단일 단계 검색과 구별된다.

from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")        # 예시 모델 — 한국어 지원 여부 확인
scores = reranker.predict([(question, c["text"]) for c in candidates])
top5 = [c for _, c in sorted(zip(scores, candidates), key=lambda x: x[0], reverse=True)][:5]

🔍 읽는 포인트 : (질문, 청크) 쌍 을 넣습니다. 이것이 "함께 읽는다"의 모양입니다. 후보 30개면 쌍도 30개 — 그래서 1단계가 후보를 줄여 줘야 합니다.

💡 리랭킹은 "정답이 30위 안에는 있는데 5위 밖에 있는" 경우를 고칩니다. 정답이 30위 안에도 없다면 리랭킹으로는 못 고칩니다 — 1단계(하이브리드 · 쿼리 재작성 · 청킹)를 봐야 합니다. Recall@30과 Recall@5를 함께 보면 어느 쪽 문제인지 갈립니다.


5. 쿼리 재작성 — 질문을 검색용 문장으로

쿼리 재작성 (Query Rewriting) — [검색 전처리]인데, [ LLM이 사용자의 질문을 검색에 맞는 문장(들)로 바꾼 뒤 검색한다 ]는 점에서 질문을 그대로 검색하는 방식과 구별된다.

종류직원의 질문재작성 결과
검색용 문장으로"G포털 비번 초기화 어떻게 해?""그룹웨어 비밀번호 재설정 절차"
여러 질문으로"육휴 쓰면 성과급 깎여?""육아휴직 기간 성과급 지급 기준" / "휴직자 평가 제외 규정"
대화 맥락의 대명사 풀기(경조휴가 이야기 뒤) "그거 며칠이야?""본인 결혼 경조휴가 일수"
class Rewrite(BaseModel):
    queries: list[str]

rw = client.messages.parse(
    model="claude-haiku-5-5", max_tokens=1024,
    system=REWRITE_SYSTEM,          # 사내 용어집(G포털=그룹웨어, 육휴=육아휴직 ...)을 포함
    messages=[{"role": "user", "content": question}],
    output_format=Rewrite,
).parsed_output

🔍 읽는 포인트

  • claude-haiku-5-5 — 재작성은 짧고 자주 하는 일이라 가볍고 싼 모델 을 씁니다(2차시의 모델 선택). 가격은 공식 페이지 확인.
  • REWRITE_SYSTEM의 사내 용어집 — 모델이 모르는 은어는 재작성으로도 못 풉니다. 용어집을 넣어 주는 것이 핵심입니다.
  • 여러 질문이 나오면 각각 검색해 RRF로 합칩니다 (3.2).

⚠️ 재작성이 뜻을 바꿀 수 있습니다("성과급 깎여?" → "성과급 인상 기준"). 그래서 ① 원래 질문도 함께 검색하고 ② 재작성 결과를 로그에 남겨 평가 때 확인합니다.

앞으로 다시 만납니다 — 세 번째 줄(대명사 풀기)은 이전 대화 가 있어야 가능합니다. 16차시에서 대화 이력을 세션으로 관리하면서 회수합니다.


6. 개선 순서 — 한 번에 하나씩

6.1 순서

순서할 일고치는 것
0⭐ 평가셋 · Recall@k 기준선 측정— (출발점)
1놓친 질문의 정답 청크를 열어 봄 — 청킹 · 로딩 문제인가 (12차시)깨진 표, 반쪽 조항
2하이브리드번호 · 은어 · 고유명사
3리랭킹정답이 후보에는 있는데 순위가 낮음
4쿼리 재작성구어체 · 줄임말 · 대명사

⭐ 한 번에 하나만 바꾸고 다시 잽니다. 셋을 한꺼번에 넣고 점수가 올랐다면, 무엇이 효과였는지, 무엇은 오히려 깎아 먹었는지 알 수 없습니다. 그리고 1번을 건너뛰지 마세요 — 적재가 깨져 있으면 위의 기법은 깨진 청크를 더 정교하게 찾을 뿐입니다(12차시 2절).

6.2 개선의 대가

추가하는 것추가 비용추가 지연운영 부담
하이브리드 (BM25)거의 없음작음키워드 인덱스를 문서 개정 때 함께 갱신
리랭킹서버 자원 (또는 API 비용)후보 수에 비례모델 하나 더 운영
쿼리 재작성⚠️ 질문마다 LLM 호출 1회LLM 왕복 1회용어집 관리, 재작성 로그 점검

⚠️ 쿼리 재작성은 모든 질문에 LLM 호출을 하나 더합니다. 10차시 3.3의 곱셈(요청 수 × 날짜)을 다시 하세요. 단계가 늘면 응답 시간도 늘어 사용자가 기다립니다. 2.3의 결과표에 지연 · 비용 칸이 있는 이유 입니다 — Recall이 조금 오른 대가가 너무 크면 멈추는 것도 결정입니다(README 문장 1).


7. 오피스봇 적용 — 유형별 처방

약한 유형 (2.3 표에서)먼저 볼 것처방
번호 ("23조")BM25 결과하이브리드
은어 ("G포털")용어집쿼리 재작성 + 용어집, 또는 적재 시 청크에 동의어 추가
줄임말 ("육휴")의미 검색 결과쿼리 재작성
정답이 6~30위Recall@30 vs Recall@5리랭킹
정답이 30위 밖정답 청크 원문청킹 · 로딩 재점검 (12차시)

8. 실습 — 맡기고 검수하기

지시

오피스봇 규정 검색의 품질을 측정하고 개선해줘.
- 평가셋: 내가 준 evalset.jsonl (질문·유형·정답 청크 id). 수정 금지
- 참고: rank_bm25, sentence-transformers(CrossEncoder), Claude API structured outputs 공식 문서. 버전·주소를 보고에 적을 것
- 단계별로 하나씩 추가하고 매 단계 측정: ① 의미 검색만 ② +BM25 하이브리드(RRF, k=60) ③ +리랭킹(후보 30→5) ④ +쿼리 재작성(claude-haiku-5-5, 용어집 포함, 원 질문도 함께 검색)
- 모든 단계에서 access_dept 권한 필터 유지 (BM25 경로 포함)
- 측정: Recall@1, @5, @30, 유형별 Recall@5, 질문당 평균 지연, 질문당 추가 LLM 토큰
- 재작성 결과는 질문별로 로그에 남길 것
추측하지 말고 실행 출력 원문을 붙여.
보고 형식: 2.3과 같은 [방법 | Recall@1 | Recall@5 | 유형별 | 지연 | 추가 비용] 표
 + 단계마다 새로 맞힌 질문 / 새로 틀린 질문 목록

받을 증거

  • 단계별 결과표와 측정 스크립트 실행 출력 원문
  • 새로 틀린 질문 목록 (개선이 다른 질문을 망쳤는가)
  • 쿼리 재작성 로그 10건 샘플

내가 직접 확인할 것

볼 것이걸로 아는 것
각 단계의 숫자가 앞 단계와 하나만 다른 조건에서 나왔는가한 번에 하나만 바꿨는가 (6.1)
번호 유형의 Recall이 하이브리드에서 오르는가BM25가 제 몫을 하는가 (3절)
재작성 로그에서 뜻이 바뀐 사례가 있는가재작성의 부작용 (5절)
개발팀 사용자로 하이브리드 검색 시 인사팀 전용 청크가 0건인가권한 필터가 모든 경로에 있는가 (3.2)
마지막 단계의 지연 · 비용을 10차시 방식으로 하루치로 곱해 봄개선의 대가가 감당할 만한가 (6.2)

부록 A. 스스로 확인하기

#질문답이 있는 곳
1실사용 질문이 검색을 흔드는 다섯 유형은?1절
2Recall@k의 정의와, 검색만 따로 재는 이유는?2.1, 2.2
3BM25에서 한국어가 까다로운 이유는?3.1
4RRF가 점수 대신 순위를 쓰는 이유는?3.2
5교차 인코더와 임베딩 검색은 무엇으로 갈리나?4.1
6리랭킹으로 고칠 수 없는 경우는? 어떻게 알아보나?4.2
7쿼리 재작성의 세 종류와 부작용은?5절
8개선을 한 번에 하나씩 해야 하는 이유는?6.1
9각 개선이 늘리는 비용 · 지연은?6.2

부록 B. 자주 하는 실수

실수바로잡기
측정 없이 "리랭커 넣으면 좋아진다"❌ 기준선부터. 숫자로 비교
평가셋을 개선하면서 함께 고침❌ 고정해야 전후 비교가 됨
세 기법을 한꺼번에 적용⚠️ 무엇이 효과였는지 모름
BM25를 띄어쓰기로만 토큰화⚠️ 한국어 조사 문제. 토큰화 방법도 평가로
BM25 경로에 권한 필터를 빠뜨림❌ 하이브리드로 권한이 샘
전체 청크에 교차 인코더❌ 너무 느림. 후보만
재작성 질문만 검색⚠️ 뜻이 바뀔 수 있음. 원 질문도 함께
비용 · 지연은 안 적고 Recall만 보고⚠️ 개선의 대가도 같은 표에

부록 C. NotebookLM 복습 프롬프트

이 15차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"측정 먼저와 Recall@k", "하이브리드와 RRF의 직관", "리랭킹(교차 인코더)과 두 단계 검색", "쿼리 재작성과 한 번에 하나씩 바꾸기"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.