- multilingual-e5-small (384 dim) → multilingual-e5-large (1024 dim) - Cascade: embedding_version bump → fb-23 incremental ingest re-embeds all chunks - Migration policy: dim mismatch detection at LanceVectorStore::open → error.v1 (code = embedding_dim_mismatch) + hint "kebab reset --vector-only && kebab ingest" - Config defaults flip (model + dimensions). User TOML pinning small preserves backwards-compat - bge-m3 deferred (fastembed enum 미포함, UserDefinedEmbeddingModel ONNX path 별도) - Release trigger: 0.6 → 0.7 minor bump per CLAUDE.md cascade rule Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.3 KiB
title, phase, component, task_id, status, target_version, contract_source, contract_sections, date
| title | phase | component | task_id | status | target_version | contract_source | contract_sections | date | |||
|---|---|---|---|---|---|---|---|---|---|---|---|
| p9-fb-39b — Embedding model upgrade design (multilingual-e5-large) | P9 | kebab-embed-local + kebab-store-vector + kebab-config + kebab-app | p9-fb-39b | design | 0.7.0 | ../../docs/superpowers/specs/2026-04-27-kebab-final-form-design.md |
|
2026-05-10 |
p9-fb-39b — Embedding model upgrade
Goal
fb-39 의 lever 적용 — embedding model 을 multilingual-e5-small (384 dim) 에서 multilingual-e5-large (1024 dim) 로 업그레이드. 도그푸딩 한국어 corpus 의 retrieval precision 개선.
fb-39 가 측정 도구 (P@5 / P@10) 를 추가했으므로, 본 PR 머지 후 small vs large 비교 가능.
bge-m3 검토했으나 fastembed 4.9.1 의 EmbeddingModel enum 에 미포함 — UserDefinedEmbeddingModel ONNX 직접 로드 path 는 별도 작업 (fb-39c 후보). 본 PR scope = e5-large 만.
Behavior contract
Embedding model
- 신규 default:
multilingual-e5-large(1024 dim). kebab-embed-local::resolve_model에 신규 arm:
"multilingual-e5-large" => Ok(EmbeddingModel::MultilingualE5Large),
기존 multilingual-e5-small arm 그대로 (backwards-compat opt-out).
Config defaults
Config::defaults().models.embedding.model:"multilingual-e5-small"→"multilingual-e5-large".Config::defaults().models.embedding.dimensions:384→1024.kebab init가 생성하는 config.toml 템플릿 동일 갱신.
기존 user TOML 이 model = "multilingual-e5-small" 또는 dimensions = 384 명시한 경우 그대로 유지 — serde 가 user value 우선. opt-out 가능.
Cascade
embedding_version: 자동 변경 (config.models.embedding.model 값 그대로 wire 에 emit).multilingual-e5-small→multilingual-e5-large.- fb-23 incremental ingest: 4-input match (blake3 + parser_version + chunker_version + embedding_version) 에서 embedding_version 깨짐 → 모든 chunk 재-embed. text/parse/chunk 비용 회피, embed 비용만 발생.
eval_runs.config_snapshot_json: 새 version 자동 기록. 비교 시 동일 version 끼리.- design §9 cascade rule 의 5 키 중
embedding_version변경 — binary release 트리거 (CLAUDE.mdVersioning cascade룰).
Migration policy
LanceDB stored vectors 의 dim 과 config.models.embedding.dimensions 가 mismatch 면:
LanceVectorStore::open(또는 첫 호출) 가 비교 → mismatch 시 신규ErrorV1:code = "embedding_dim_mismatch"message:"vector index dim 384 vs config dim 1024"hint:"기존 vector index 가 4-dim, config 는 N-dim. 'kebab reset --vector-only && kebab ingest' 로 재구축."
- CLI: exit 1 + error.v1 stderr (또는 비-
--json모드 plain stderr). - silent migration / auto-wipe 안 함 — 사용자 명시 동의 필요.
remediation flow:
$ kebab search "..."
error: vector index dim 384 vs config dim 1024
Hint: 기존 vector index 가 384-dim, config 는 1024-dim.
'kebab reset --vector-only && kebab ingest' 로 재구축.
$ kebab reset --vector-only
[wipe LanceDB + SQLite embedding_records]
$ kebab ingest
[full re-embed with new model — fastembed downloads e5-large ONNX (~1.3 GB) on first run]
Wire shape
신규 wire field 없음. error.v1.code 의 valid value namespace 에 "embedding_dim_mismatch" 추가 (string, enum 아님 — additive).
Allowed / forbidden dependencies
kebab-embed-local: 신규 dep 없음. fastembed enum variant 추가만.kebab-store-vector: 신규 dep 없음. LanceDB schema reader 사용.kebab-config: 신규 dep 없음. defaults 값 변경.kebab-app: 신규 dep 없음. error propagation.
kebab-core 의 다른 kebab-* 의존 금지 룰 그대로.
Public surface delta
kebab-embed-local (lib.rs)
fn resolve_model(name: &str) -> Result<EmbeddingModel> {
match name {
"multilingual-e5-small" => Ok(EmbeddingModel::MultilingualE5Small),
"multilingual-e5-large" => Ok(EmbeddingModel::MultilingualE5Large), // 신규
other => anyhow::bail!(/* ... */),
}
}
kebab-config (defaults + TOML 템플릿)
EmbeddingCfg {
provider: "fastembed".to_string(),
model: "multilingual-e5-large".to_string(),
dimensions: 1024,
// ... 기타 ...
}
generated config.toml 템플릿 도 같이 갱신.
kebab-store-vector (lib.rs 또는 신규 helper)
impl LanceVectorStore {
pub fn open(...) -> Result<Self> {
// 기존 open 로직 ...
let stored_dim = read_schema_vector_dim(&table)?;
if stored_dim != config_dim {
anyhow::bail!(StructuredError(ErrorV1 {
code: "embedding_dim_mismatch".to_string(),
message: format!("vector index dim {stored_dim} vs config dim {config_dim}"),
hint: Some(format!(
"기존 vector index 가 {stored_dim}-dim, config 는 {config_dim}-dim. \
'kebab reset --vector-only && kebab ingest' 로 재구축."
)),
// ...
}));
}
Ok(...)
}
}
(정확한 LanceDB schema reading API 는 구현 시 확인 — Table::schema() 또는 arrow_schema::Schema 직접 inspect.)
Test plan
| kind | description |
|---|---|
| unit (kebab-embed-local) | resolve_model("multilingual-e5-large") returns Ok |
| unit (kebab-embed-local) | check_dim(1024, 1024) ok |
| unit (kebab-embed-local) | check_dim(384, 1024) Err — message mentions both dims |
| unit (kebab-config) | Config::defaults().models.embedding.model == "multilingual-e5-large" |
| unit (kebab-config) | Config::defaults().models.embedding.dimensions == 1024 |
| unit (kebab-config) | TOML model = "multilingual-e5-small" deserialize 정상 (backwards-compat) |
| unit (kebab-config) | 생성된 config.toml 템플릿 안 model = "multilingual-e5-large", dimensions = 1024 |
| unit (kebab-store-vector) | mismatch fixture (384-dim stored + 1024 cfg) → embedding_dim_mismatch ErrorV1 |
| 통합 (kebab-cli) | mismatch scenario — pre-existing 384-dim DB + new config → exit 1 + error.v1 stderr (code = embedding_dim_mismatch) + hint mentions reset --vector-only |
| 통합 (kebab-cli) | small config 로 fresh ingest + search → 정상 (backwards-compat path 검증) |
multilingual-e5-large 모델 다운로드 회피 위해 unit/integration 테스트는 fixture 또는 mock — 실 모델 호출 안 함. 첫 도그푸딩 시 사용자가 fastembed cache 다운로드.
Implementation steps (high-level)
kebab-embed-local::resolve_modelarm + check_dim 단위 테스트.kebab-store-vectordim mismatch detection + ErrorV1 + 단위 테스트.kebab-configdefaults flip + TOML 템플릿 + 단위 테스트.kebab-cliintegration: mismatch error.v1 wire + backwards-compat path 통합 테스트.- README + SMOKE + design + HOTFIXES + status flip.
5 task. 단일 PR, single 세션 가능.
Risks / notes
- 첫 실행 모델 다운로드: e5-large ONNX ~1.3 GB. fastembed cache (
config.storage.model_dir/fastembed/) 에 자동 다운로드 (첫 호출 시). progress 표시 없음 — 사용자 침묵 latency.kebab doctor또는 README 에 경고 안내. - Search/ingest latency: e5-large 가 e5-small 대비 ~3-4× embedding 시간. ingest 비용 증가 (one-time + 신규 docs). search 시 query embed per-call 증가.
- Disk usage: vector dim 2.6× → LanceDB 약 2.7× 증가.
- HOTFIXES entry: dim mismatch UX (error.v1 + reset --vector-only flow) 가 frozen design 안 명시 안 된 신규 동작 — HOTFIXES 한 항목 추가.
- eval comparison: fb-39 P@k 가 측정 도구. 도그푸딩 corpus + golden 의 expected_chunk_ids 채워서 small vs large 정량 비교 별도 (PR 안 의무 아님).
- fb-23 incremental ingest 와의 상호작용: embedding_version 변경 → 모든 doc 재-embed. fb-23 의 unchanged path 는 한 번도 hit 안 함 (예상 동작).
- release trigger: design §9 cascade rule 의
embedding_version변경 → CLAUDE.mdVersioning cascade룰에 따라 binary 0.6 → 0.7 minor bump 필요.
Out of scope
- bge-m3 또는 user-defined ONNX path (fb-39c 후보).
- Other lever (RRF / cross-encoder / chunk policy).
- Auto-migration / background re-vector.
- LanceDB schema migration tooling (별도 wipe + re-ingest).
- multi-model coexistence (한 KB 안 small + large 동시).
- precision 정량 비교 의무 (별도 도그푸딩).
Documentation updates (implementation PR 동시)
README.md[models.embedding]config 섹션 — default 변경 + small opt-out 안내 + dim mismatch 시 reset 명령 안내.docs/SMOKE.md— upgrade walkthrough (kebab reset --vector-only && kebab ingest시퀀스 + 첫 ONNX 다운로드 latency 경고).docs/superpowers/specs/2026-04-27-kebab-final-form-design.md§5 storage / §9 versioning 적절 절 — 새 default + dim 1024 명시.tasks/HOTFIXES.md— dim mismatch UX entry.tasks/p9/p9-fb-39-retrieval-precision-tuning.mdbanner — fb-39b lever 적용 (embedding upgrade) ✅ 추가 (단 spec status 는 fb-39 frozen).tasks/p9/p9-fb-39b-embedding-upgrade.md신규 task spec (만들거나, fb-39 sub-task 로 frontmatter 처리).tasks/INDEX.md— fb-39b 행 추가 ✅.- 본 PR 머지 후
chore: bump version 0.6 → 0.7+ tag (CLAUDE.md release 절차).