Custom Vector Stores: 벡터 저장소를 내 손으로
Custom Vector Stores: 벡터 저장소를 내 손으로
기본적으로 인덱스는 파싱→청킹→임베딩→관리형 벡터 저장소 쓰기까지 전부 자동으로 처리해요. 그런데 벡터 저장소를 꼭 직접 갖고 싶을 때가 있어요 — LlamaCloud가 관리하지 않는 데이터베이스에 자체 호스팅 중이거나, 데이터를 내 인프라에만 두고 싶을 때죠. 이럴 때 관리형 내보내기를 끄고 raw 파싱 출력을 직접 내려 받을 수 있어요.
출처: 공식문서
이 모드에서도 LlamaCloud가 디렉토리 관리·파싱·동기화 오케스트레이션은 계속 처리해요. 대신 청킹·임베딩·DB 쓰기를 내가 맡는 거예요.
parse-only 인덱스 만들기
인덱스를 만들 때 vector_target="DISABLED"를 넘겨요. 파이프라인이 다운로드 전용 내보내기로 전환되면서, 파싱 출력이 관리형 벡터 저장소 대신 객체 스토리지에 기록돼요.
index = await client.beta.indexes.create(
source_directory_id=directory.id,
vector_target="DISABLED",
)
일반 인덱스와 같은 방식으로 ready 상태가 될 때까지 기다리면 돼요 (getting started guide 참고).
파싱 출력 다운로드
소스 디렉토리의 각 파일은 페이지별 마크다운(header, text, footer), 구조화 항목, 첨부, 출처 메타데이터를 담은 JSON 페이로드를 만들어요. 디렉토리 파일을 나열하고 각 페이로드를 presigned URL로 내려 받아요.
import httpx
# 소스 디렉토리의 파일 나열
files_resp = await client.beta.directories.files.list(
directory_id=directory.id,
)
# 각 디렉토리 파일 ID는 스토리지의 parsed-output JSON 객체를 가리킨다.
# presigned URL을 해석해 다운로드한다.
async with httpx.AsyncClient() as http:
for f in files_resp.items:
presigned = await client.files.get(f.file_id)
response = await http.get(presigned.url)
response.raise_for_status()
parsed = response.json()
# parsed["parse"] holds the parsed output payload
매 동기화 후 이 루프를 다시 돌려 변경분을 반영하세요. 각 페이로드의 content_fingerprint_hash와 source_modified_at 필드로 마지막 내보내기 이후 변경되지 않은 파일은 건너뛸 수 있어요.
청킹·임베딩·내 저장소로 밀어넣기
여기부터는 일반적인 커스텀 RAG 파이프라인과 같아요.
- 페이지 경계를 문자 오프셋으로 추적하면서 페이지별 마크다운을 연결해요.
- 선호하는 청커로 텍스트를 청킹해요.
- 선호하는 임베딩 모델로 청크를 임베딩해요.
(parsed_directory_file_id, export_config_id)키로 DB에 청크를 써요. 재파싱된 파일이 이전 내보내기를 중복 없이 완전히 대체하도록 하기 위함이에요.
레퍼런스 구현
index-v2-data-sinks 저장소에 여러 데이터베이스용 완전한 실행 가능한 레퍼런스 익스포터가 있어요.
- MongoDB (Atlas vector search)
- PostgreSQL + pgvector
- Qdrant
- Pinecone
- Turbopuffer
- Azure AI Search
각 익스포터는 인덱스/컬렉션 프로비저닝, 멱등 재내보내기를 위한 결정적 ID, 파일별 delete-then-insert, 증분 동기화용 스냅샷 목록을 처리해요. export/base.py의 공유 Exporter 프로토콜이 새 싱크를 추가할 때 구현해야 하는 계약이에요.
class Exporter(Protocol):
async def export(self, outputs, *, project_id, embeddings=None, embedding_model=None): ...
async def delete_file(self, *, parsed_directory_file_id, export_config_id): ...
async def delete_files(self, *, parsed_directory_file_ids, export_config_id): ...
async def list_snapshots(self, *, export_config_id): ...
코딩 에이전트를 이 저장소에 가리켜 작업 예제로 삼거나, 마음에 드는 싱크를 복사해 시작점으로 쓰거나, 원하는 스토어에 맞춰 프로토콜을 구현하면 돼요.
주의사항
client.beta.*의 검색·채팅·파일 작업은 관리형 벡터 저장소를 질의해요.vector_target="DISABLED"면 이 엔드포인트는 질의할 대상이 없어요 — 검색은 내 DB에서 처리해야 해요.- 소스 디렉토리에서 파일이 제거될 때 내 DB의 레코드 정리는 내 책임이에요. 레퍼런스 구현의
list_snapshots()패턴이 현재 디렉토리 상태와 대조하는 방법을 보여줘요.
더 알아보기
- Index 시작 가이드 — 인덱스 만들기부터 검색까지
- Syncing — 파일 변경 후 인덱스 재동기화