Skip to content

windlass.providers.embeddings.hf_inference

hf_inference

HuggingFace Inference API embeddings.

The huggingface provider runs sentence-transformers locally — which means torch, a model download, and a machine with the RAM to hold it. This one calls the hosted inference endpoint instead: an API token, no local model, no cold start on your own hardware.

It needs no optional dependency at all. httpx is already part of the core install, so this works on a bare pip install windlass::

embedder = Windlass.embedding("hf_inference", model="BAAI/bge-base-en-v1.5")

BGE and E5 models expect an instruction prefix on queries but not on documents. Getting that asymmetry wrong is a silent quality bug — retrieval still "works", just worse — so the prefixes are declared through the interface's own hooks and applied by the base class on the right side of the split.

Example

from windlass import Windlass # doctest: +SKIP emb = Windlass.embedding("hf_inference") # doctest: +SKIP len(emb.embed_one("hello")) # doctest: +SKIP 768

HuggingFaceInferenceEmbedder

HuggingFaceInferenceEmbedder(
    model: str = "",
    *,
    api_key: str | None = None,
    timeout: float = 60.0,
    base_url: str = _ROUTER,
    dimensions: int | None = None,
    **config: Any
)

Bases: Embedder

Embeddings from the hosted HuggingFace Inference API.

Parameters:

Name Type Description Default
model str

Repository id, e.g. "BAAI/bge-base-en-v1.5".

''
api_key str | None

Token. Falls back to HUGGINGFACE_API_KEY then HF_TOKEN.

None
timeout float

Per-request timeout. Hosted models cold-start, so this is generous by default.

60.0
base_url str

Inference router base URL. Override for a dedicated endpoint.

_ROUTER
dimensions int | None

Output width. Inferred for known models, which lets a vector store be provisioned before the first call.

None
**config Any

Forwarded to :class:~windlass.interfaces.embedding.Embedder.

{}

Raises:

Type Description
AuthenticationError

When no token is configured.

Example

from windlass import Windlass # doctest: +SKIP emb = Windlass.embedding("hf_inference") # doctest: +SKIP emb.dimension() # doctest: +SKIP 768

Source code in src\windlass\providers\embeddings\hf_inference.py
def __init__(
    self,
    model: str = "",
    *,
    api_key: str | None = None,
    timeout: float = 60.0,
    base_url: str = _ROUTER,
    dimensions: int | None = None,
    **config: Any,
) -> None:
    resolved = model or self.default_model()
    super().__init__(
        resolved,
        dimensions=dimensions if dimensions is not None else _KNOWN_DIMENSIONS.get(resolved),
        **config,
    )
    key = api_key or os.environ.get("HUGGINGFACE_API_KEY") or os.environ.get("HF_TOKEN")
    if not key:
        from windlass.core.config import settings

        key = settings().secret("huggingface_api_key")
    if not key:
        raise AuthenticationError(
            "No API token configured for the HuggingFace Inference API.",
            provider="hf_inference",
            hint=(
                "Set HUGGINGFACE_API_KEY (or HF_TOKEN) in your environment or .env,\n"
                "    or pass Windlass.embedding('hf_inference', api_key='hf_...')."
            ),
        )
    self.base_url = base_url.rstrip("/")
    self.timeout = timeout
    self.query_prefix = _QUERY_PREFIXES.get(resolved, "")
    self.document_prefix = _DOCUMENT_PREFIXES.get(resolved, "")
    self._client = httpx.AsyncClient(
        timeout=timeout,
        headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
    )

default_model classmethod

default_model() -> str

Return "BAAI/bge-base-en-v1.5".

Source code in src\windlass\providers\embeddings\hf_inference.py
@classmethod
def default_model(cls) -> str:
    """Return ``"BAAI/bge-base-en-v1.5"``."""
    return "BAAI/bge-base-en-v1.5"

native

native() -> httpx.AsyncClient

Return the underlying httpx.AsyncClient (Level 3 access).

Source code in src\windlass\providers\embeddings\hf_inference.py
def native(self) -> httpx.AsyncClient:
    """Return the underlying ``httpx.AsyncClient`` (Level 3 access)."""
    return self._client

aembed_texts async

aembed_texts(texts: list[str], *, kind: str = 'document') -> list[list[float]]

Embed one batch through the feature-extraction pipeline.

Parameters:

Name Type Description Default
texts list[str]

Texts to embed, already carrying any instruction prefix.

required
kind str

"document" or "query"; the prefix was applied upstream.

'document'

Returns:

Type Description
list[list[float]]

One vector per input, in input order.

Raises:

Type Description
AuthenticationError

On 401 or 403.

RateLimitError

On 429.

ProviderTimeoutError

On a timeout or a cold-starting model (503).

ProviderError

For any other failure, including a response whose shape does not match the request.

Source code in src\windlass\providers\embeddings\hf_inference.py
async def aembed_texts(self, texts: list[str], *, kind: str = "document") -> list[list[float]]:
    """Embed one batch through the feature-extraction pipeline.

    Args:
        texts: Texts to embed, already carrying any instruction prefix.
        kind: ``"document"`` or ``"query"``; the prefix was applied upstream.

    Returns:
        One vector per input, in input order.

    Raises:
        AuthenticationError: On 401 or 403.
        RateLimitError: On 429.
        ProviderTimeoutError: On a timeout or a cold-starting model (503).
        ProviderError: For any other failure, including a response whose
            shape does not match the request.
    """
    url = f"{self.base_url}/{self.model}/pipeline/feature-extraction"
    try:
        response = await self._client.post(url, json={"inputs": texts})
    except httpx.TimeoutException as exc:
        raise ProviderTimeoutError(
            f"HuggingFace did not respond within {self.timeout:g}s.",
            provider="hf_inference",
            hint="Hosted models cold-start. Raise timeout=... or retry.",
            original=exc,
        ) from exc
    except httpx.HTTPError as exc:
        raise ProviderError(
            f"Could not reach the HuggingFace Inference API: {exc}",
            provider="hf_inference",
            original=exc,
        ) from exc

    self._raise_for_status(response)

    try:
        payload = response.json()
    except ValueError as exc:
        raise ProviderError(
            "HuggingFace returned a non-JSON response.",
            provider="hf_inference",
            context={"body": response.text[:200]},
            original=exc,
        ) from exc

    return self._as_vectors(payload, expected=len(texts))

aclose async

aclose() -> None

Close the HTTP connection pool.

Source code in src\windlass\providers\embeddings\hf_inference.py
async def aclose(self) -> None:
    """Close the HTTP connection pool."""
    await self._client.aclose()