Skip to content

feat: add fail-closed shared Qwen embedding and reranking - #902

Draft
coolmanns wants to merge 2 commits into
tobi:mainfrom
coolmanns:integration/qmd-shared-http
Draft

coolmanns wants to merge 2 commits into
tobi:mainfrom
coolmanns:integration/qmd-shared-http

Conversation

@coolmanns

Copy link
Copy Markdown

Summary

Adds strict, fail-closed HTTP backends for shared embedding and reranking services while preserving QMD's existing local model-string behavior.

This draft is intentionally narrower than the complete generation + embedding + reranking backend requested in #620. It contributes a hardened embedding/reranking path for a concrete Qwen3 deployment:

  • OpenAI-compatible POST /v1/embeddings
  • llama.cpp-compatible POST /v1/rerank
  • native Qwen3 2,560-dimensional validation
  • first-1,024 Matryoshka prefix reduction
  • L2 normalization after truncation
  • no local model initialization or fallback in remote mode

Motivation

Multiple QMD clients should be able to reuse one embedding model and one reranking model without each process loading duplicate GGUF models.

The important correctness boundary is stronger than transport compatibility: vectors from different producers, preprocessing paths, dimensions, or normalization pipelines must never be silently mixed under one identity. Remote failure therefore fails closed rather than falling back to a local GGUF model.

Configuration

models:
  embed:
    provider: openai
    endpoint: http://127.0.0.1:8086/v1
    model: Qwen3-Embedding-4B-Q8_0.gguf
    nativeDimensions: 2560
    dimensions: 1024
    reduction: mrl-prefix
    normalization: l2
    formatVersion: qwen3-query-document-v1
  rerank:
    provider: openai
    endpoint: http://127.0.0.1:8088/v1
    model: Qwen3-Reranker-0.6B-Q4_K_M.gguf
    failurePolicy: fail-closed

Plain model strings remain local configurations, including strings that happen to look like HTTP URLs. Remote mode requires the explicit structured form.

Embedding safety contract

  • Supports single and batched input.
  • Maps entries using each returned index, never response position.
  • Rejects missing, duplicate, fractional, negative, and out-of-range indexes.
  • Requires exactly 2,560 native values for this Qwen3 configuration.
  • Validates every native value before truncation, including the discarded tail.
  • Rejects non-finite values and finite JS doubles that overflow Float32.
  • Takes exactly the first 1,024 dimensions, then L2-normalizes the prefix.
  • Rejects zero/invalid prefix norms and invalid normalized Float32 values.
  • Applies the identical transformation to document and query embeddings.
  • Requires response model identity, with only explicit canonical aliases accepted.
  • Uses a semantic fingerprint covering provider, model, native/output dimensions, reduction, normalization order, and formatting version; endpoint and credentials are excluded.
  • Never initializes node-llama-cpp or silently falls back locally in remote mode.
  • Stages remote results in memory before a bounded SQLite write, avoiding network awaits inside transactions/savepoints.
  • Prevents overlapping remote embedding invocations against the same store.

Reranking safety contract

  • Sends chunks as documents and maps results by returned document index.
  • Validates cardinality, unique/in-range integer indexes, finite normalized scores, and response model identity.
  • Uses normalized relevance_score directly without applying a second sigmoid.
  • Caches by returned document index rather than file path.
  • Separates cache identity for different remote backends without including credentials.
  • Uses explicit failurePolicy: fail-closed and never initializes/falls back to a local reranker in remote mode.

CLI and configuration behavior

Structured configuration is validated before status, doctor, pull, trust, update, embed preflight, and runtime use. Malformed remote configuration does not degrade into a local path. Diagnostics redact API keys, URL credentials/query secrets, response bodies, and raw transport causes.

Relation to existing work

This draft overlaps with and is informed by:

It specifically addresses correctness concerns raised during review of those PRs:

  • fail closed rather than mix local/remote vector producers;
  • validate response cardinality and complete returned-index coverage;
  • reject malformed dimensions and non-finite values;
  • fingerprint the actual semantic transform;
  • separate reranking cache identities;
  • add focused routing/config/store/CLI tests;
  • avoid duplicate local model initialization.

This is submitted as a draft because the Qwen3 2,560→1,024 MRL contract is intentionally explicit and opinionated. Maintainer guidance is welcome on whether to retain this strict profile, generalize the structured transform fields, or extract parts into the broader #620 implementation.

Verification

Focused local test lanes:

  • embedding/reranking/routing/LLM/store: 452 passed, 0 failed
  • CLI/config/SDK/trust/update-hook: 318 passed, 0 failed
  • TypeScript check: passed
  • build: passed
  • git diff --check: passed

Full Vitest run:

  • 1,351 passed
  • 1 failed: MCP HTTP Transport > POST /mcp initialize still works for 2025-era clients (no session id)

That MCP failure was reproduced on the untouched base commit and is unrelated to this change; this PR does not claim a completely green full suite.

Additional isolated endpoint verification against llama.cpp services confirmed:

  • adapter output length: 1,024
  • post-prefix norm: approximately 1.0
  • manual native-prefix transform cosine: approximately 1.0
  • retrieval fixture: Recall@3 1.00, MRR 0.85
  • bounded four-worker load: 20/20 requests successful
  • live TCP traffic to both embedding and reranking endpoints
  • no additional embedding or reranking model process loaded

No production database, generated index, credential, benchmark artifact, or deployment configuration is included in this PR.

Add strict fail-closed HTTP adapters for Qwen embedding and reranking, preserve full response validation, reduce native 2560-dimensional embeddings to the normalized 1024-dimensional MRL prefix, and prevent local model fallback. Includes routing, fingerprint, cache, CLI, trust, transaction-safety, and regression tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant