ES에 저장된 문서 본문을 의미 벡터로 변환하여 kNN 검색이 가능하게 만드는 단계. 인덱서가 적재 시 한 번(문서 임베딩), 백엔드가 사용자 질문 처리 시 한 번(query 임베딩) — 양쪽이 동일 모델(text-embedding-3-large, 3072 dims)을 써야 cosine 유사도가 의미를 갖는다. Python 측에는 SQLite 기반 로컬 캐시가 있어 재적재 시 OpenAI 호출 비용을 회피한다.
sequenceDiagram
autonumber
participant IDX as XxxIndexer
participant EMB as OpenAIEmbedder
participant CACHE as SQLite (.db)
participant TIK as tiktoken
participant API as OpenAI Embeddings API
IDX->>EMB: get_embeddings_batch([text1, text2, ...])
loop 각 텍스트
EMB->>EMB: SHA256(strip(text)) → text_hash
EMB->>CACHE: SELECT vector FROM cache WHERE key=text_hash
alt hit
CACHE-->>EMB: 기존 벡터 반환 (3072 floats)
else miss
EMB->>EMB: miss_indices.append(i)
end
end
alt miss_texts 있음
EMB->>TIK: encode(text)로 토큰 수 확인
Note over EMB: 8000 토큰 초과 시 자동 절단
EMB->>API: POST /embeddings { input: miss_texts, model: text-embedding-3-large }
API-->>EMB: 3072-dim vectors (배치)
EMB->>CACHE: put_many([(hash, vector), ...])
end
EMB-->>IDX: List[List[float]] (입력 순서대로)
sequenceDiagram
autonumber
participant SVC as StreamingRagProcessor
participant HYDE as HydeService
participant EU as EmbeddingUtil
participant LLM as OpenAI
SVC->>HYDE: generateHypotheticalAnswer(question)
HYDE-->>SVC: 가상 답변 텍스트
SVC->>EU: embed(가상 답변)
EU->>LLM: openai.embeddings.create model: ModelId("text-embedding-3-large") input: [hypothetical]
LLM-->>EU: 3072-dim List
EU-->>SVC: List
Note over SVC: ES kNN query에 query_vector로 전달
모델 정합성 self-discipline에 의존 — Python 인덱서가 text-embedding-3-large로 적재하는데 backend EmbeddingUtil이 다른 모델로 query embed하면 검색이 silent하게 무의미해진다. 양쪽 모두 코드 hardcode + CLI 기본값으로만 일치 유지 중 — config 단일 출처 부재가 위험.
Backend 모델 하드코딩 — EmbeddingUtil.kt의 ModelId("text-embedding-3-large")가 application.yml로 외부화되어 있지 않음. 모델 교체 = 코드 변경 + 재배포.
Langfuse 트레이싱 라벨 mismatch — LangfuseTracingService.embeddingModel 기본값이 "text-embedding-3-small"로 남아있어 트레이스 메타데이터가 실제 호출 모델과 불일치. 검색 품질 분석 시 혼동 가능.
임베딩 텍스트 절단 — 8000 토큰 초과 문서는 뒷부분이 임베딩에 반영되지 않음. 긴 판례/예규는 chunk 분할이 권장되지만 미구현 (1 doc = 1 embedding).
캐시 키가 strip만 적용 — 공백 외 정규화(대소문자, NFKC 등) 없음. 동일 의미의 텍스트라도 미세 차이로 캐시 miss → 중복 호출 가능.
OpenAIEmbedder 기본 모델 = small — 클래스 기본값이 text-embedding-3-small이라 CLI 외 경로에서 인스턴스 생성 시 잘못된 모델 사용 위험. 운영에서는 CLI가 항상 large로 명시.
재시도 후 영구 실패 처리 없음 — tenacity 3회 재시도 후 실패 시 예외 전파 → indexer 전체 batch 실패. dead-letter / 부분 skip 옵션 없음.
임베딩 비용 모니터링 부재 — --embed 사용 시 비용 알람/카운터 없음. 캐시 hit rate 통계도 미출력 — 대량 재적재 시 청구 surprise 가능.