RAG 및 검색을 위한 텍스트 임베딩 - Python, Ollama, OpenAI 호환 API
RAG 임베딩 - Python, Ollama, OpenAI API.
검색 증강 생성 (RAG)을 공부 중이시라면, 이 섹션에서는 텍스트 임베딩이 무엇인지, 검색 및 검색 (retrieval) 과 어떻게 연관되는지, 그리고 Ollama 또는 OpenAI 호환 HTTP API(많은 llama.cpp 기반 서버에서 제공하는 방식) 를 사용하여 Python에서 두 가지 일반적인 로컬 설정을 호출하는 방법을 쉽게 설명합니다.

Go 클라이언트 및 Ollama SDK 비교에 대해서는 Go SDKs for Ollama — comparison with examples을 참조하세요.
텍스트 임베딩이란 무엇인가요?
텍스트 임베딩은 임베딩 모델이 생성하는 벡터 (실수 리스트) 입니다. 이 모델은 가변 길이의 텍스트를 고정 차원 공간으로 매핑하여, 의미적으로 유사한 텍스트들이 거리 또는 유사도 측정 (일반적으로 L2 정규화 벡터에 대한 코사인 유사도) 하에서 서로 가까이 위치하도록 합니다.
임베딩은 토큰 ID 와 동일하지 않으며 채팅 완성 (chat completion) 과도 동일하지 않습니다. 이는 검색, 군집화, 중복 제거 및 RAG 에서의 검색을 위해 사용하는 표현 레이어입니다.
일반적인 사용 사례
| 사용 사례 | 임베딩의 역할 |
|---|---|
| 의미 기반 검색 / RAG 검색 | 쿼리와 문서 청크를 임베딩한 후 유사도에 따라 순위를 매겨 관련 패시지를 가져옵니다. |
| 임베딩 모델 기반 재순위화 (Reranking) | 쿼리와 각 후보를 임베딩한 후 유사도로 쌍을 점수화합니다 (참고: 임베딩 모델 기반 재순위화). |
| 군집화 및 중복 제거 | 모든 예시를 수동으로 라벨링하지 않고도 임베딩 공간에서 항목을 그룹화하거나 중복을 제거합니다. |
| 분류 스타일 점수 부여 | 같은 공간 내에서 텍스트를 프로토타입 설명 또는 클래스 이름과 비교합니다 (모델에 따라 패턴이 다름). |
멀티모달 설정 (이미지 - 텍스트 및 관련 개념) 에 대해서는 크로스 모달 임베딩을 참조하세요.
RAG 파이프라인 내부의 임베딩
일반적인 오프라인 경로는 다음과 같습니다:
- 문서를 청크화합니다 (크기, 겹침, 구조가 중요합니다 — RAG 의 청킹 전략 참조).
- 각 청크를 임베딩하고, 선택적으로 메타데이터 (출처 ID, 섹션, ACL) 를 저장합니다.
- 벡터를 메모리, 라이브러리 인덱스 또는 벡터 데이터베이스에 인덱싱합니다 (트레이드오프는 RAG 용 벡터 저장소 비교) 에서 확인 가능).
쿼리 시점:
- 사용자 쿼리를 임베딩합니다 (짧은 문자열 하나 또는 작은 배치).
- 벡터 검색을 통해 상위 k 개의 유사한 청크를 검색합니다 (선택적으로 키워드/하이브리드 검색 포함).
- 검색된 일반 텍스트 청크로 프롬프트를 구성하고 채팅 모델을 호출합니다.
중요한 뉘앙스 — 채팅 API 의 대형 언어 모델은 임의의 임베딩 텐서가 아니라 텍스트 (및 도구) 를 소비합니다. 임베딩은 주입할 텍스트를 선택하는 데 사용됩니다. “미리 계산된 임베딩으로 LLM 에 쿼리한다"는 표현을 보게 되면, 실제로는 임베딩으로 검색한 후 선택된 텍스트를 LLM 으로 전송한다는 의미입니다.
Ollama 를 사용하여 임베딩 가져오기 (Python)
Ollama 는 HTTP API 를 노출합니다. 임베딩을 호출하려면 Ollama 호스트 (기본 http://127.0.0.1:11434) 에서 **POST /api/embed**을 호출하세요. JSON 본문에는 model 이름과 input(문자열 또는 문자열 리스트) 이 포함됩니다. 응답에는 입력과 정렬된 벡터 리스트인 **embeddings**가 포함됩니다.
httpx 를 설치하거나 (**requests**를 같은 방식으로 사용) 하세요.
import httpx
OLLAMA = "http://127.0.0.1:11434"
MODEL = "nomic-embed-text" # pull 한 임베딩 모델로 교체
def embed_ollama(texts: list[str]) -> list[list[float]]:
r = httpx.post(
f"{OLLAMA}/api/embed",
json={"model": MODEL, "input": texts},
timeout=120.0,
)
r.raise_for_status()
data = r.json()
return data["embeddings"]
if __name__ == "__main__":
q = "What is retrieval-augmented generation?"
chunks = [
"RAG combines retrieval with generation.",
"Embeddings map text into vector space for similarity search.",
]
qv = embed_ollama([q])[0]
doc_vs = embed_ollama(chunks)
print(len(qv), len(doc_vs), len(doc_vs[0]))
운영 노트
- 먼저 모델을 풀 (pull) 합니다 (선택한 태그에 대해
ollama pull …). Ollama 의 Qwen3 클래스 모델에 대해서는 Ollama 의 Qwen3 임베딩 및 리랭커 모델을 참조하세요. - 부하 하에서 임베딩 처리량은 Ollama 가 작업을 스케줄링하는 방식과 상호작용합니다 — Ollama 가 병렬 요청을 처리하는 방식을 참조하세요.
OpenAI 호환 서버를 사용하여 임베딩 가져오기 (Python)
많은 로컬 서버 (일반적인 llama.cpp HTTP 설정 포함) 는 OpenAI 호환 루트인 POST /v1/embeddings 등을 노출합니다. 공식 openai Python 패키지를 사용하고 **base_url**을 서버의 …/v1 루트로 설정할 수 있습니다.
from openai import OpenAI
# 예시 — 호스트, 포트, 모델 ID 를 서버 값으로 교체
client = OpenAI(
base_url="http://127.0.0.1:8080/v1",
api_key="not-needed", # 많은 로컬 서버는 이를 무시함
)
def embed_openai_compatible(text: str, model: str) -> list[float]:
r = client.embeddings.create(model=model, input=text)
return r.data[0].embedding
if __name__ == "__main__":
v = embed_openai_compatible("hello from llama.cpp", "your-embedding-model-id")
print(len(v))
왜 두 가지 패턴을 하나의 페이지에 보관해야 하나요? 개념 (청크, 임베딩, 인덱싱, 쿼리, 텍스트 검색) 은 동일하며, 오직 HTTP 표면만 다릅니다. 워크숍 스타일의 기사는 두 URL 아래에서 동일한 서술을 중복하지 않도록 합니다.
벡터 저장 및 쿼리
최소한 각 청크마다 세 가지를 저장해야 합니다 — 벡터, 텍스트, 메타데이터 (출처 ID, 오프셋, ACL). 빠른 프로토타입을 위해 모든 것을 Python 리스트에 보관하고 NumPy 또는 scikit-learn을 사용하여 코사인 유사도를 사용할 수 있습니다. 성장하는 데이터의 경우 벡터 데이터베이스 또는 라이브러리 인덱스(FAISS 등) 를 사용하세요 — 제품 수준의 트레이드오프는 RAG 용 벡터 저장소 비교를 참조하세요.
개념적 쿼리 루프:
query_vec = embed(query)neighbors = index.search(query_vec, k)context = "\n\n".join(chunk.text for chunk in neighbors)context와 사용자 질문을 채팅 API 로 전송합니다.
검색 후 재순위화 (Reranking)
리랭커(일반적으로 크로스 인코더 또는 두 번째 스코어링 모델) 는 벡터 검색 후 상위 후보의 순서를 다시 정렬할 수 있습니다. 이 사이트에는 임베딩 모델 기반 재순위화 및 Ollama 와 Qwen3 임베딩을 사용한 Go 재순위화를 포함한 Python 및 Go 예제가 있습니다.
이 사이트의 관련 글
| 주제 | 글 |
|---|---|
| 전체 RAG 아키텍처 | RAG 튜토리얼 — 아키텍처, 구현, 프로덕션 |
| 임베딩 전 청킹 | RAG 의 청킹 전략 |
| 벡터 DB 선택 | RAG 용 벡터 저장소 비교 |
| Ollama 의 Qwen3 | Ollama 의 Qwen3 임베딩 및 리랭커 |
| 크로스 모달 | 크로스 모달 임베딩 |
| Ollama CLI 및 팁 | Ollama 치트시트 |
| Go + Ollama | Go 에서 Ollama 사용 — SDK 비교 |
유용한 링크
- Ollama — 모델 및 런타임
- Ollama API — embed —
/api/embed에 대한 업스트림 API 참조 - OpenAI Python 라이브러리 — OpenAI 호환
base_url과 함께 작동