들어가며
외부 API에 모든 걸 던지지 않고, 로컬 머신에서 임베딩을 만들고 벡터로 검색하는 흐름을 구성해보면 LLM 앱이 어떻게 돌아가는지 감이 잡힐 것 같았다. 이번에는 그 조합에서 가장 자주 언급되는 Ollama + Chroma DB가 각각 무엇이고, 왜 같이 묶어 쓰는지를 정리한다.
1. Ollama - 로컬 LLM 런타임
Ollama는 로컬 환경에서 LLM을 쉽게 실행하고 관리하는 런타임/도구다. macOS, Windows, Linux에서 쓸 수 있고 로컬 API도 제공한다. 설치 후 백그라운드에서 실행되며, API는 기본적으로 http://localhost:11434에서 노출된다.
핵심은 모델 자체가 아니라 모델 실행 환경이라는 점이다. 즉 Ollama는 특정 AI 서비스 하나가 아니라, 여러 모델을 같은 인터페이스로 실행하게 해주는 레이어다.
# 모델 실행 - 한 줄로 끝
ollama run gemma3API 관점에서는 다음과 같은 기능을 제공한다.
- chat - 대화형 응답 생성
- generate - 일반 텍스트 생성
- embed - 임베딩 벡터 생성
세 엔드포인트가 분리되어 있어서, 앱에서 로컬 모델을 HTTP로 호출하는 구조를 만들기 쉽다.
2. Chroma DB - 임베딩을 저장하는 벡터 DB
Chroma는 공식 문서에서 스스로를 AI를 위한 오픈소스 데이터 인프라로 소개한다. 임베딩 저장, 메타데이터 저장, 벡터 검색, 필터링, retrieval을 제공한다. 한 줄로 정리하면 "비슷한 의미의 문서"를 찾는 데 특화된 벡터 DB다.
기본 저장 단위는 collection이다. 하나의 collection 안에 다음 4종의 데이터가 묶여 들어간다.
documents- 원문 텍스트embeddings- 벡터metadatas- 필터링용 부가 정보ids- 식별자
collection
├── documents: ["배포 프로세스는...", "온보딩 가이드는...", ...]
├── embeddings: [[0.12, -0.04, ...], [0.55, 0.21, ...], ...]
├── metadatas: [{tag: "infra"}, {tag: "hr"}, ...]
└── ids: ["doc_001", "doc_002", ...]Python, TypeScript, Rust용 퍼스트파티 클라이언트를 모두 제공한다. 그래서 로컬 실험부터 애플리케이션 연동까지 비교적 쉽게 구성된다.
3. 왜 같이 쓰는가
둘의 역할이 깔끔하게 분리되어서 궁합이 좋다.
| 도구 | 역할 |
|---|---|
| Ollama | 텍스트를 이해/생성하는 모델 실행 (임베딩 + 답변) |
| Chroma | 문서 임베딩 저장, 검색, 필터링 |
특히 Ollama 문서는 임베딩 기능을 semantic search, retrieval, RAG에 쓰라고 안내한다. 다시 말해 Ollama가 문서를 벡터로 바꾸고, Chroma가 그 벡터를 저장하고 검색하는 구조로 자연스럽게 연결된다.
이 조합이 가장 많이 쓰이는 시나리오가 RAG (Retrieval-Augmented Generation) 다. 사내 문서나 개인 노트를 Chroma에 저장해두고, 사용자의 질문이 들어오면 관련 문서를 먼저 찾아 그 내용을 Ollama 모델에게 함께 넘겨 답변 품질을 높이는 방식이다.
질문 → [Ollama embed] → 질문 벡터
↓
[Chroma query]
↓
유사 문서 chunk 추출
↓
질문 + chunk → [Ollama chat] → 최종 답변4. 연계 방식
방식 1 - Ollama의 /api/embed를 직접 호출
가장 직관적인 방식. Ollama의 POST /api/embed로 텍스트(또는 텍스트 배열)의 임베딩을 만들고, 그 벡터를 Chroma collection에 직접 넣는다.
[애플리케이션]
├─ POST /api/embed (Ollama) → 벡터 받음
└─ collection.add(embeddings=...) → Chroma에 저장장점은 임베딩 생성 과정을 명시적으로 통제할 수 있다는 점이다.
- 어떤 모델로 벡터를 만들지
- 입력을 어떻게 쪼갤지(chunking)
- 어느 시점에 재임베딩할지
이 모든 결정이 애플리케이션 코드에 노출된다.
방식 2 - Chroma의 OllamaEmbeddingFunction 사용
Chroma는 Ollama용 embedding function wrapper를 공식 제공한다. collection을 만들 때 embedding function을 Ollama로 지정해두면, 문서를 넣을 때 Chroma가 알아서 Ollama를 호출해 임베딩을 만든다.
[애플리케이션]
└─ collection.add(documents=...) → Chroma 내부에서 Ollama 호출 + 저장장점은 코드가 단순해진다는 것. 애플리케이션 입장에서는 문서를 넣고 질의만 하면 되고, 임베딩 생성 과정은 collection 설정에 숨겨진다.
방식 1은 명시적 통제, 방식 2는 단순함. 어떤 게 맞는지는 임베딩 파이프라인을 얼마나 직접 다루고 싶냐에 따라 갈린다.
5. 실제 구현 흐름
1. 문서를 적절한 길이로 분할 (chunking)
2. Ollama로 각 chunk의 임베딩 생성
3. Chroma collection에 documents + embeddings + metadatas 저장
4. 사용자 질문 → 같은 임베딩 모델로 벡터화
5. Chroma에서 가장 유사한 chunk 검색
6. 검색된 chunk를 프롬프트에 붙여 Ollama chat으로 답변 생성이 흐름은 Ollama의 embedding/chat API와 Chroma의 add/query 구조를 그대로 조합한 형태다.
6. 예시 - 팀 위키 챗봇
"우리 팀 위키 문서 500개를 기반으로 답하는 로컬 챗봇"을 만든다고 하면 이렇게 구성된다.
- 문서 500개를 여러 chunk로 분할
- 각 chunk를 Ollama 임베딩 모델로 벡터화
- Chroma에
문서 본문 + 문서 ID + 작성일 + 태그 + 임베딩형태로 저장 - 사용자가 "배포 프로세스가 어떻게 되지?"라고 묻는 순간, 질문을 같은 임베딩 모델로 변환
- Chroma가 유사한 배포 관련 chunk 몇 개 반환
- 그 chunk들을 Ollama chat API에 넣어서 근거 기반 답변 생성
Chroma는 metadata filtering도 지원하므로 "2026년 문서만", "운영팀 태그만" 같이 범위를 좁히는 것도 가능하다. 이게 일반 키워드 검색과 가장 큰 차이다.
7. 같이 쓸 때의 장점
- 로컬 중심 구성 - Ollama도 Chroma도 로컬에서 시작 가능. 외부 API 의존도를 낮출 수 있음
- 역할 분담이 명확 - 임베딩/생성은 Ollama, retrieval은 Chroma. 각자 책임이 분리되어 디버깅이 쉬움
- 모델 교체가 비교적 쉬움 - 임베딩 모델이나 생성 모델을 바꿔도 전체 구조는 그대로. Ollama가 모델 실행 인터페이스를 통일해주기 때문
- 메타데이터 기반 검색 - 단순 유사도 검색뿐 아니라 속성별 필터링이 가능해서 실제 업무용 검색에 유리
8. 주의할 점
임베딩 모델과 답변 모델은 다르다
문서 검색용 임베딩과 최종 답변 생성용 LLM은 역할이 다르다. 보통 같은 모델일 필요가 없다. Ollama도 embed와 chat/generate를 분리해서 제공하는 이유다. 임베딩 모델은 "의미 거리를 잘 재는" 능력, 답변 모델은 "자연스럽게 글을 쓰는" 능력이 우선이라 최적점이 다르다.
chunking 품질이 retrieval 품질을 결정한다
Chroma는 저장과 검색을 잘해주지만, 문서를 어떻게 자르냐에 따라 retrieval 품질이 크게 갈린다. 너무 길면 한 chunk에 여러 주제가 섞여 검색 정밀도가 떨어지고, 너무 짧으면 맥락이 소실된다. Chroma의 query는 결국 저장된 단위 기준으로 동작하므로, chunking은 RAG 품질의 첫 관문이다.
하드웨어 제약
Ollama는 로컬 머신 자원을 그대로 쓴다. 큰 모델일수록 RAM/VRAM 요구치가 가파르게 올라간다. 사양이 받쳐주지 않으면 답변 속도가 실용 범위를 벗어난다.
임베딩 재생성 비용
임베딩 모델을 바꾸면 기존 벡터를 전부 재생성해야 일관된 검색 품질이 유지된다. 새 모델로 만든 질문 벡터를 옛 모델로 만든 문서 벡터들과 비교하면 의미 공간 자체가 어긋난다. 운영 단계에서 모델 교체는 곧 마이그레이션 비용이라는 걸 기억해두자.
정리
- Ollama는 로컬에서 LLM과 임베딩 모델을 실행하는 도구
- Chroma는 그 임베딩을 저장하고 검색하는 벡터 DB
- 둘을 묶으면 "문서 임베딩 생성 → 벡터 저장 → 유사 문서 검색 → 검색 결과 기반 답변" 흐름이 만들어진다. 이게 가장 전형적인 로컬 RAG 아키텍처
- 연결 방식은 두 가지
- Ollama embed API를 직접 호출해서 Chroma에 넣는 방식 (명시적 통제)
- Chroma의
OllamaEmbeddingFunction을 쓰는 방식 (단순한 코드)