[Bug]: URL-backed custom models with the same basename reuse the wrong cached model
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 25/100
Direzione di ricerca
Read fastembed/common/model_management.py around the URL loader at lines 535–550 and trace how the model name determines the cache directory and cache-hit behavior. Use the issue’s reproduction to compare both registrations with a shared cache against the fresh-cache control; done means each registered name loads its own archive, with existing basename-only cache entries handled consistently for offline users.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What happened?
Two URL-backed custom models can be registered under different names, such as owner-a/shared-model and owner-b/shared-model. When they use the same cache directory, loading the second model silently reuses the first model's files. It returns the first model's embeddings without requesting the second archive.
The URL loader derives the on-disk directory from the last segment of model_name and treats an existing nonempty directory as a cache hit. Both registrations therefore look up cache_dir/shared-model. Source at the tested revision
Expected behavior
Each registration should load its own model files. A cache hit for one registered name should leave other names free to download their own archives. A separate cache_dir for each model is a workaround.
Before implementing a change, I'd appreciate guidance on how the loader should handle existing basename-only cache entries, especially for offline users.
Reproduction
Save this as repro.py and run it with FastEmbed and onnx installed. It builds two small ONNX archives and serves them on loopback. No pretrained model or external service is needed.
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
import json
from pathlib import Path
import tarfile
from tempfile import TemporaryDirectory
from threading import Thread
import onnx
from onnx import TensorProto as T, helper as h
from tokenizers import Tokenizer
from tokenizers.models import WordLevel
from tokenizers.pre_tokenizers import Whitespace
from fastembed import TextEmbedding
from fastembed.common.model_description import ModelSource, PoolingType
def archive(root, name, factor):
folder = root / name / "shared-model"
folder.mkdir(parents=True)
tokenizer = Tokenizer(WordLevel({"[UNK]": 0, "[PAD]": 1, "hello": 2, "world": 3}, unk_token="[UNK]"))
tokenizer.pre_tokenizer = Whitespace()
tokenizer.enable_padding(pad_id=1, pad_token="[PAD]")
tokenizer.enable_truncation(max_length=8)
tokenizer.save(str(folder / "tokenizer.json"))
(folder / "tokenizer_config.json").write_text(json.dumps({"model_max_length": 8, "pad_token": "[PAD]"}))
(folder / "special_tokens_map.json").write_text(json.dumps({"unk_token": "[UNK]", "pad_token": "[PAD]"}))
graph = h.make_graph(
[
h.make_node("Cast", ["input_ids"], ["tokens"], to=T.FLOAT),
h.make_node("ReduceSum", ["tokens"], ["sum"], axes=[1], keepdims=1),
h.make_node("Mul", ["sum", "factor"], ["scaled"]),
h.make_node("Concat", ["sum", "scaled"], ["embedding"], axis=1),
],
name,
[h.make_tensor_value_info("input_ids", T.INT64, ["batch", "sequence"])],
[h.make_tensor_value_info("embedding", T.FLOAT, ["batch", 2])],
[h.make_tensor("factor", T.FLOAT, [1], [factor])],
)
model = h.make_model(graph, opset_imports=[h.make_opsetid("", 11)], ir_version=9)
onnx.checker.check_model(model)
onnx.save(model, str(folder / "model.onnx"))
with tarfile.open(root / f"{name}.tar.gz", "w:gz") as out:
out.add(folder, arcname="shared-model")
with TemporaryDirectory() as tmp:
root = Path(tmp)
archive(root, "a", 1.0)
archive(root, "b", -1.0)
with ThreadingHTTPServer(("127.0.0.1", 0), partial(SimpleHTTPRequestHandler, directory=tmp)) as server:
thread = Thread(target=server.serve_forever)
thread.start()
try:
base = f"http://127.0.0.1:{server.server_port}"
for owner in ("a", "b"):
TextEmbedding.add_custom_model(
model=f"owner-{owner}/shared-model",
pooling=PoolingType.DISABLED,
normalization=False,
sources=ModelSource(url=f"{base}/{owner}.tar.gz"),
dim=2,
model_file="model.onnx",
)
for owner, cache in (("a", "shared"), ("b", "shared"), ("b", "fresh")):
model = TextEmbedding(f"owner-{owner}/shared-model", cache_dir=str(root / cache), threads=1)
print(owner, cache, next(model.embed(["hello world"])).tolist(), flush=True)
finally:
server.shutdown()
thread.join()
Observed:
GET /a.tar.gz
a shared [5.0, 5.0]
b shared [5.0, 5.0]
GET /b.tar.gz
b fresh [5.0, -5.0]
The expected output for b shared is [5.0, -5.0], matching the fresh-cache control.
Environment
Python 3.11.15 on macOS arm64. FastEmbed source from main at f91d9168c0291daeafb0a54cebc7c5b4b83f312f (project version 0.9.1), loaded through PYTHONPATH with the installed runtime dependencies. ONNX 1.23.2, ONNX Runtime 1.30.0 and NumPy 2.4.6.
- Lingua principale
- Python
- Stelle
- 3.3k
- Fork
- 296
- Merge medio
- 4g 11h
- PR unite (30g)
- 38
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di qdrant/fastembed
-
[Bug]: Revision-pinned HF downloads can falsely report intact files as corruptedForse già presa @N7766 l’ha presa oggi. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: Model download sleeps after its final failed attemptForse già presa @elysiopires l’ha presa 9 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Weekly tests failedForse già presa @joein l’ha presa 13 giorni fa. Aperta
qdrant/fastembed#843 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: rerank_pairs raises TypeError when pairs are passed as a tuple of pairsForse già presa @michaelkillgta l’ha presa 30 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 22/100
I maintainer di solito rispondono entro 1 giorno
-
[Feature]: Support huggingface-hub 2.0Forse di nuovo libera @joein l’ha presa 40 giorni fa e non c’è nessuna pull request aperta. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 65/100
qdrant/fastembed#742 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di qdrant/fastembed
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
igormcsouza/tether#278 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 91/100
aws-samples/sample-per-model-bedrock#803 ·
I maintainer di solito rispondono entro 1 giorno
-
documentation p1
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
huggingface/accelerate#4511 ·
I maintainer di solito rispondono entro 1 giorno
-
follow-up
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno