Merge pull request #26976 from BerriAI/litellm_default_embedding_encoding_format

feat(embedding): default OpenAI-path encoding_format to float
This commit is contained in:
Mateo Wang
2026-05-01 15:37:59 -07:00
committed by GitHub
4 changed files with 155 additions and 25 deletions
+12 -1
View File
@@ -2,4 +2,15 @@ No transformation is required for hosted_vllm embedding.
VLLM is a superset of OpenAI's `embedding` endpoint.
To pass provider-specific parameters, see [this](https://docs.litellm.ai/docs/completion/provider_specific_params)
## `encoding_format`
For OpenAI-compatible embedding calls (including `openai/...` with a custom `api_base` pointing at vLLM), LiteLLM resolves `encoding_format` when it is not set on the request:
1. Explicit value on the embedding call (`encoding_format=...`).
2. Model config (`litellm_params.encoding_format` on the proxy `model_list` entry).
3. Environment variable `LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT` (e.g. in `.env` or container env).
4. Default **`float`**.
That avoids forwarding `encoding_format=None` to the provider/SDK where some servers behave poorly.
To pass provider-specific parameters, see [provider-specific params](https://docs.litellm.ai/docs/completion/provider_specific_params).
+11 -2
View File
@@ -4923,8 +4923,17 @@ def embedding( # noqa: PLR0915
if encoding_format is not None:
optional_params["encoding_format"] = encoding_format
else:
# Omiting causes openai sdk to add default value of "float"
optional_params["encoding_format"] = None
env_fmt = get_secret_str("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT")
if env_fmt is not None and env_fmt.strip().lower() == "none":
optional_params.pop("encoding_format", None)
else:
_default_fmt = (
optional_params.get("encoding_format") or env_fmt or "float"
)
if _default_fmt.strip().lower() == "none":
optional_params.pop("encoding_format", None)
else:
optional_params["encoding_format"] = _default_fmt
api_version = None
+8 -22
View File
@@ -1257,22 +1257,13 @@ def test_jina_ai_img_embeddings(input_data, expected_payload_input):
assert sent_data["input"] == expected_payload_input
def test_encoding_format_none_not_omitted_from_openai_sdk():
def test_encoding_format_defaults_to_float_for_openai_sdk(monkeypatch):
"""
Test that encoding_format=None is explicitly sent to OpenAI SDK.
When encoding_format is not provided, LiteLLM sends `float` for OpenAI-path embeddings.
This test verifies that when encoding_format is not provided by the user,
liteLLM explicitly sets it to None rather than omitting it. This prevents
the OpenAI SDK from adding its default value of 'base64'.
Without this fix:
- OpenAI SDK adds encoding_format='base64' as default when parameter is missing
- This causes issues with providers that don't support encoding_format (like Gemini)
With this fix:
- encoding_format=None is explicitly passed
- OpenAI SDK respects the explicit None and doesn't add defaults
Optional global override: `LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT`.
"""
monkeypatch.delenv("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT", raising=False)
with patch(
"litellm.llms.openai.openai.OpenAIChatCompletion._get_openai_client"
) as mock_get_client:
@@ -1310,17 +1301,12 @@ def test_encoding_format_none_not_omitted_from_openai_sdk():
call_kwargs = call_args[1] # Get kwargs
# The key assertion: encoding_format should be in the request with value None
# This prevents OpenAI SDK from adding its default 'base64' value
assert "encoding_format" in call_kwargs, (
"encoding_format should be explicitly passed to OpenAI SDK "
"(even if None) to prevent SDK from adding default value"
)
assert "encoding_format" in call_kwargs
assert (
call_kwargs["encoding_format"] is None
), "encoding_format should be None when not provided by user"
call_kwargs["encoding_format"] == "float"
), "encoding_format should default to float when not provided by user"
print("✅ PASS: encoding_format=None is correctly passed to OpenAI SDK")
print("✅ PASS: encoding_format='float' is correctly passed to OpenAI SDK")
def test_encoding_format_explicit_value_preserved():
@@ -0,0 +1,124 @@
from unittest.mock import MagicMock, patch
import pytest
from litellm import embedding
@pytest.mark.parametrize(
"set_env, env_value, expected",
[
(False, None, "float"),
(True, "base64", "base64"),
],
)
def test_openai_embedding_encoding_format_default(
monkeypatch, set_env, env_value, expected
):
monkeypatch.delenv("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT", raising=False)
if set_env:
monkeypatch.setenv("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT", env_value)
mock_response = MagicMock()
mock_response.parse.return_value = MagicMock(
model_dump=lambda: {
"data": [{"embedding": [0.1, 0.2, 0.3], "index": 0}],
"model": "text-embedding-ada-002",
"object": "list",
"usage": {"prompt_tokens": 1, "total_tokens": 1},
}
)
mock_response.headers = {}
with patch(
"litellm.llms.openai.openai.OpenAIChatCompletion._get_openai_client"
) as mock_get_client:
mock_client_instance = MagicMock()
mock_get_client.return_value = mock_client_instance
mock_client_instance.embeddings.with_raw_response.create.return_value = (
mock_response
)
embedding(
model="text-embedding-ada-002",
input="Hello world",
)
call_kwargs = (
mock_client_instance.embeddings.with_raw_response.create.call_args[1]
)
assert call_kwargs["encoding_format"] == expected
@pytest.mark.parametrize("env_none", ["none", "NONE", " none "])
def test_openai_embedding_encoding_format_env_none_omits_param(
monkeypatch, env_none
):
"""LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT=none omits encoding_format (provider default)."""
monkeypatch.setenv("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT", env_none)
mock_response = MagicMock()
mock_response.parse.return_value = MagicMock(
model_dump=lambda: {
"data": [{"embedding": [0.1, 0.2, 0.3], "index": 0}],
"model": "text-embedding-ada-002",
"object": "list",
"usage": {"prompt_tokens": 1, "total_tokens": 1},
}
)
mock_response.headers = {}
with patch(
"litellm.llms.openai.openai.OpenAIChatCompletion._get_openai_client"
) as mock_get_client:
mock_client_instance = MagicMock()
mock_get_client.return_value = mock_client_instance
mock_client_instance.embeddings.with_raw_response.create.return_value = (
mock_response
)
embedding(
model="text-embedding-ada-002",
input="Hello world",
)
call_kwargs = (
mock_client_instance.embeddings.with_raw_response.create.call_args[1]
)
assert "encoding_format" not in call_kwargs
def test_openai_embedding_encoding_format_explicit_overrides_env(monkeypatch):
"""Request `encoding_format` wins over LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT."""
monkeypatch.setenv("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT", "float")
mock_response = MagicMock()
mock_response.parse.return_value = MagicMock(
model_dump=lambda: {
"data": [{"embedding": [0.1, 0.2, 0.3], "index": 0}],
"model": "text-embedding-ada-002",
"object": "list",
"usage": {"prompt_tokens": 1, "total_tokens": 1},
}
)
mock_response.headers = {}
with patch(
"litellm.llms.openai.openai.OpenAIChatCompletion._get_openai_client"
) as mock_get_client:
mock_client_instance = MagicMock()
mock_get_client.return_value = mock_client_instance
mock_client_instance.embeddings.with_raw_response.create.return_value = (
mock_response
)
embedding(
model="text-embedding-ada-002",
input="Hello world",
encoding_format="base64",
)
call_kwargs = (
mock_client_instance.embeddings.with_raw_response.create.call_args[1]
)
assert call_kwargs["encoding_format"] == "base64"