feat(config,app): embedding provider=ollama 배선 + endpoint, version 0.26.0
kebab-config: EmbeddingModelCfg.endpoint: Option<String>(serde default, ollama용, None→models.llm.endpoint 폴백) + provider 문서에 ollama + env KEBAB_MODELS_EMBEDDING_ENDPOINT. kebab-app embedder(): provider match 에 ollama 분기(facade 경유). workspace member += kebab-embed-ollama, app dep 추가. version 0.25.0 → 0.26.0(minor, +Cargo.lock) — 신규 임베딩 백엔드/모델은 CLAUDE.md §Release 의 surface 변경 트리거. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
Cargo.lock
generated
63
Cargo.lock
generated
@@ -4724,7 +4724,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-app"
|
name = "kebab-app"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -4739,6 +4739,7 @@ dependencies = [
|
|||||||
"kebab-embed",
|
"kebab-embed",
|
||||||
"kebab-embed-candle",
|
"kebab-embed-candle",
|
||||||
"kebab-embed-local",
|
"kebab-embed-local",
|
||||||
|
"kebab-embed-ollama",
|
||||||
"kebab-llm",
|
"kebab-llm",
|
||||||
"kebab-llm-local",
|
"kebab-llm-local",
|
||||||
"kebab-nli",
|
"kebab-nli",
|
||||||
@@ -4771,7 +4772,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-chunk"
|
name = "kebab-chunk"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -4789,7 +4790,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-cli"
|
name = "kebab-cli"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -4810,7 +4811,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-config"
|
name = "kebab-config"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
@@ -4826,7 +4827,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-core"
|
name = "kebab-core"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -4840,7 +4841,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-embed"
|
name = "kebab-embed"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -4854,7 +4855,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-embed-candle"
|
name = "kebab-embed-candle"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"candle-core",
|
"candle-core",
|
||||||
@@ -4864,6 +4865,7 @@ dependencies = [
|
|||||||
"kebab-config",
|
"kebab-config",
|
||||||
"kebab-core",
|
"kebab-core",
|
||||||
"kebab-embed-local",
|
"kebab-embed-local",
|
||||||
|
"kebab-embed-ollama",
|
||||||
"rayon",
|
"rayon",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@@ -4873,7 +4875,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-embed-local"
|
name = "kebab-embed-local"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fastembed",
|
"fastembed",
|
||||||
@@ -4884,9 +4886,24 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kebab-embed-ollama"
|
||||||
|
version = "0.26.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"kebab-config",
|
||||||
|
"kebab-core",
|
||||||
|
"reqwest 0.12.28",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"wiremock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-eval"
|
name = "kebab-eval"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kebab-app",
|
"kebab-app",
|
||||||
@@ -4905,7 +4922,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-llm"
|
name = "kebab-llm"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kebab-core",
|
"kebab-core",
|
||||||
@@ -4914,7 +4931,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-llm-local"
|
name = "kebab-llm-local"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kebab-config",
|
"kebab-config",
|
||||||
@@ -4931,7 +4948,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-mcp"
|
name = "kebab-mcp"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kebab-app",
|
"kebab-app",
|
||||||
@@ -4949,7 +4966,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-nli"
|
name = "kebab-nli"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hf-hub",
|
"hf-hub",
|
||||||
@@ -4964,7 +4981,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-parse-code"
|
name = "kebab-parse-code"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"gix",
|
"gix",
|
||||||
@@ -4987,7 +5004,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-parse-image"
|
name = "kebab-parse-image"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph",
|
"ab_glyph",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -5011,7 +5028,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-parse-md"
|
name = "kebab-parse-md"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"kebab-core",
|
"kebab-core",
|
||||||
@@ -5028,7 +5045,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-parse-pdf"
|
name = "kebab-parse-pdf"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -5043,7 +5060,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-rag"
|
name = "kebab-rag"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -5065,7 +5082,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-search"
|
name = "kebab-search"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"globset",
|
"globset",
|
||||||
@@ -5084,7 +5101,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-source-fs"
|
name = "kebab-source-fs"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -5102,7 +5119,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-store-sqlite"
|
name = "kebab-store-sqlite"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -5122,7 +5139,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-store-vector"
|
name = "kebab-store-vector"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrow",
|
"arrow",
|
||||||
@@ -5146,7 +5163,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kebab-tui"
|
name = "kebab-tui"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ members = [
|
|||||||
"crates/kebab-embed",
|
"crates/kebab-embed",
|
||||||
"crates/kebab-embed-local",
|
"crates/kebab-embed-local",
|
||||||
"crates/kebab-embed-candle",
|
"crates/kebab-embed-candle",
|
||||||
|
"crates/kebab-embed-ollama",
|
||||||
"crates/kebab-llm",
|
"crates/kebab-llm",
|
||||||
"crates/kebab-llm-local",
|
"crates/kebab-llm-local",
|
||||||
"crates/kebab-rag",
|
"crates/kebab-rag",
|
||||||
@@ -31,7 +32,7 @@ edition = "2024"
|
|||||||
rust-version = "1.85"
|
rust-version = "1.85"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/altair823/kebab"
|
repository = "https://github.com/altair823/kebab"
|
||||||
version = "0.25.0" # v0.25.0 — doc-side expansion(별칭) 기능 완전 제거: Chunk.aliases / expansion.rs / IngestExpansionCfg / alias lexical arm / expansion_progress wire kind 제거, 신규 마이그레이션 V013 이 chunk_aliases_fts + chunks.aliases DROP. AssetTimings.expansion_ms 는 wire 호환 위해 값 0 유지. 별칭 default-off 였어 사용자 체감 0. — CLAUDE.md §Release
|
version = "0.26.0" # v0.26.0 — arctic-embed-l-v2.0 임베더 통합: kebab-embed-candle 다중 모델 레지스트리(e5 mean + arctic CLS, 모델별 pooling/prefix 분기) + 신규 kebab-embed-ollama 크레이트(provider="ollama", POST /api/embed, L2 정규화, batch+fail-soft). config models.embedding.provider 에 "ollama" 추가 + endpoint: Option<String>. 기본 동작 불변(provider=fastembed e5), arctic 은 opt-in, embedding_version cascade(arctic-cls / ollama:{model} 태그). — CLAUDE.md §Release
|
||||||
|
|
||||||
# pre-v0.18 workspace-wide cleanup: enable clippy::pedantic group with
|
# pre-v0.18 workspace-wide cleanup: enable clippy::pedantic group with
|
||||||
# intentional allow-list. The allowed lints are either cosmetic (doc style),
|
# intentional allow-list. The allowed lints are either cosmetic (doc style),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ kebab-search = { path = "../kebab-search" }
|
|||||||
kebab-embed = { path = "../kebab-embed" }
|
kebab-embed = { path = "../kebab-embed" }
|
||||||
kebab-embed-local = { path = "../kebab-embed-local" }
|
kebab-embed-local = { path = "../kebab-embed-local" }
|
||||||
kebab-embed-candle = { path = "../kebab-embed-candle" }
|
kebab-embed-candle = { path = "../kebab-embed-candle" }
|
||||||
|
kebab-embed-ollama = { path = "../kebab-embed-ollama" }
|
||||||
kebab-llm = { path = "../kebab-llm" }
|
kebab-llm = { path = "../kebab-llm" }
|
||||||
kebab-llm-local = { path = "../kebab-llm-local" }
|
kebab-llm-local = { path = "../kebab-llm-local" }
|
||||||
kebab-rag = { path = "../kebab-rag" }
|
kebab-rag = { path = "../kebab-rag" }
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ use kebab_core::{
|
|||||||
};
|
};
|
||||||
use kebab_embed_candle::CandleEmbedder;
|
use kebab_embed_candle::CandleEmbedder;
|
||||||
use kebab_embed_local::FastembedEmbedder;
|
use kebab_embed_local::FastembedEmbedder;
|
||||||
|
use kebab_embed_ollama::OllamaEmbedder;
|
||||||
use kebab_llm_local::OllamaLanguageModel;
|
use kebab_llm_local::OllamaLanguageModel;
|
||||||
use kebab_parse_code::{
|
use kebab_parse_code::{
|
||||||
CAstExtractor, CppAstExtractor, GoAstExtractor, JavaAstExtractor, JavascriptAstExtractor,
|
CAstExtractor, CppAstExtractor, GoAstExtractor, JavaAstExtractor, JavascriptAstExtractor,
|
||||||
@@ -834,11 +835,13 @@ impl App {
|
|||||||
if let Some(e) = self.embedder.get() {
|
if let Some(e) = self.embedder.get() {
|
||||||
return Ok(Some(e.clone()));
|
return Ok(Some(e.clone()));
|
||||||
}
|
}
|
||||||
// Provider branch (Track 1 spec §3). `embeddings_disabled()` above
|
// Provider branch (Track 1 spec §3 + arctic-embedder spec). The
|
||||||
// already handled `"none"`; here we route the live providers.
|
// `embeddings_disabled()` check above already handled `"none"`; here we
|
||||||
// `fastembed`/`onnx`/(empty) keep the default onnxruntime path
|
// route the live providers. `fastembed`/`onnx`/(empty) keep the default
|
||||||
// (vectors unchanged — `embedding_version` is preserved); `candle`
|
// onnxruntime path (vectors unchanged — `embedding_version` is
|
||||||
// selects the pure-Rust NUMA-safe backend.
|
// preserved); `candle` selects the pure-Rust NUMA-safe backend (e5 or
|
||||||
|
// arctic via its model registry); `ollama` offloads to a remote
|
||||||
|
// `/api/embed` daemon.
|
||||||
let provider = self.config.models.embedding.provider.as_str();
|
let provider = self.config.models.embedding.provider.as_str();
|
||||||
let emb: Arc<dyn Embedder + Send + Sync> = match provider {
|
let emb: Arc<dyn Embedder + Send + Sync> = match provider {
|
||||||
"fastembed" | "onnx" | "" => Arc::new(
|
"fastembed" | "onnx" | "" => Arc::new(
|
||||||
@@ -847,10 +850,13 @@ impl App {
|
|||||||
"candle" => Arc::new(
|
"candle" => Arc::new(
|
||||||
CandleEmbedder::new(&self.config).context("kb-app: load CandleEmbedder")?,
|
CandleEmbedder::new(&self.config).context("kb-app: load CandleEmbedder")?,
|
||||||
),
|
),
|
||||||
|
"ollama" => Arc::new(
|
||||||
|
OllamaEmbedder::new(&self.config).context("kb-app: load OllamaEmbedder")?,
|
||||||
|
),
|
||||||
other => {
|
other => {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"kb-app: unknown embedding provider {other:?}; expected one of \
|
"kb-app: unknown embedding provider {other:?}; expected one of \
|
||||||
`fastembed` (default), `candle`, or `none` (lexical-only)"
|
`fastembed` (default), `candle`, `ollama`, or `none` (lexical-only)"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -155,9 +155,10 @@ impl NliCfg {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct EmbeddingModelCfg {
|
pub struct EmbeddingModelCfg {
|
||||||
/// `fastembed` (default, onnxruntime) or `candle` (pure-Rust,
|
/// `fastembed` (default, onnxruntime), `candle` (pure-Rust, NUMA-safe),
|
||||||
/// NUMA-safe). `none` disables embeddings (lexical-only). Unknown
|
/// or `ollama` (remote HTTP embedding endpoint). `none` disables
|
||||||
/// values error at embedder construction.
|
/// embeddings (lexical-only). Unknown values error at embedder
|
||||||
|
/// construction.
|
||||||
pub provider: String,
|
pub provider: String,
|
||||||
pub model: String,
|
pub model: String,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
@@ -170,6 +171,13 @@ pub struct EmbeddingModelCfg {
|
|||||||
/// provider. Defaulted on load so pre-0.22 config files still parse.
|
/// provider. Defaulted on load so pre-0.22 config files still parse.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub num_threads: u32,
|
pub num_threads: u32,
|
||||||
|
/// HTTP endpoint for the `ollama` embedding provider (e.g.
|
||||||
|
/// `"http://127.0.0.1:11434"`). `None` (or a missing key in TOML) means
|
||||||
|
/// "fall back to `models.llm.endpoint`" — same convention as the OCR /
|
||||||
|
/// vision endpoints. Ignored by the `fastembed` / `candle` providers.
|
||||||
|
/// Defaulted on load so pre-0.26 config files still parse.
|
||||||
|
#[serde(default)]
|
||||||
|
pub endpoint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -688,6 +696,7 @@ impl Config {
|
|||||||
dimensions: 1024,
|
dimensions: 1024,
|
||||||
batch_size: 64,
|
batch_size: 64,
|
||||||
num_threads: 0,
|
num_threads: 0,
|
||||||
|
endpoint: None,
|
||||||
},
|
},
|
||||||
llm: LlmCfg {
|
llm: LlmCfg {
|
||||||
provider: "ollama".to_string(),
|
provider: "ollama".to_string(),
|
||||||
@@ -950,6 +959,12 @@ impl Config {
|
|||||||
self.models.embedding.num_threads = n;
|
self.models.embedding.num_threads = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"KEBAB_MODELS_EMBEDDING_ENDPOINT" => {
|
||||||
|
// Empty value → None (= fall back to models.llm.endpoint),
|
||||||
|
// mirroring the OCR endpoint override semantics.
|
||||||
|
self.models.embedding.endpoint =
|
||||||
|
if v.is_empty() { None } else { Some(v.clone()) };
|
||||||
|
}
|
||||||
|
|
||||||
// models.llm
|
// models.llm
|
||||||
"KEBAB_MODELS_LLM_PROVIDER" => self.models.llm.provider = v.clone(),
|
"KEBAB_MODELS_LLM_PROVIDER" => self.models.llm.provider = v.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user