Skip to Content
RecipesCustom embedder

Custom embedder

You’ll plug your own embedding model into agent memory, here a local sentence-transformers model that needs no API key. Use this pattern when the built-in embedders don’t fit: loomflow ships OpenAIEmbedder, VoyageEmbedder and CohereEmbedder (plus HashEmbedder for tests) in loomflow.memory, so you only need a custom one for other providers, self-hosted models, or offline use.

Any class with name, dimensions, an async embed(text) and an async embed_batch(texts) satisfies the Embedder protocol. No inheritance required.

import anyio from loomflow import Agent from loomflow.memory.vector import VectorMemory class SentenceTransformerEmbedder: """Local embeddings with sentence-transformers; no network calls.""" def __init__(self, model_name: str = "all-MiniLM-L6-v2") -> None: from sentence_transformers import SentenceTransformer self._model = SentenceTransformer(model_name) self.name = model_name self.dimensions = self._model.get_sentence_embedding_dimension() async def embed(self, text: str) -> list[float]: return (await self.embed_batch([text]))[0] async def embed_batch(self, texts: list[str]) -> list[list[float]]: # encode() is CPU-bound and blocking: run it off the event loop. vectors = await anyio.to_thread.run_sync(self._model.encode, texts) return [vector.tolist() for vector in vectors] memory = VectorMemory(embedder=SentenceTransformerEmbedder()) agent = Agent("...", model="claude-opus-4-7", memory=memory)

Keep embed and embed_batch async, and move blocking work (local inference, a synchronous SDK) to a worker thread as above so it doesn’t stall other runs. The framework only uses the protocol surface, so the same shape works for any provider.

Last updated on