
현대적인 RAG 봇이 동작하는 방식
좋은 RAG 파이프라인은 “문서를 벡터 데이터베이스에 넣는 것” 이상입니다. 기본 흐름은 다음과 같습니다:| Step | What happens |
|---|---|
| Load | 로컬 Markdown, 텍스트, reStructuredText 파일 읽기 |
| Chunk | 긴 문서를 겹치는 섹션으로 분할 |
| Embed | Venice 임베딩으로 청크를 벡터로 변환 |
| Store | Qdrant에 벡터와 출처 메타데이터 저장 |
| Retrieve | 사용자의 질문을 임베딩하고 벡터 검색 실행 |
| Re-rank | cross-encoder로 최선의 후보를 재점수화 |
| Answer | 인용 지침과 함께 최선의 context를 Venice chat 모델로 전송 |
의존성 설치
Venice가 OpenAI 호환 API를 노출하므로 OpenAI Python SDK를 사용합니다. FastEmbed 지원이 있는 Qdrant Python 클라이언트도 함께 사용합니다:requirements.txt를 만드세요:
모델 선택
rag_bot.py라는 파일을 만들고, 임포트, 데이터 구조, API URL, 모델 이름을 추가해 시작하세요:
base_url과 API 키만 바꾸면 이전 가능합니다.
다음으로 사용 가능한 Venice 모델을 나열할 수 있습니다:
Venice와 Qdrant 클라이언트 생성
임베딩과 chat completion 모두를 위한 하나의 OpenAI 호환 Venice 클라이언트를 만드세요:| Mode | When to use it |
|---|---|
QdrantClient(":memory:") | 빠른 로컬 데모와 테스트 |
QdrantClient(path="./qdrant_data") | 로컬 영구 저장 |
QdrantClient(url=..., api_key=...) | 원격 또는 매니지드 Qdrant 클러스터 |
문서 로드 및 청킹
이 튜토리얼에서는 봇이 로컬 파일이나 폴더를 ingest하게 합니다..md, .rst, .txt 파일로 시작하세요:
1000 문자와 150 문자 오버랩으로 시작하는 것이 혼합 Markdown과 텍스트 문서에 좋은 기본값입니다. 더 작은 청크는 정밀도를 개선할 수 있습니다. 더 큰 청크는 더 많은 context를 보존할 수 있습니다. 올바른 설정은 종종 저장하는 문서의 종류에 따라 다릅니다.
Venice로 문서 임베딩
청크가 있으면 배치로 임베딩합니다:Qdrant에 벡터 저장
포인트를 삽입하기 전에 올바른 벡터 크기로 Qdrant 컬렉션을 만드세요. 벡터 크기를 알기 가장 쉬운 방법은 첫 배치를 임베딩한 다음len(embeddings[0])을 사용하는 것입니다.
source, chunk_index, 콘텐츠에서 파생된 결정적 UUID를 사용하세요. 그러면 변경되지 않은 청크에 대해 반복 ingest가 멱등이 됩니다.
후보 청크 검색
질문 시점에 봇은 사용자의 질문을 임베딩하고 Qdrant에 상위 벡터 매칭을 요청합니다:limit는 후보 수입니다. 다음 단계에서 재순위할 것이므로 보통 모델에 보낼 청크 수보다 더 높아야 합니다. 좋은 기본값은 8개 후보를 검색하고 상위 4개를 chat 모델로 보내는 것입니다.
FastEmbed로 재순위
이제 검색이 훨씬 더 똑똑하게 느껴지게 만드는 부분을 추가합니다.- 벡터 검색으로 더 큰 후보 집합 검색.
- 그 후보들을 로컬에서 재순위.
- 상위 몇 개 청크를 언어 모델로 전송.
candidate_k=8, top_k=4입니다. 올바른 출처가 종종 근처에 있지만 최종 context에 들어가지 못한다면 candidate_k를 늘리세요.
Venice Chat Completion으로 답변
context가 선택되면 출처 번호로 포맷하세요:봇 실행
조각들을 스크립트로 조립한 다음rag_bot.py로 저장하세요. 첫 번째 단순 실행은 자체 파일을 ingest하기 전에 파이프라인을 검증할 수 있도록 몇 가지 내장 샘플 문서를 사용할 수 있습니다:
유용한 CLI 옵션
코드 수정 없이 봇을 튜닝할 수 있도록 주요 검색 손잡이를 CLI 옵션으로 노출하세요:| Option | Default | What it controls |
|---|---|---|
--candidate-k | 8 | 재순위할 벡터 검색 결과 수 |
--top-k | 4 | chat 모델로 보낼 재순위된 청크 수 |
--chunk-size | 1000 | 오버랩 전 최대 청크 크기 |
--chunk-overlap | 150 | 인접 청크 사이에 반복되는 문자 수 |
--embedding-batch-size | 32 | Venice 임베딩 요청당 청크 수 |
--qdrant-path | 미설정 | 로컬 영구 Qdrant 저장 경로 |
--qdrant-url | 미설정 | 원격 Qdrant URL |
--skip-ingest | false | 문서를 다시 로드하지 않고 기존 컬렉션 쿼리 |
--recreate-collection | false | Qdrant 컬렉션 삭제 및 재빌드 |
프라이버시 노트
프라이빗 RAG 설정의 경우 각 레이어를 별도로 생각하세요:| Layer | Privacy consideration |
|---|---|
| Venice 임베딩 | 벡터 생성을 위해 문서 청크가 Venice로 전송 |
| Venice 채팅 | 질문에 답하기 위해 검색된 context가 Venice로 전송 |
| 로컬 Qdrant | 벡터와 페이로드가 머신에 남음 |
| 원격 Qdrant | 벡터와 페이로드가 Qdrant 서버가 실행되는 어디에든 저장 |
| FastEmbed 재순위기 | 모델이 사용 가능해진 뒤 재순위가 로컬에서 실행 |
미리 처리할 흔한 에러
| Symptom | What it usually means | What to do |
|---|---|---|
Set VENICE_API_KEY before running this example. | 환경 변수가 없음 | 스크립트 실행 전 VENICE_API_KEY export |
Document path does not exist | --docs에 전달된 경로가 잘못됨 | 파일 또는 폴더 경로 확인 |
| 검색 결과 없음 | ingest되지 않았거나 잘못된 컬렉션을 쿼리 중 | --skip-ingest 제거 또는 --collection과 --qdrant-path 확인 |
| Qdrant 벡터 크기 에러 | 컬렉션이 다른 임베딩 모델로 생성됨 | 임베딩 모델 변경 후 컬렉션 재생성 |
| 첫 번째 재순위가 느림 | FastEmbed가 cross-encoder를 다운로드/초기화 중일 수 있음 | 첫 실행을 끝까지 진행, 이후 실행은 더 빠를 것 |
다음으로 갈 곳
베이스라인이 동작하면 가장 영향이 큰 개선은 보통 다음과 같습니다:- PDF, HTML, 티켓, 내부 위키 페이지를 위한 문서 전용 로더 추가.
- 제목, 헤딩, 날짜, 소유자, URL 같은 더 풍부한 메타데이터 저장.
- 실제 질문에 대해
candidate_k,top_k, 청크 크기, 오버랩 튜닝. - 변경 전후 검색 품질을 측정할 수 있도록 평가 질문 추가.
- 더 나은 대화형 채팅 경험을 위해 최종 Venice chat completion 스트리밍.