원문: A complete Ruby implementation of Retrieval-Augmented Generation (RAG) pipeline using native Ruby ML/NLP gems.
Ragnar는 네이티브 Ruby ML/NLP gem을 사용하여 구현된 검색 증강 생성(Retrieval-Augmented Generation, RAG) 파이프라인의 완전한 솔루션을 제공합니다.
Ragnar는 다음 기능을 통합하여 Ruby 애플리케이션용 프로덕션 레디 RAG 파이프라인을 제공합니다:
red-candle: LLM 추론(inference), 임베딩, 및 재순위화(reranking)
lancelot: Lance 컬럼 스토리지 기반 벡터 데이터베이스
clusterkit: UMAP 차원 축소 및 클러스터링
baran: 텍스트 청킹 및 분할
graph TB
subgraph "Indexing Pipeline"
A[Documents] --> B[Chunker<br/>baran]
...
sequenceDiagram
participant User
participant CLI
...
flowchart LR
A[High-Dim Embeddings<br/>768D] --> B[UMAP Training]
B --> C[Model]
...
flowchart TB
Q[User Query] --> QA[Query Analysis<br/>w/ Cached LLM]
QA --> CI[Clarified Intent]
...
gem install ragnar-cli
git clone https://github.com/scientist-labs/ragnar-cli.git
cd ragnar-cli
bundle install
...
# 텍스트 파일 디렉토리 인덱싱
ragnar index ./documents
# 사용자 지정 설정을 사용한 인덱싱
...
ragnar 실행하기
인수 없이 ragnar를 실행하면 ratatui 기반의 대화형 TUI(Text User Interface)가 시작됩니다:
# TUI 실행 (명령어 미지정 시 기본값)
ragnar
# 또는 명시적으로
...
TUI는 다음 기능을 제공합니다:
자동 완성(Auto-completion): 명령어와 옵션에 대한 자동 완성 기능
세션 간 지속적인 기록(Persistent history): 세션 전반에 걸쳐 기록 유지
실시간 출력(Live output): 인덱싱 진행 상황, 쿼리 결과, 토픽 분석 등을 인라인으로 확인 가능
모든 CLI 명령어: /command 문법을 통해 사용 가능 (예: /index ., /umap train, `/query
참고: 토픽 모델링(Topic modeling)은 의미 있는 패턴을 식별하기 위해 충분한 문서가 필요합니다. 최상의 결과를 얻으려면:
- 최소 20~30개의 문서를 인덱싱하십시오 (이상적으로는 50개 이상)
- 문서들이 다양한 주제를 다루도록 하십시오
- 각 문서는 상당한 분량이어야 합니다 (각 50단어 이상).
HTML 내보내기에는 다음이 포함됩니다:
토픽 버블(Topic Bubbles): 토픽 크기와 일관성(coherence)을 보여주는 인터랙티브 버블 차트
임베딩 산점도(Embedding Scatter Plot): 클러스터별로 색상이 지정된 임베딩 공간 내 모든 문서의 시각화
# 기본 쿼리
ragnar query "What is the main purpose of this project?"
# 상세 모드는 모든 중간 처리 단계를 보여줍니다.
...
--verbose 또는 -v를 사용할 때 다음을 볼 수 있습니다:
쿼리 분석(Query Analysis): 원본 쿼리, 명확해진 의도, 하위 쿼리 및 핵심 용어
문서 검색(Document Retrieval): 각 하위 쿼리의 임베딩과 검색 결과
RRF 융합(RRF Fusion): 여러 검색 결과를 결합하는 방식
재순위 지정(Reranking): 관련성 점수 산정 후 상위 문서
컨텍스트 재패킹(Context Repacking): 검색된 청크를 구성하고 압축하는 방식
응답 생성(Response Generation): 최종 LLM 프롬프트 및 응답
최종 결과(Final Results): 신뢰도 점수 및 출처 귀속
ragnar stats
쿼리 재작성(Query Rewriting): 의도를 명확히 하고 하위 쿼리를 생성
다중 쿼리 검색(Multi-Query Search): 여러 쿼리 변형으로 검색
RRF 융합(RRF Fusion): 역순위 융합(Reciprocal Rank Fusion)을 사용하여 결과 결합
재순위 지정(Reranking): 정확한 관련성 점수 산정을 위해 크로스 인코더(cross-encoder) 사용
컨텍스트 재패킹(Context Repacking): 최적의 LLM 소비를 위해 검색된 청크를 중복 제거하고 구성
LLM 캐싱(LLM Caching): 쿼리 재작성과 응답 생성 사이에 공유되는 단일 LLM 인스턴스
컨텍스트 기반 응답(Contextual Response): 재패킹된 컨텍스트를 기반으로 LLM이 답변을 생성
고차원 임베딩(High-dimensional embeddings) (768D): 의미적 정확도를 위해 사용
UMAP 축소(UMAP reduction): 효율성을 위해 낮은 차원(2~50D)으로 줄임
자동 매개변수 조정(Automatic parameter adjustment): 데이터셋 크기에 기반하여 수행
배치 처리(Batch processing): 대규모 문서 컬렉션을 위한 처리
**Lance 컬럼 포맷(Lance columnar format)**을 이용한 효율적인 저장, 설정 가능한 메트릭을 사용한 벡터 유사성 검색(Vector similarity search), 출처 기여도 추적을 위한 메타데이터 추적(Metadata tracking), 그리고 증분 인덱싱(Incremental indexing) 지원
Ragnar는 YAML 기반의 유연한 구성 시스템을 사용하여 RAG 파이프라인의 모든 측면을 사용자 정의할 수 있도록 합니다.
Ragnar는 다음 순서로 구성 파일을 찾습니다:
- 현재 디렉토리의
.ragnar.yml
- 현재 디렉토리의
.ragnarrc.yml
- 현재 디렉토리의
ragnar.yml
- 홈 디렉토리의
.ragnar.yml
- 내장 기본값(Built-in defaults)
구성 파일 생성:
# 로컬 설정 생성 (현재 디렉토리)
ragnar init-config
# 전역 설정 생성 (홈 디렉토리)
...
예시 .ragnar.yml 파일:
# 저장소 경로 (모두 ~ 확장 지원)
storage:
database_path: "~/.cache/ragnar/database"
...
프로파일(Profiles)을 사용하면 설정을 편집하지 않고도 LLM 제공업체 간 전환이 가능합니다. 개발에는 로컬 모델을, 프로덕션 품질에는 클라우드 모델을 사용하세요:
# 단일 명령에 특정 프로파일 사용
ragnar --profile opus query "What is our security policy?"
# TUI 모드에서 세션 중간에 프로파일 전환
...
Ragnar는 모든 RubyLLM 제공업체(provider)를 지원합니다: red_candle (로컬), anthropic, openai, ollama 등.
API 키는 구성 파일의 개별 프로파일 또는 환경 변수(ANTHROPIC_API_KEY, OPENAI_API_KEY 등)를 통해 설정할 수 있습니다.
ragnar config # 활성 프로파일을 포함한 모든 설정 표시
ragnar model # LLM 모델 정보 표시
ragnar profile # 모든 LLM 프로파일 목록 표시
대화형 모드(Interactive mode, ragnar로 실행)에서는:
ragnar> /config # 구성 표시
ragnar> /profile # 프로파일 목록 표시
구성 값은 환경 변수로 덮어쓸 수 있습니다:
XDG_CACHE_HOME: 기본 캐시 디렉토리(~/.cache) 덮어쓰기
ANTHROPIC_API_KEY: Anthropic API 키 (anthropic 프로파일 사용)
OPENAI_API_KEY: OpenAI API 키 (openai 프로파일 사용)
LLM 제공업체 (RubyLLM을 통해):
red_candle
— 로컬 GGUF 모델 (기본값): MaziyarPanahi/Qwen3-4B-GGUF, MaziyarPanahi/Qwen3-8B-GGUF
anthropic
— Claude 모델: claude-opus-4-6, claude-sonnet-4-6
openai
— GPT 모델: gpt-4o, gpt-4o-mini
ollama
— 로컬 Ollama 모델: llama3.1:8b, mistral:7b
임베딩 모델 (red-candle을 통해):
jinaai/jina-embeddings-v2-base-en (기본값, 768 차원)
BAAI/bge-base-en-v1.5
sentence-transformers/all-MiniLM-L6-v2
재순위 모델 (red-candle을 통해, 설정 가능):
BAAI/bge-reranker-base (기본값, XLM-RoBERTa)
cross-encoder/ms-marco-MiniLM-L-12-v2 (더 작고, BERT 기반)
require 'ragnar'
indexer = Ragnar::Indexer.new(...)
...
색인된 문서에서 주제 추출:
40개 이상의 문서를 포함하는 완전한 작동 예시는 TOPIC_MODELING_EXAMPLE.md를 참조하십시오.
chunker = Ragnar::Chunker.new(
chunk_size: 1000,
chunk_overlap: 200,
...
processor = Ragnar::UmapProcessor.new
processor.train(...)
...
색인 (Indexing): 문서 1,000개당 약 100MB (768D 임베딩)
UMAP 학습: 벡터 10,000개당 약 80MB
쿼리 처리: 모델에 대한 오버헤드 약 50MB (LLM 캐싱으로 감소)
LLM 캐싱: 단일 모델 인스턴스 (~모델 크기에 따라 500MB-2GB)
색인 (Indexing): 초당 약 10개 문서 (임베딩 포함)
UMAP 학습: 벡터 10,000개당 3060초
쿼리 처리: 쿼리당 13초 (캐시된 LLM 사용 시 더 빠름)
벡터 검색: 벡터 100,000개당 <100ms
컨텍스트 재패킹: 일반적인 문서 세트의 경우 <50ms
LLM 로딩: 2~5초 (캐싱이 있는 첫 번째 쿼리에서만)
UMAP은 문서가 1,000개 초과인 데이터셋에 사용하세요.
대규모 문서 컬렉션의 배치 인덱싱을 수행하세요.
반복적인 질의를 위해 임베딩(embeddings)을 캐시하세요.
문서 유형에 따라 청크 크기를 조정하세요:
- 기술 문서(Technical docs): 500~1,000 토큰
- 서사적 텍스트(Narrative text): 200~500 토큰
- Q&A 콘텐츠: 100~300 토큰
UMAP이 "인덱스 범위를 벗어남(index out of bounds)" 오류를 일으키는 경우
- 원인: 요청된 매개변수에 비해 샘플 수가 너무 적음.
- 해결책: 시스템에서 자동으로 조정되지만, 수동으로 더 낮은 n_neighbors 값을 설정할 수 있습니다.
느린 인덱싱 성능
- 더 작은 청크 크기를 사용해 보세요.
- 배치 처리(batch processing)를 이용하세요.
- 더 빠른 임베딩 모델을 사용하는 것을 고려해 보세요.
낮은 질의 결과
- 문서를 더 많이 인덱싱하세요 (RAG는 100개 이상의 문서에서 가장 잘 작동합니다).
- 청크 크기와 오버랩(overlap)을 조정하세요.
- 다른 임베딩 모델을 시도해 보세요.
# 의존성 설치
bundle install
# 테스트 실행
...
| 구성 요소 (Component) | 목적 (Purpose) | 주요 메서드 (Key Methods) |
|---|
| Chunker | 텍스트를 의미론적 청크로 분할 | chunk_text() |
| ... | | |
| 문서(Documents) → Chunker → 텍스트 청크(Text chunks)텍스트 청크(Text chunks) → Embedder → 임베딩(Embeddings) (768D)임베딩(Embeddings) → 데이터베이스(Database) → 저장된 벡터(Stored vectors)저장된 벡터(Stored vectors) → UMAP → 축소된 벡터(Reduced vectors) (2-50D)질의(Query) → 리라이터(Rewriter) (캐시된 LLM 사용) → 하위 질의(Sub-queries)하위 질의(Sub-queries) → Embedder → 질의 벡터(Query vectors)질의 벡터(Query vectors) → 데이터베이스(Database) → 유사 문서(Similar documents)문서(Documents) → 리랭커(Reranker) → 상위 결과(Top results)상위 결과(Top results) → 컨텍스트 재패커(Context Repacker) → 최적화된 컨텍스트(Optimized context)최적화된 컨텍스트(Optimized context) → LLM (동일한 캐시 인스턴스 사용) → 최종 답변(Final answer) | | |
기여를 환영합니다! 다음을 수행해 주세요:
- 저장소 포크(Fork the repository)
- 기능 브랜치 생성(Create a feature branch)
- 새로운 기능에 대한 테스트 추가(Add tests for new functionality)
- 모든 테스트가 통과하는지 확인(Ensure all tests pass)
- 풀 리퀘스트 제출(Submit a pull request)
MIT 라이선스 - 자세한 내용은 LICENSE 파일을 참조하세요.
이 프로젝트는 여러 훌륭한 Ruby gem들을 통합했습니다:
- red-candle - Ruby ML/LLM 툴킷
- lancelot - Lance 데이터베이스 바인딩
- clusterkit - UMAP 및 클러스터링 구현
- thor-interactive - Thor CLI용 대화형 TUI
- ratatui_ruby - Ratatui 터미널 UI 바인딩
- parsekit - 콘텐츠 추출
- baran - 텍스트 분할 유틸리티