Files
kebab/docs/superpowers/specs/2026-06-01-embedding-numa-backends-meta-spec.md
altair823 6ec4e6809f fix(embed-candle): address round-1 review
- commit track-spec + meta-spec/plan into branch (HIGH: dangling `amends:` ref)
- inline parity evidence (cosine 1.0, max_abs_diff 2.01e-7) into HOTFIXES +
  release notes; drop refs to deleted IMPL_REPORT/SPIKE_REPORT (MEDIUM)
- model guard: reject non-e5-large `model` before the 2GB download so
  model_id() can't mislabel vectors (MEDIUM) + unit test
- parity test now covers BOTH query: and passage: prefixes (MEDIUM)
- guard encodings.first() index; document zero-attention/pooling invariant;
  clarify embed_batch prefixing doc (LOW)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:54:20 +00:00

6.6 KiB
Raw Blame History

Meta-Spec — NUMA-안전 임베딩 백엔드 (다중 트랙)

  • 날짜: 2026-06-01
  • 상태: DRAFT (umbrella)
  • 범위: kebab-embed-local 및 임베더 주입 경로. 4개 트랙의 우산 스펙.
  • 하위 산출물: 각 트랙은 본 메타스펙을 참조하는 자체 spec(tasks/ 또는 docs/superpowers/specs/)과 plan을 가진다.

1. 문제

CPU-only Ollama 서버(Intel Xeon Silver 4214 ×2 소켓 = 48 logical, NUMA 2노드)에서 kebab ingest 가 매 실행 힙 손상으로 죽는다:

ingest [>     ] 3/5150  double free or corruption (!prev)
중지됨 (core dumped)

근본 원인(코드로 확정): fastembed 4.9.1 (text_embedding/impl.rs:52,80) 이 ONNX intra-op 스레드를 available_parallelism()(=48) 로 하드코딩하고 InitOptions 에 이를 덮어쓸 API 가 없다. 듀얼소켓 NUMA 에서 onnxruntime(ort 2.0.0-rc.9) 스레드풀이 힙을 손상시킨다. 진단 근거: tasks/HOTFIXES.md 의 본 날짜 entry + 대화 로그.

  • 모델/디스크/AVX/데이터 문제 아님 (모델 2.08GB 정상, AVX-512 완비). 순수 스레드/NUMA × 네이티브 런타임 버그.
  • onnxruntime 공식 문서도 듀얼소켓 NUMA 는 intra-op 스레드를 한 노드로 묶으라고 권고.

2. 목표 / 비목표

목표:

  • 그 NUMA 서버에서 5150-doc 코퍼스를 double-free 없이 완주하는 임베딩 경로 확보.
  • 검색 품질을 골든 스위트(MRR/hit@k) baseline 이상으로 유지.
  • models.embedding.provider 로 선택 가능한 백엔드들로 구현 (기존 provider 필드 활용).

비목표:

  • 랭킹 자동 조정 (별도 보류 결정, [[project_ranking_deferred]]).
  • 임베딩 모델 품질 개선 자체 (NUMA 안정성이 본 과제의 초점).
  • GPU 경로.

3. 공유 아키텍처

  • 교체 지점은 단일: crates/kebab-app/src/app.rs:836FastembedEmbedder::new(&config).
  • 트레이트 표면이 작다: kebab_core::Embedder (traits.rs:127) — model_id / model_version / dimensions / embed. 새 백엔드는 이 4개만 구현.
  • 설정: models.embedding.provider (이미 존재), model, version, dimensions, batch_size. 신규로 트랙별 스레드/affinity 노브 추가 가능.

4. 횡단 정책 (모든 트랙 공통)

4.1 embedding_version & 재색인

  • 벡터가 바뀌면(=candle, ollama) embedding_version bump → 전체 재색인 (design §9 cascade). A2/A1 은 동일 onnxruntime e5-large 라 벡터 불변 → 재색인 불필요.
  • 재색인 비용/절차를 각 트랙 spec 에 명시.

4.2 품질 검증 (필수 게이트)

  • 벡터가 바뀌는 트랙은 머지 전 kebab-eval 골든 스위트(/build/dogfood/golden_queries.yaml) 로 MRR/hit@k 측정, baseline 이상이어야 default 승격. baseline 미달이면 opt-in provider 로만 유지.
  • 패러프레이즈 robustness(#195/#196) 회귀 확인.

4.3 NUMA 서버 검증 (필수 게이트, 사용자 실행)

  • 결정적 증거는 그 서버에서만 난다 (Claude 접근 불가). 각 트랙은 사용자가 그 서버에서 5150-doc 코퍼스 ingest 를 double-free 없이 완주(EXIT=0) 함을 확인해야 "검증 완료".
  • 각 트랙 spec 에 사용자-실행 검증 절차(명령 + 기대 출력)를 문서화.

4.4 스레드/NUMA 제어

  • 각 백엔드가 intra-op/worker 스레드를 캡하고 한 NUMA 노드로 묶을 수 있어야 함. 캡 못 하면 트랙 실패.

5. 트랙

선호/구현 순서: candle → ollama → A2 → A1. (단 A1 은 무코드 stopgap 이라 즉시 문서화해 당장의 불통을 해소; 구현 순서와 별개.)

# 트랙 백엔드 벡터 변경(재색인) 핵심 리스크 격리 브랜치
1 candle 순수 Rust (candle xlm_roberta) XLM-R padding_idx/패리티/CPU 성능 feat/embed-candle
2 ollama 별 프로세스 (Ollama /api/embed) 모델이 e5 아님→품질, ingest 가 Ollama 의존 feat/embed-ollama
3 A2 onnxruntime 직접(ort 세션) 아니오 fastembed 우회 후 토크나이즈/풀링 재현 정확도 feat/embed-ort-direct
4 A1 onnxruntime + 실행 래핑(taskset/numactl) 아니오 코드 변경 거의 없음, 문서/런처만 docs/embed-numa-affinity

5.1 트랙별 테스트 매트릭스 (각 트랙 spec 에서 구체화)

모든 트랙:

  • 단위: embed() 가 올바른 dim/정규화(L2≈1) 벡터 반환.
  • 통합: kebab ingest 소량 fixture → 청크/임베딩 카운트.
  • NUMA 서버 검증(§4.3): 5150-doc 완주.

벡터-변경 트랙(candle/ollama) 추가:

  • 패리티: onnxruntime e5-large 대비 동일 입력 cosine 유사도(가능 시) 또는 골든 스위트 동등성.
  • 골든: MRR/hit@k ≥ baseline (§4.2).
  • 재색인 절차 검증.

벡터-불변 트랙(A2/A1) 추가:

  • 회귀: 기존 e5-large 벡터와 cosine ≈ 1.0 (A2 는 같은 런타임이라 사실상 동일해야).

6. 결정사항 (확정 2026-06-01)

  • D1 조기 종료 (사용자 확정): 트랙을 선호 순서로 진행하되, candle 또는 ollama 가 허용 품질 기준 + NUMA 안전을 만족하면 거기서 멈춘다 (이후 트랙 미진행). 둘 다 품질이 너무 낮으면 A2 → A1 까지 계속.
    • 허용 품질 기준: 골든 스위트 MRR/hit@k 가 현 e5-large(onnxruntime) baseline 대비 유의미한 회귀 없음. candle 은 동일 e5-large 가중치라 패리티 통과 시 이 기준을 거의 자동 충족 → candle 이 종착 가능성 높음. ollama 는 모델이 달라 경계선이면 사용자 판단.
    • A2/A1 은 candle·ollama 둘 다 실패 시의 fallback (A2 는 재색인 0 품질-중립).
  • D2 즉시 완화: A1(taskset/numactl) 은 무코드라 본 작업과 무관하게 지금 바로 사용자에게 워크어라운드로 제공.
  • D3 메타 산출물 위치: 본 메타스펙 + 메타플랜은 docs/superpowers/specs/. 트랙별 spec 은 도달 시 작성.
  • D4 frozen design 영향: 임베딩 백엔드 다변화는 design §(임베딩) 갱신 가능 — 트랙 머지 시 동기화.

7. 성공 기준

  • 그 NUMA 서버에서 최소 1개 트랙이 5150-doc 완주(EXIT=0).
  • default 로 승격되는 백엔드는 골든 baseline 이상.
  • 각 트랙이 자체 브랜치/워크트리 + 문서화된 테스트로 독립 검증.

8. 시퀀싱 게이트

  1. candle 스파이크(Phase 0) 가 패리티+CPU 성능+스레드 제어를 입증해야 candle 본 구현 진행. 실패 시 candle 트랙 강등/스킵 후 ollama 로.
  2. 각 트랙은 PR open + NUMA 서버 검증 예약 후 다음 트랙 시작 (omc-teams sequential single-team 제약).
  3. 벡터-변경 트랙은 골든 게이트 통과 전 default 승격 금지.