docs(spec): arctic-embed-l-v2.0 임베더 통합 spec + plan
별칭 제거 후 설명형 recall 보강 최선책(측정 arctic recall@10 130/132, 용어 무손실). candle 다중모델화(CLS pooling+query: prefix) 우선 + Ollama embed provider 폴백. correctness 게이트 = candle≈Ollama 코사인>0.99. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
33
docs/superpowers/plans/2026-06-03-arctic-embedder-plan.md
Normal file
33
docs/superpowers/plans/2026-06-03-arctic-embedder-plan.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Plan: arctic-embed-l-v2.0 임베더 통합 구현
|
||||||
|
|
||||||
|
spec: `docs/superpowers/specs/2026-06-03-arctic-embedder-spec.md`. 브랜치 `feat/arctic-embedder`. 빌드 `CARGO_TARGET_DIR=/build/out/cargo-target`, `-j 4`(전체 test `-j 1`). cli 통합테스트용 `target` 심링크 필요 후 정리.
|
||||||
|
|
||||||
|
## Task 1 — kebab-embed-candle 모델 레지스트리
|
||||||
|
- e5 하드코딩(`HF_MODEL`/`SUPPORTED_MODEL`/mean pool/`query:`+`passage:`) → 레지스트리 구조체 `EmbedModelSpec { name, hf_repo, pooling: Pooling, query_prefix, doc_prefix, dim }`.
|
||||||
|
- 등록: e5(`intfloat/multilingual-e5-large`, Mean, `query: `/`passage: `, 1024) + arctic(`Snowflake/snowflake-arctic-embed-l-v2.0`, Cls, `query: `/``, 1024). **arctic pooling 은 모델 `1_Pooling/config.json` 로 확인 후 확정(CLS 추정).**
|
||||||
|
- `embed_batch` pooling 분기: Mean=기존 attention-mask-weighted, Cls=hidden_state[:,0,:]. tokenize/forward/L2 공유.
|
||||||
|
- `CandleEmbedder::new` 가 config model 로 spec 조회, 없으면 에러. `model_id`/`model_version` 에 모델명 반영.
|
||||||
|
- 단위테스트: 레지스트리 조회, prefix 적용, (가능하면) CLS vs mean pooling shape.
|
||||||
|
|
||||||
|
## Task 2 — kebab-embed-ollama 신규 크레이트
|
||||||
|
- `Cargo.toml`(workspace member), `Embedder` 구현. `reqwest::blocking` POST `/api/embed`.
|
||||||
|
- 배치(48) + fail-soft 재시도(3). query/doc prefix 모델별. L2 normalize. dim 검증(config 와 일치).
|
||||||
|
- endpoint = config.models.embedding.endpoint ?? models.llm.endpoint. model_version=`ollama:{model}`.
|
||||||
|
- 단위테스트: wiremock 으로 /api/embed mock → dim·정규화·prefix 검증.
|
||||||
|
|
||||||
|
## Task 3 — config + app 배선
|
||||||
|
- `kebab-config`: `EmbeddingCfg.provider` 문서/검증에 `ollama` 추가, `endpoint: Option<String>` 필드(serde default None). migrate.rs 주석.
|
||||||
|
- `kebab-app` `embedder()`(또는 해당 선택부, lib.rs ~836): provider match → fastembed | candle(레지스트리) | ollama. facade 통해 cfg 주입.
|
||||||
|
- config 직렬화/round-trip 테스트 갱신.
|
||||||
|
|
||||||
|
## Task 4 — correctness 검증 테스트 (핵심)
|
||||||
|
- candle arctic vs Ollama arctic 코사인>0.99 테스트: 테스트 문장 임베딩을 candle(arctic spec)로 1개 + Ollama(`snowflake-arctic-embed2` @192.168.0.47)로 1개 → cos>0.99 assert. live Ollama 의존이라 `#[ignore]`(이유: 외부 Ollama), 수동 실행 절차를 테스트 doc + HOTFIXES 에 기록. (CI 무인 환경 회피.)
|
||||||
|
- 단, **리더가 머지 전 이 테스트를 수동 실행해 통과 확인**(pooling/prefix 정확성 게이트).
|
||||||
|
|
||||||
|
## Task 5 — 검증 + 문서
|
||||||
|
- clippy 0 / 전체 test 통과(기존 e5 회귀 0).
|
||||||
|
- provider=candle+arctic, ollama+arctic, fastembed+e5(기본) 각 로드 스모크.
|
||||||
|
- 문서: README Configuration(provider candle/ollama + arctic + endpoint + metal), ARCHITECTURE(백엔드 그래프 + kebab-embed-ollama 크레이트 + 결정표), HANDOFF 1줄, HOTFIXES dated, Cargo.toml members + version minor bump(+Cargo.lock).
|
||||||
|
|
||||||
|
## 리뷰 루프
|
||||||
|
구현 완료 → 리더가 (a) clippy/test 독립 재확인 (b) **candle≈Ollama 코사인>0.99 수동 검증** → `gitea-pr`(title `feat(embed): arctic-embed-l-v2.0 임베더(candle+ollama)`) → 리뷰 루프 → 사용자 머지. 머지 후 Mac Metal 도그푸딩(recall 130 재현).
|
||||||
66
docs/superpowers/specs/2026-06-03-arctic-embedder-spec.md
Normal file
66
docs/superpowers/specs/2026-06-03-arctic-embedder-spec.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Spec: arctic-embed-l-v2.0 임베더 통합 (candle 우선 + Ollama provider)
|
||||||
|
|
||||||
|
**날짜**: 2026-06-03
|
||||||
|
**유형**: feature (신규 임베딩 백엔드/모델)
|
||||||
|
**근거**: `docs/superpowers/research/2026-06-03-expansion-cost-rethink-research.md` + `/build/dogfood/logs/2026-06-03-method-measurements.md`. 별칭 제거(v0.25.0) 후 설명형 recall 보강의 최선책. 측정: arctic-embed2 = recall@10 **130/132**, recall@50 **132/132**, **용어 무손실**(bge-m3 와 달리 syn/abbr/en 유지). e5 대비 +7, 색인 1회·per-query 0·LLM 0 = 살아있는 KB 최적합.
|
||||||
|
**사용자 결정**: candle 우선 + Ollama embed provider 폴백 둘 다.
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
`models.embedding` 에서 arctic-embed-l-v2.0 을 선택 가능하게 한다. 두 백엔드:
|
||||||
|
1. **candle** (주): `kebab-embed-candle` 를 e5 전용 → 다중 모델로 일반화, arctic 추가. in-process pure-Rust, NUMA 안전.
|
||||||
|
2. **ollama** (폴백): 신규 Ollama embedding provider. 측정에 쓴 경로(`/api/embed`) 그대로 → 130 보장.
|
||||||
|
기본 동작 불변(기본 provider=fastembed e5). arctic 은 opt-in.
|
||||||
|
|
||||||
|
## 모델 사실 (구현 기준)
|
||||||
|
- 아키텍처: **XLM-RoBERTa-large** (candle `XLMRobertaModel` 로드 가능, e5 와 동일 계열).
|
||||||
|
- dim: **1024** (e5 와 동일 → 벡터스토어/lancedb 테이블 차원 불변, 단 테이블명은 모델명 포함).
|
||||||
|
- pooling: arctic-embed-l-v2.0 의 sentence-transformers `1_Pooling/config.json` 기준(**CLS 토큰 추정 — 반드시 config 로 확인**). e5 는 mean pooling → pooling 을 모델별 분기.
|
||||||
|
- prefix: **query 에 `query: ` 접두어, 문서는 무접두어**(e5 의 `query:`/`passage:` 와 다름). 모델별 분기.
|
||||||
|
- 정규화: L2 normalize (코사인 일관성, 기존 e5 경로와 동일).
|
||||||
|
- HF repo: `Snowflake/snowflake-arctic-embed-l-v2.0` (candle 다운로드). Ollama: `snowflake-arctic-embed2`.
|
||||||
|
|
||||||
|
## 작업 A — kebab-embed-candle 다중 모델화
|
||||||
|
- 현재 `HF_MODEL`/`SUPPORTED_MODEL` 상수(e5 하드코딩) → **모델 레지스트리**로: `{ name, hf_repo, pooling: Mean|Cls, query_prefix, doc_prefix, dim }`. e5(mean, `query: `/`passage: `) + arctic(cls, `query: `/``).
|
||||||
|
- `embed_batch` 의 pooling 단계를 모델별 분기(mean=attention-mask-weighted mean / cls=first token). 나머지(tokenize→forward→L2)는 공유.
|
||||||
|
- `model_id()` / `model_version()` 가 모델명+pooling 반영(전환 시 embedding_version cascade 트리거).
|
||||||
|
- config `models.embedding.model` 이 레지스트리에 없으면 기존처럼 명확한 에러.
|
||||||
|
- `[features] metal`/`mkl` 유지(arctic 도 동일 XLM-R 경로라 그대로 동작).
|
||||||
|
|
||||||
|
## 작업 B — Ollama embedding provider (신규)
|
||||||
|
- 신규 크레이트 `kebab-embed-ollama` (또는 kebab-embed-local 내 모듈 — **새 크레이트 권장**, 의존 분리). `Embedder` trait 구현.
|
||||||
|
- `reqwest::blocking` 으로 `POST {endpoint}/api/embed` `{model, input:[...]}` → `embeddings`. 배치(예: 48/req), fail-soft 재시도.
|
||||||
|
- query/doc prefix 모델별(arctic: query 에 `query: `). 결과 **L2 normalize**(Ollama raw 반환 → 일관성 위해 정규화).
|
||||||
|
- endpoint: `models.embedding.endpoint`(신규, 미설정 시 models.llm.endpoint fallback). model_version = `ollama:{model}`.
|
||||||
|
|
||||||
|
## 작업 C — config + app 배선
|
||||||
|
- `kebab-config`: `EmbeddingCfg.provider` 에 `"ollama"` 허용. 신규 `endpoint: Option<String>`(ollama 용). serde forward-compat 유지.
|
||||||
|
- `kebab-app`: embedder 선택 분기(`embedder()`)에 candle 다중모델 + ollama provider 추가. facade(`*_with_config`) 통해 config 주입(facade rule 준수).
|
||||||
|
- UI 크레이트는 kebab-app 만 touch(불변).
|
||||||
|
|
||||||
|
## 결정 사항
|
||||||
|
- **차원 1024 동일** → lancedb 테이블은 모델명 포함(`chunk_embeddings_{model}_{dim}`)이라 모델 전환 시 새 테이블, 충돌 없음.
|
||||||
|
- **embedding_version cascade**: arctic 으로 전환 = embedding_version 변경 → 전체 재임베딩 필요(breaking). 기존 e5 KB 와 혼용 불가(명확). 기본값 e5 유지라 기존 사용자 무영향.
|
||||||
|
- arctic **ko 파인튠(dragonkue)** 은 base(130) 로 충분 → 본 작업은 base. ko 는 후속 옵션(레지스트리에 추가만 하면 됨).
|
||||||
|
- A(heading enrichment) 는 측정상 arctic 에서 악화 → **미적용**.
|
||||||
|
|
||||||
|
## 검증 기준 (Acceptance)
|
||||||
|
- `cargo clippy --workspace --all-targets -j 4 -- -D warnings` 통과.
|
||||||
|
- `cargo test --workspace --no-fail-fast -j 1` 통과 — 기존 e5-candle/fastembed 테스트 회귀 0.
|
||||||
|
- **correctness 핵심**: candle arctic 으로 임베딩한 테스트 문장(예: `query: 스택 자료구조` + 문서 `후입선출 자료구조`)이 **Ollama `snowflake-arctic-embed2` 임베딩과 코사인 > 0.99 일치**(Ollama 192.168.0.47 도달 가능 — pooling/prefix 정확성 정밀 검증, 130 재현 위험 차단). live Ollama 없으면 `#[ignore]` + 수동 절차 문서화.
|
||||||
|
- ollama provider: mock 또는 live 로 dim 1024 정규화 벡터 반환 smoke.
|
||||||
|
- config provider=`candle`+arctic / `ollama`+arctic 각각 올바른 embedder 로드.
|
||||||
|
- 기본 provider=fastembed e5 동작 불변(스모크).
|
||||||
|
|
||||||
|
## 도그푸딩 (별도, Mac Metal — 본 PR acceptance 아님)
|
||||||
|
arctic 으로 namu 재임베딩 → `namu_golden_expanded.yaml` 로 recall@10 ≈ 130 재현 확인. CLAUDE.md §Dogfood trigger(embedder 모델 변경) 충족. 결과 HOTFIXES + release notes.
|
||||||
|
|
||||||
|
## 문서 동기화 (같은 PR)
|
||||||
|
- README Configuration: provider=candle/ollama + arctic 모델 + endpoint + Apple Silicon(metal) 안내.
|
||||||
|
- docs/ARCHITECTURE: 임베딩 백엔드 그래프 + 신규 크레이트(kebab-embed-ollama) + 결정 표(arctic 채택 근거 측정 링크).
|
||||||
|
- HANDOFF 1줄. tasks/HOTFIXES dated entry(측정 근거 + cascade).
|
||||||
|
- Cargo.toml workspace members += kebab-embed-ollama, version minor bump.
|
||||||
|
|
||||||
|
## 비범위
|
||||||
|
- e5 KB 자동 마이그레이션(전환 = 수동 재임베딩, cascade 규칙대로).
|
||||||
|
- dragonkue ko 파인튠(후속).
|
||||||
|
- D(query-side)·C(reranker) 통합(별도 후속, 본 PR 은 임베더만).
|
||||||
Reference in New Issue
Block a user