Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions llama_cpp/llama.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def __init__(
yarn_orig_ctx: int = 0,
logits_all: bool = False,
embedding: bool = False,
embeddings: Optional[bool] = None,
offload_kqv: bool = True,
flash_attn: bool = False,
op_offload: Optional[bool] = None,
Expand Down Expand Up @@ -173,7 +174,9 @@ def __init__(
yarn_beta_slow: YaRN high correction dim
yarn_orig_ctx: YaRN original context size
logits_all: Return logits for all tokens, not just the last token. Must be True for completion to return logprobs.
embedding: Embedding mode only.
embedding: Embedding mode only (historical name).
embeddings: Alias of ``embedding``. Prefer this spelling; if both are
provided they must agree.
offload_kqv: Offload K, Q, V to GPU.
flash_attn: Use flash attention.
op_offload: offload host tensor operations to device
Expand Down Expand Up @@ -203,6 +206,34 @@ def __init__(

set_verbose(verbose)

# Resolve embedding / embeddings. Historical name is ``embedding``;
# ``embeddings`` is accepted as an alias. The bare ``**kwargs`` sink
# previously swallowed the plural form so failures only appeared later
# inside embed() (issue #2210).
if embeddings is not None:
if not isinstance(embeddings, bool):
raise TypeError(
f"embeddings must be a bool, got {type(embeddings).__name__}"
)
if embedding is True and embeddings is False:
raise ValueError(
"Conflicting values for embedding=True and embeddings=False"
)
# When embeddings is provided, it is authoritative for the plural alias.
# If embedding was left at the default False, adopt embeddings.
# If embedding is True, require embeddings to also be True (checked above).
embedding = embeddings

if kwargs:
unknown = ", ".join(sorted(str(k) for k in kwargs))
warnings.warn(
f"Llama() got unexpected keyword argument(s): {unknown}. "
"These were ignored. If you meant embedding mode, pass "
"embedding=True (or embeddings=True).",
UserWarning,
stacklevel=2,
)

if not Llama.__backend_initialized:
with suppress_stdout_stderr(disable=verbose):
llama_cpp.llama_backend_init()
Expand Down Expand Up @@ -1088,7 +1119,7 @@ def embed(

if self.context_params.embeddings is False:
raise RuntimeError(
"Llama model must be created with embedding=True to call this method"
"Llama model must be created with embedding=True (or embeddings=True) to call this method"
)

if self.verbose:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_llama.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,3 +653,28 @@ def test_real_llama_embeddings(llama_cpp_embedding_model_path):
repeated_embeddings = model.embed(list(reversed(prompts)))
assert len(repeated_embeddings) == len(prompts)
assert all(len(repeated) == len(embedding) for repeated in repeated_embeddings)


def test_embeddings_kwarg_alias_and_unknown_kwargs():
"""embeddings= is accepted; unknown kwargs warn; conflicts raise (issue #2210)."""
import warnings

missing = "/nonexistent/path/to/model.gguf"

with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
try:
llama_cpp.Llama(model_path=missing, embeddings=True, not_a_real_flag=1)
except ValueError as exc:
assert "does not exist" in str(exc)
else:
raise AssertionError("expected ValueError for missing model path")
assert any(issubclass(w.category, UserWarning) for w in caught)
assert any("not_a_real_flag" in str(w.message) for w in caught)

try:
llama_cpp.Llama(model_path=missing, embedding=True, embeddings=False)
raise AssertionError("expected conflicting embedding kwargs ValueError")
except ValueError as exc:
assert "Conflicting" in str(exc)