mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-12 18:58:49 -04:00
* fix(router): score classifier production-readiness Conversation trimming runs through the classifier model's chat template and trims by exact token count, sized to the model's n_batch which is now scaled to context so long probes can't crash the backend. Missing chat_message templates are a hard error at router build time. Router- facing factories (Embedder/Scorer/Reranker/TokenCounter) re-resolve ModelConfig per call so a model installed post-startup doesn't bind a stub Backend="" config and silently fall into the loader's auto- iterate path. New 'vector_store' backend trace recorded inside localVectorStore on every Search/Insert — including the backend-load-failure path that previously vanished into an xlog.Warn — with outcome tagging (hit/miss/empty_store/backend_load_error/find_error/insert_error/ok). Companion cleanup drops misleading similarity:0 and input_tokens_count:0 from non-hit and text-mode traces. Gallery local-store-development aliases to 'local-store' so the master image satisfies pkg/model.LocalStoreBackend lookups from the embedding cache. Misc: llama-cpp TokenizeString reads the correct 'prompt' JSON key (the original bug); ModelTokenize nil-guard; non-fatal mitm proxy startup; PII 'route_local' renamed to 'allow' with docs/UI in sync; model-editor footer no longer eats the edit area on small screens; several config-editor template/dropdown/section fixes. Tests: e2e router specs (casual/code-hint + long-conversation trim), vector_store trace specs, lazy-factory specs, gallery dev-alias resolution, Playwright trace badge + scroll regression. Assisted-by: Claude:claude-opus-4-7 [Claude Code] Signed-off-by: Richard Palethorpe <io@richiejp.com> * feat(backend): auto-size batch to context for embedding and rerank models Embedding and rerank models pool over the whole input in a single physical batch (n_ubatch). With batch left at the 512 default, the backend rejects longer inputs with "input is too large to process", silently capping a large-context embedder (e.g. 8k/32k) at 512 tokens. Size n_batch to the context for these single-pass usecases, mirroring the existing FLAG_SCORE behaviour; an explicit batch: still wins. Extracts EffectiveContextSize/EffectiveBatchSize from grpcModelOpts so the effective decode window has one home for other callers to reuse. Adds an e2e-aio regression test that embeds a >512-token input. The AIO embedding model is switched to nomic-embed-text-v1.5 (2048 context) because the previous granite model was capped at 512 tokens and could not exercise the larger batch. Assisted-by: claude-code:claude-opus-4-8 [Claude Code] Signed-off-by: Richard Palethorpe <io@richiejp.com> * fix(gallery): raise arch-router scoring output cap via parallel:64 Scoring decodes the whole prompt+candidate in a single llama_decode and reads one logit row per candidate token. The vendored llama.cpp server caps causal output rows at n_parallel, so the default of 1 aborts with GGML_ASSERT(n_outputs_max <= cparams.n_outputs_max) on multi-token route labels. Set options: [parallel:64] on both arch-router quant entries to lift the cap; kv_unified (the grpc-server default) keeps the full context per sequence, so this does not split the KV cache. Assisted-by: claude-code:claude-opus-4-8 [Claude Code] Signed-off-by: Richard Palethorpe <io@richiejp.com> --------- Signed-off-by: Richard Palethorpe <io@richiejp.com>
89 lines
3.1 KiB
Go
89 lines
3.1 KiB
Go
package backend
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/mudler/LocalAI/core/config"
|
|
"github.com/mudler/LocalAI/core/trace"
|
|
"github.com/mudler/LocalAI/pkg/model"
|
|
"github.com/mudler/LocalAI/pkg/system"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
// findVectorStoreTrace returns the most recent vector_store trace whose
|
|
// model_name matches storeName, or nil if none was recorded. Used by
|
|
// the specs below to assert the trace landed without relying on
|
|
// ring-buffer ordering across other tests in the suite.
|
|
func findVectorStoreTrace(storeName string) *trace.BackendTrace {
|
|
traces := trace.GetBackendTraces()
|
|
for i := range traces {
|
|
bt := &traces[i]
|
|
if bt.Type == trace.BackendTraceVectorStore && bt.ModelName == storeName {
|
|
return bt
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var _ = Describe("localVectorStore tracing", func() {
|
|
// Pin the trace surface admins read from /api/backend-traces.
|
|
// The original failure mode that motivated these specs — the
|
|
// local-store backend not installed — was silent on every surface
|
|
// except a per-call xlog.Warn. With tracing wired in, the row
|
|
// appears next to the embedder/score traces for the same request.
|
|
BeforeEach(func() {
|
|
trace.ClearBackendTraces()
|
|
})
|
|
|
|
It("records a vector_store trace with outcome=backend_load_error when the backend can't be loaded", func() {
|
|
// nil ModelLoader → s.backend → StoreBackend → panics on load.
|
|
// Use a real-but-empty loader so the failure surfaces as an
|
|
// error instead, exercising the load-failure trace path the
|
|
// admin would hit when local-store isn't installed.
|
|
appCfg := &config.ApplicationConfig{
|
|
EnableTracing: true,
|
|
TracingMaxItems: 16,
|
|
TracingMaxBodyBytes: 1024,
|
|
}
|
|
s := &localVectorStore{
|
|
loader: model.NewModelLoader(&system.SystemState{}),
|
|
appConfig: appCfg,
|
|
storeName: "router-cache-test",
|
|
}
|
|
|
|
// Search must surface the error AND record a trace describing it.
|
|
_, _, _, err := s.Search(context.Background(), []float32{0.1, 0.2, 0.3})
|
|
Expect(err).To(HaveOccurred())
|
|
|
|
Eventually(func() *trace.BackendTrace {
|
|
return findVectorStoreTrace("router-cache-test")
|
|
}).ShouldNot(BeNil())
|
|
|
|
bt := findVectorStoreTrace("router-cache-test")
|
|
Expect(bt.Backend).To(Equal(model.LocalStoreBackend))
|
|
Expect(bt.Data["op"]).To(Equal("search"))
|
|
Expect(bt.Data["outcome"]).To(Equal("backend_load_error"))
|
|
Expect(bt.Data["vector_dim"]).To(Equal(3))
|
|
// Error is the wrapped "vector store load: …" surfaced to the caller.
|
|
Expect(bt.Error).To(ContainSubstring("vector store load"))
|
|
})
|
|
|
|
It("does not record a trace when tracing is disabled", func() {
|
|
// Opt-out path: appConfig.EnableTracing=false must short-circuit
|
|
// before InitBackendTracingIfEnabled, so a workload with tracing
|
|
// turned off doesn't pay the channel-send cost per cache call.
|
|
appCfg := &config.ApplicationConfig{EnableTracing: false}
|
|
s := &localVectorStore{
|
|
loader: model.NewModelLoader(&system.SystemState{}),
|
|
appConfig: appCfg,
|
|
storeName: "router-cache-disabled",
|
|
}
|
|
_, _, _, _ = s.Search(context.Background(), []float32{1})
|
|
Consistently(func() *trace.BackendTrace {
|
|
return findVectorStoreTrace("router-cache-disabled")
|
|
}).Should(BeNil())
|
|
})
|
|
})
|