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

멀티 에이전트

이 페이지에 묻기

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

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

MULTI · AGENT

멀티 에이전트

생성 수정

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

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

13차시 · 임베딩과 벡터 DB

지도 위치 : 2일차 · README 4장의 ③ 지식 층 — 잘라 둔 청크를 뜻으로 찾을 수 있게 저장하는 자리 | 이전: 12차시 문서 로딩과 청킹 | 다음: 14차시 근거 기반 답변 키워드 : 임베딩, 유사도 검색, 벡터 DB

이 차시를 다 읽으면

  1. 임베딩을 유와 종차로 정의하고, 인코딩 · 토큰화와 구별할 수 있다.
  2. 코사인 유사도를 "방향이 얼마나 같은가"로 설명하고, 축 ⑧로 키워드 검색과 의미 검색을 가를 수 있다.
  3. 임베딩 모델을 고를 때의 기준(한국어 · 실행 위치 · 비용)을 말하고, ⚠️ 적재와 질의에 같은 모델 을 써야 하는 이유를 설명할 수 있다.
  4. 벡터 DB를 정의하고, Chroma 코드에서 저장 · 검색 · 메타데이터 필터 줄을 짚을 수 있다.
  5. 인덱스가 디스크에 영구 저장된다는 것(축 ①)과, 문서가 개정되면 적재를 어떻게 다시 하는지 말할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1⭐ 구문론 ↔ 의미론키워드 검색 — 같은 글자가 있는가의미 검색 — 뜻이 가까운가"결혼하면 며칠 쉬어?"로 "경조휴가"를 찾는가⑧ 구문론 ↔ 의미론
2디스크 ↔ 메모리벡터 인덱스 — 디스크에 영구이번 요청의 messages — 끝나면 사라짐무엇을 미리 만들어 두는가① 디스크 ↔ 메모리
3로컬 ↔ 원격내 서버의 오픈소스 임베딩 모델임베딩 API 서비스문서 원문이 밖으로 나가는가④ 로컬 ↔ 원격
4정확 ↔ 근사모든 벡터와 비교길잡이 구조로 후보만 비교 (ANN)검색 속도 ↔ 놓칠 가능성이 차시의 축

이 차시의 질문 — 12차시에서 규정 문서를 조항 단위 청크로 잘랐습니다. 직원이 "결혼하면 며칠 쉬어?"라고 물으면, 수백 개 청크 중 "제24조(경조휴가)"를 어떻게 찾을까요? 질문에는 "경조"라는 글자가 없습니다. 이 차시는 글의 뜻 을 숫자로 바꿔 가까운 뜻 을 찾는 방법과, 그 숫자를 저장해 두는 창고를 다룹니다.


1. 임베딩 — 뜻을 좌표로

1.1 정의와 경계

임베딩 (Embedding) — [텍스트 표현 방식]인데, [ 글의 뜻을 숫자 목록(벡터)으로 바꿔, 뜻이 비슷한 글끼리 벡터가 가깝게 놓이게 한다 ]는 점에서 글자를 정해진 규칙으로 바이트로 바꾸는 인코딩(UTF-8 등)이나, 글을 조각으로 나눠 번호를 붙이는 토큰화와 구별된다.

인코딩 (UTF-8)토큰화 (2차시)임베딩
결과바이트 열토큰 번호 열실수 수백~수천 개의 벡터
거리에 뜻이 있는가❌❌ 번호가 가깝다고 뜻이 가깝지 않음⭕ 가까우면 뜻이 비슷
누가 정하나규칙토크나이저 규칙학습된 모델

⭐ 핵심은 마지막 줄의 둘째 칸입니다. 임베딩에서만 "거리"가 "뜻의 차이" 를 나타냅니다.

        "결혼하면 며칠 쉬어?" ●
                              ● "제24조(경조휴가) 본인 결혼 5일 ..."
   "가족 사망 시 휴가" ●

                                          ● "제7조(비밀번호) 90일마다 변경"
                                        ● "VPN 접속 오류 해결"

(뜻의 지도를 2차원으로 그린 그림 — 실제는 수백 차원)

1.2 반례 — 이건 임베딩이 아닙니다

대상왜 아닌가
토큰 번호 목록 [1523, 88, 4012]숫자이지만 거리에 뜻이 없음
단어 등장 횟수 표글자가 같아야만 가까워짐. 키워드 쪽 (2절)
Claude의 답임베딩 모델은 글을 만들지 않고 벡터만 냄

1.3 코사인 유사도 — 방향이 얼마나 같은가

코사인 유사도 (Cosine Similarity) — [벡터 간 유사도 척도]인데, [ 두 벡터의 길이는 무시하고 가리키는 방향이 얼마나 같은지를 -1~1로 잰다 ]는 점에서 두 점 사이의 직선 거리를 재는 유클리드 거리와 구별된다. 1에 가까울수록 뜻이 비슷합니다.

질문청크코사인 유사도 (예시 — 실측 아님)
결혼하면 며칠 쉬어?제24조(경조휴가) 본인 결혼 5일 …0.78
결혼하면 며칠 쉬어?제23조(연차휴가 신청) …0.52
결혼하면 며칠 쉬어?제7조(비밀번호) …0.11

💡 비유(기억 보조용): 두 사람이 같은 쪽을 가리키고 있는가 를 보는 것입니다. 팔 길이(글 길이)는 상관없습니다.


2. 축 ⑧ — 키워드 검색 ↔ 의미 검색

질문찾아야 할 청크키워드 검색 (구문)의미 검색 (의미)
"결혼하면 며칠 쉬어?"제24조(경조휴가)❌ 겹치는 글자 없음⭕ 뜻이 가까움
"재택근무 가능해?"제31조(원격근무)❌⭕
"제23조 알려줘"제23조⭕ 정확히 일치⚠️ 번호는 뜻이 약해 다른 조항이 섞일 수 있음
"VPN-302 오류"IT FAQ의 VPN-302 항목⭕⚠️ 비슷한 오류 코드들이 다 가까움

⭐ 의미 검색은 표현이 달라도 뜻이 같으면 찾고, 키워드 검색은 번호 · 코드 · 고유명사 에 강합니다. 어느 한쪽이 이기는 것이 아니라 잘하는 일이 다릅니다. 앞에서 배운 구조화 출력(4차시)에서 스키마 검증(형식)과 분류 정확도(뜻)가 다른 것처럼, 검색에서도 같은 축이 갈립니다.

앞으로 다시 만납니다 — 15차시에서 둘을 합치는 하이브리드 검색 을 다룹니다.


3. 임베딩 모델 고르기

3.1 Claude API는 임베딩을 주지 않는다

Claude API는 글을 생성 하는 API이고, 임베딩 기능은 제공하지 않습니다. 임베딩은 별도 모델 을 씁니다.

선택지예실행 위치 (축 ④)장점주의
오픈소스 모델sentence-transformers로 다국어 모델 (예: BAAI/bge-m3)내 서버문서가 밖으로 안 나감, 호출 비용 없음서버 자원 · 설치 · 운영
임베딩 API 서비스예: Voyage AI 등외부설치 없음, 관리 쉬움⚠️ 규정 원문 · 질문이 외부로 전송, 호출당 비용

고르는 기준: ① 한국어를 잘 다루는가 (모델 설명서에서 다국어 · 한국어 지원 확인) ② 문서가 밖으로 나가도 되는가 ③ 벡터 크기와 속도 ④ 비용. 모델 이름과 성능 순위는 자주 바뀌므로 공식 문서 · 모델 설명서로 확인 합니다.

from sentence_transformers import SentenceTransformer

embedder = SentenceTransformer("BAAI/bge-m3")        # 예시 모델 — 실제 선택은 평가로
vectors = embedder.encode([c["text"] for c in chunks], normalize_embeddings=True)

🔍 읽는 포인트 : 모델 이름 한 줄과 encode 한 줄입니다. normalize_embeddings=True는 벡터 길이를 1로 맞춰 코사인 유사도 계산을 단순하게 합니다.

3.2 ⚠️ 적재와 질의에 같은 모델

임베딩 모델마다 좌표계가 다릅니다. A 모델로 만든 청크 벡터와 B 모델로 만든 질문 벡터는 같은 지도 위의 점이 아닙니다. 에러도 나지 않고(벡터 크기가 우연히 같다면) 엉뚱한 결과만 나옵니다.

상황결과
적재 A 모델, 질의 A 모델⭕ 정상
적재 A 모델, 질의 B 모델❌ 결과가 무작위에 가까움 (크기가 다르면 에러)
모델을 바꾸고 싶다⭕ 모든 청크를 새 모델로 다시 적재 (7절)

💡 사용한 임베딩 모델 이름을 컬렉션 정보나 설정 파일에 기록해 두세요. 몇 달 뒤 누군가 질의 쪽 모델만 바꾸는 사고를 막습니다.


4. 벡터 DB — 뜻으로 찾는 창고

4.1 정의와 경계

벡터 DB (Vector Database) — [데이터베이스]인데, [ 벡터를 저장하고, 주어진 벡터와 가까운 것을 빠르게 찾는 데 특화되어 있다 ]는 점에서 값이 정확히 같은 행을 찾는 일반 관계형 DB와 구별된다.

이름형태맞는 곳
Chroma파이썬에서 바로 쓰는 가벼운 DB, 파일로 저장⭐ 실습 · 작은 서비스 (이 노트의 예시)
FAISS벡터 검색 라이브러리 (DB 기능은 직접)대량 벡터 · 빠른 검색
pgvectorPostgreSQL 확장이미 Postgres를 쓰는 회사
Qdrant독립 서버운영 규모 서비스

4.2 Chroma로 저장하고 찾기

import chromadb

db = chromadb.PersistentClient(path="./office_index")          # 디스크에 저장
col = db.get_or_create_collection(name="policies")             # 거리 방식 설정은 버전마다 다름 — 문서 확인

col.add(ids=[c["id"] for c in chunks],
        documents=[c["text"] for c in chunks],
        embeddings=vectors.tolist(),
        metadatas=[c["metadata"] for c in chunks])

q_vec = embedder.encode(["결혼하면 며칠 쉬어?"], normalize_embeddings=True)
res = col.query(query_embeddings=q_vec.tolist(), n_results=5,
                where={"access_dept": {"$in": ["ALL", session.dept]}})

🔍 읽는 포인트

  • PersistentClient(path=...) — 인덱스를 디스크의 폴더 에 저장합니다(5절).
  • col.add(...) — 네 가지를 같은 순서로 넣습니다: 번호(ids) · 원문 · 벡터 · 메타데이터(12차시).
  • embedder.encode([...질문...]) — 질문도 적재 때와 같은 embedder 로 바꿉니다(3.2).
  • n_results=5 — 가까운 청크 5개. 이 숫자가 뒤에서 말하는 k 입니다.
  • where= — ⭐ 메타데이터 필터. 다음 절의 권한 장치입니다.

5. 축 ① — 인덱스는 디스크에 영구

이번 요청의 messages (9차시)벡터 인덱스
어디에앱 메모리디스크 (./office_index)
언제 만드나요청마다적재할 때 한 번
서버를 재시작하면사라짐남아 있음
만드는 비용작음큼 — 청크 전부를 임베딩

임베딩은 청크 수만큼 모델을 돌려야 해서 비쌉니다. 그래서 적재는 미리 한 번 하고 디스크에 두며, 질의할 때는 질문 하나만 임베딩합니다(12차시 2절의 적재 ↔ 질의). Chroma에도 메모리 전용 클라이언트가 있지만, 그 경우 프로그램이 꺼지면 인덱스가 사라져 매번 다시 적재해야 합니다.


6. 메타데이터 필터 — 권한은 검색에서 거른다

12차시에서 청크마다 access_dept를 붙였습니다. 이제 그것을 씁니다.

❌ 부탁⭕ 강제
모든 청크를 검색한 뒤, 프롬프트에 "인사팀 전용 문서는 답에 쓰지 마"검색 요청의 where에 사용자 부서를 넣어 애초에 꺼내지 않음
인젝션 한 줄이면 뚫림 (10차시 5절)모델은 그 청크를 본 적이 없음

⭐ 필터 값 session.dept는 앞에서 배운 권한 경계(8차시)처럼 로그인 세션 에서 옵니다. 직원이 "나 인사팀이야"라고 써도 바뀌지 않습니다.


7. 근사 탐색과 적재 재실행

7.1 ANN — 빠르게, 대신 가끔 놓친다

근사 최근접 탐색 (ANN, Approximate Nearest Neighbor) — [벡터 검색 방식]인데, [ 모든 벡터와 비교하지 않고 미리 만들어 둔 길잡이 구조(예: HNSW)를 따라가 가까운 후보를 빠르게 찾는다 ]는 점에서 전부 비교하는 정확 탐색과 구별된다.

정확 탐색근사 탐색 (ANN)
속도벡터 수에 비례해 느려짐대량에서도 빠름
정확도진짜 가장 가까운 k개가끔 하나쯤 놓칠 수 있음
맞는 규모수천 개수십만 개 이상

오피스봇의 규정 청크는 수천 개 수준이라 어느 쪽이든 충분히 빠릅니다. 대부분의 벡터 DB는 ANN 인덱스를 기본으로 쓰며, 정확도와 속도를 맞바꾸는 설정값을 둡니다(세부는 각 DB 문서 확인).

7.2 문서가 개정되면 — 적재를 다시

일어난 일할 일
취업규칙 개정그 문서의 청크를 source 기준으로 지우고 새로 로딩 → 청킹 → 임베딩 → 저장
문서 폐지그 문서의 청크 삭제
임베딩 모델 교체⚠️ 모든 문서 전체 재적재 (3.2)
청킹 방식 변경전체 재적재
col.delete(where={"source": "취업규칙_2025.pdf"})     # 옛 판 청크 삭제 후 새 판을 add

🔍 읽는 포인트 : 옛 청크를 지우지 않고 새 청크만 넣으면, 검색 결과에 옛 규정과 새 규정이 함께 나와 모델이 옛 일수로 답할 수 있습니다. 청크 id를 "파일명#조항#순번"처럼 정해 두면 무엇이 어느 판인지 추적하기 쉽습니다.

앞으로 다시 만납니다 — 14차시에서 이 검색 결과를 프롬프트에 넣어 근거로 답하게 하고, 15차시에서 검색이 놓치는 질문을 측정하고 고칩니다.


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

지시

12차시의 chunks.jsonl을 임베딩해서 Chroma에 저장하고 검색 함수를 만들어줘.
- 참고: chromadb, sentence-transformers 공식 문서. 설치 버전과 확인한 주소를 보고에 적을 것
- 임베딩: 한국어를 지원하는 오픈소스 다국어 모델을 내 서버에서 실행 (외부 임베딩 API 쓰지 말 것)
  모델 이름을 설정 파일 한곳에 두고, 적재와 질의가 같은 설정을 읽게 할 것
- PersistentClient로 ./office_index에 저장. 청크 id는 "파일명#조항#순번"
- search(question, dept, k=5): where 필터로 access_dept가 "ALL" 또는 dept인 청크만
- 재적재 함수 reload(source): 해당 source 청크 삭제 후 다시 적재
테스트 질문 10개(내가 준 목록)를 dept="개발팀"과 dept="인사팀"으로 각각 검색
추측하지 말고 실행 출력 원문을 붙여.
보고 형식: [질문 | dept | 1위 청크 id | 1위 유사도 | 5개 안에 정답 조항이 있나] 표
 + 서버(파이썬) 재시작 후 같은 검색을 다시 돌린 출력

받을 증거

  • 위 형식의 표와 검색 출력 원문
  • 재시작 후에도 같은 결과가 나온 출력
  • reload("취업규칙_2026.pdf") 전후의 청크 수

내가 직접 확인할 것

볼 것이걸로 아는 것
"결혼하면 며칠 쉬어?"의 상위 결과에 경조휴가 조항이 있는가의미 검색이 동작하는가 (1.3, 2절)
"제23조 알려줘"의 1위가 제23조인가번호 질문에서 의미 검색의 약점 (2절 — 15차시로)
개발팀으로 검색한 결과에 인사 평가 지침 청크가 하나도 없는가권한 필터가 검색 단계에서 강제되는가 (6절)
재시작 후 결과가 같은가인덱스가 디스크에 영구 저장되는가 (5절)
설정 파일의 모델 이름이 한 곳에만 있는가적재 · 질의 같은 모델 (3.2)
reload 후 청크 수가 늘지 않고 같은가옛 청크가 남지 않는가 (7.2)

부록 A. 스스로 확인하기

#질문답이 있는 곳
1임베딩은 인코딩 · 토큰화와 무엇이 다른가?1.1
2코사인 유사도는 무엇을 재나?1.3
3의미 검색이 약하고 키워드 검색이 강한 질문의 예는?2절
4Claude API로 임베딩을 만들 수 없을 때의 선택지와 각각의 축 ④ 위치는?3.1
5적재와 질의에 다른 임베딩 모델을 쓰면?3.2
6Chroma 코드에서 권한을 거르는 줄은?4.2, 6절
7벡터 인덱스를 디스크에 두는 이유는?5절
8ANN은 무엇을 얻고 무엇을 내주나?7.1
9규정이 개정되면 어떤 순서로 다시 적재하나?7.2

부록 B. 자주 하는 실수

실수바로잡기
"Claude API로 임베딩하면 되겠지"❌ 임베딩은 별도 모델
질의 쪽 임베딩 모델만 새 것으로 교체❌ 좌표계가 달라짐. 전체 재적재
영어 전용 임베딩 모델로 한국어 규정 적재⚠️ 한국어 · 다국어 지원 확인
권한을 프롬프트로 "그 문서는 쓰지 마"❌ 검색의 where 필터로 강제
메모리 전용 클라이언트로 운영⚠️ 재시작하면 인덱스가 사라짐
개정판을 add만 하고 옛 판을 안 지움❌ 옛 규정이 검색됨. source 기준 삭제 후 적재
외부 임베딩 API에 사내 문서를 확인 없이 전송⚠️ 무엇이 밖으로 나가는지 먼저 결정 (축 ④)

부록 C. NotebookLM 복습 프롬프트

이 13차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"임베딩 ↔ 인코딩", "키워드 검색 ↔ 의미 검색(구문론 ↔ 의미론)", "적재와 질의에 같은 모델", "메타데이터 필터로 권한 강제"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.