> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Embedding

> Turn text and media into vectors for search, RAG, and memory

An **Embedding Model** converts text (and, for multimodal models, images, videos, and other media) into dense vectors that power semantic search, RAG, and memory retrieval. AgentScope currently ships the following embedding model classes:

| Provider  | Model Class               | Highlights                                                                                             |
| --------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
| DashScope | `DashScopeEmbeddingModel` | Unified text + multimodal API (`text-embedding-v4`, `qwen3-vl-embedding`, ...), content-aware batching |
| OpenAI    | `OpenAIEmbeddingModel`    | `text-embedding-3-small/large`, compatible with OpenAI-compatible endpoints                            |
| Gemini    | `GeminiEmbeddingModel`    | Text (`gemini-embedding-001`) and multimodal (`gemini-embedding-2`, image / video / audio / PDF)       |
| Ollama    | `OllamaEmbeddingModel`    | Local embedding models (`nomic-embed-text`, ...), credential carries the host URL                      |

## Create Embedding Model

Every embedding model takes a credential, a model name, and an optional `Parameters` object, the same pattern as chat models. `Parameters` carries `dimensions`, the output vector size:

<CodeGroup>
  ```python DashScope theme={null}
  import os
  from agentscope.embedding import DashScopeEmbeddingModel
  from agentscope.credential import DashScopeCredential

  model = DashScopeEmbeddingModel(
      credential=DashScopeCredential(api_key=os.environ["DASHSCOPE_API_KEY"]),
      model="text-embedding-v4",
      parameters=DashScopeEmbeddingModel.Parameters(dimensions=1024),
  )
  ```

  ```python OpenAI theme={null}
  import os
  from agentscope.embedding import OpenAIEmbeddingModel
  from agentscope.credential import OpenAICredential

  model = OpenAIEmbeddingModel(
      credential=OpenAICredential(api_key=os.environ["OPENAI_API_KEY"]),
      model="text-embedding-3-small",
      parameters=OpenAIEmbeddingModel.Parameters(dimensions=1536),
  )
  ```

  ```python Gemini theme={null}
  import os
  from agentscope.embedding import GeminiEmbeddingModel
  from agentscope.credential import GeminiCredential

  model = GeminiEmbeddingModel(
      credential=GeminiCredential(api_key=os.environ["GEMINI_API_KEY"]),
      model="gemini-embedding-001",
      parameters=GeminiEmbeddingModel.Parameters(dimensions=768),
  )
  ```

  ```python Ollama theme={null}
  from agentscope.embedding import OllamaEmbeddingModel
  from agentscope.credential import OllamaCredential

  model = OllamaEmbeddingModel(
      credential=OllamaCredential(host="http://localhost:11434"),
      model="nomic-embed-text",
  )
  ```
</CodeGroup>

Common constructor arguments shared by every embedding model:

| Argument          | Type                         | Description                                                                            |
| ----------------- | ---------------------------- | -------------------------------------------------------------------------------------- |
| `credential`      | `CredentialBase`             | Provider-specific credential                                                           |
| `model`           | `str`                        | Model identifier (e.g. `"text-embedding-v4"`)                                          |
| `parameters`      | `Parameters \| None`         | `dimensions`, the output vector size (default `512`)                                   |
| `embedding_cache` | `EmbeddingCacheBase \| None` | Optional cache that skips repeated API calls (see [Embedding Cache](#embedding-cache)) |
| `context_size`    | `int`                        | Maximum input tokens per item                                                          |
| `max_retries`     | `int`                        | Maximum retries per batch on retryable failures                                        |
| `retry_delay`     | `float`                      | Seconds between retry attempts                                                         |

<Info>
  Valid `dimensions` values differ per model: each model card pins the default via its top-level `dimensions` field and the allowed values via `supported_dimensions` (e.g. `text-embedding-v4` accepts 2048 / 1536 / 1024 / ... / 64). See [EmbeddingModelCard](#embeddingmodelcard).
</Info>

## Call Embedding Model

Invoke the model by calling it with a list of inputs. Text-only models accept `list[str]`; multimodal models also accept `DataBlock` elements:

```python theme={null}
async def __call__(
    self,
    inputs: list[str | DataBlock],
    **kwargs: Any,
) -> EmbeddingResponse:
```

Batching and retry are handled for you:

1. Inputs are split into chunks of the model's batch size (10 for DashScope text, 2048 for OpenAI, 100 for Gemini, 512 for Ollama).
2. All chunks are dispatched **concurrently** via `asyncio.gather`.
3. Each chunk is retried independently up to `max_retries` times on provider-specific retryable errors.
4. Results are merged into a single `EmbeddingResponse`, preserving input order.

```python theme={null}
import asyncio
import os
from agentscope.embedding import DashScopeEmbeddingModel
from agentscope.credential import DashScopeCredential

async def main():
    model = DashScopeEmbeddingModel(
        credential=DashScopeCredential(api_key=os.environ["DASHSCOPE_API_KEY"]),
        model="text-embedding-v4",
        parameters=DashScopeEmbeddingModel.Parameters(dimensions=1024),
    )
    response = await model(
        ["What is AgentScope?", "A multi-agent framework."],
    )
    print(len(response.embeddings))     # 2, one vector per input
    print(len(response.embeddings[0]))  # 1024
    print(response.usage.tokens)        # total tokens consumed
    print(response.source)              # "api" or "cache"

asyncio.run(main())
```

Each `EmbeddingResponse` carries:

| Field                        | Type                     | Description                                                     |
| ---------------------------- | ------------------------ | --------------------------------------------------------------- |
| `embeddings`                 | `list[Embedding]`        | One vector per input, in input order                            |
| `usage`                      | `EmbeddingUsage \| None` | `tokens` consumed and `time` elapsed in seconds                 |
| `source`                     | `"api" \| "cache"`       | Whether the result came from the API or the cache               |
| `id` / `created_at` / `type` | `str`                    | Response identity and timestamp; `type` is always `"embedding"` |

### Multimodal Embedding

Multimodal models (`DashScopeEmbeddingModel` with `qwen3-vl-embedding` etc., `GeminiEmbeddingModel` with `gemini-embedding-2`) accept `DataBlock` inputs alongside strings (images as URL or base64, videos as URL):

```python theme={null}
import asyncio
import os
from agentscope.embedding import DashScopeEmbeddingModel
from agentscope.credential import DashScopeCredential
from agentscope.message import DataBlock, URLSource

async def main():
    model = DashScopeEmbeddingModel(
        credential=DashScopeCredential(api_key=os.environ["DASHSCOPE_API_KEY"]),
        model="qwen3-vl-embedding",
    )
    response = await model([
        "A cat sitting on a windowsill",
        DataBlock(
            source=URLSource(
                url="https://example.com/cat.png",
                media_type="image/png",
            ),
        ),
    ])
    print(len(response.embeddings))  # 2, one vector per input

asyncio.run(main())
```

<Info>
  Multimodal models replace the plain batch-size split with **content-aware batching**: inputs are greedily packed into batches that respect the model's per-request limits on total elements, images, and videos (e.g. `qwen3-vl-embedding` allows 20 elements / 5 images / 1 video per request, `tongyi-embedding-vision-plus` allows 20 / 64 / 8). You never need to split inputs yourself.
</Info>

## Embedding Cache

Pass an `EmbeddingCacheBase` implementation through the `embedding_cache` argument to reuse previously computed vectors. The built-in `FileEmbeddingCache` stores each result as a `.npy` file keyed by the SHA-256 hash of the request:

```python theme={null}
import asyncio
import os
from agentscope.embedding import DashScopeEmbeddingModel, FileEmbeddingCache
from agentscope.credential import DashScopeCredential

async def main():
    model = DashScopeEmbeddingModel(
        credential=DashScopeCredential(api_key=os.environ["DASHSCOPE_API_KEY"]),
        model="text-embedding-v4",
        embedding_cache=FileEmbeddingCache(
            cache_dir="./.cache/embeddings",
            max_file_number=1000,
            max_cache_size=100,  # MB
        ),
    )
    r1 = await model(["What is AgentScope?"])
    print(r1.source)  # "api": first call hits the API

    r2 = await model(["What is AgentScope?"])
    print(r2.source)  # "cache": identical request served locally

asyncio.run(main())
```

When `max_file_number` or `max_cache_size` is exceeded, the oldest files are evicted first. To use a different backend (Redis, SQLite, ...), subclass `EmbeddingCacheBase` and implement its four methods: `store`, `retrieve`, `remove`, and `clear`.

## Custom Embedding Provider

Adding an embedding provider follows the same steps as a [custom chat provider](/versions/2.0.5dev/en/building-blocks/model/llm#custom-provider).

### Step 1: Link the Credential

Override `get_embedding_model_class()` on your credential (the base implementation returns `None`, meaning "no embedding support"):

```python theme={null}
from typing import Type, TYPE_CHECKING
from agentscope.credential import CredentialBase

if TYPE_CHECKING:
    from agentscope.embedding import EmbeddingModelBase

class MyProviderCredential(CredentialBase):
    # ... fields and get_chat_model_class() as before ...

    @classmethod
    def get_embedding_model_class(cls) -> Type["EmbeddingModelBase"]:
        from .my_embedding import MyProviderEmbeddingModel
        return MyProviderEmbeddingModel
```

### Step 2: Implement the Embedding Model

Subclass `EmbeddingModelBase` and implement `_call_api` for a **single batch**; batching, concurrency, and retry are inherited from the base class. Declare provider-specific transient errors via `_get_retryable_exceptions`:

```python theme={null}
from typing import Any, Type
from agentscope.embedding import EmbeddingModelBase, EmbeddingResponse, EmbeddingUsage

class MyProviderEmbeddingModel(EmbeddingModelBase[str]):
    def __init__(
        self,
        credential: "MyProviderCredential",
        model: str,
        parameters: "MyProviderEmbeddingModel.Parameters | None" = None,
        context_size: int = 8192,
        max_retries: int = 3,
        retry_delay: float = 1.0,
    ) -> None:
        super().__init__(
            credential=credential,
            model=model,
            parameters=parameters,
            context_size=context_size,
            batch_size=100,          # max items per API call
            max_retries=max_retries,
            retry_delay=retry_delay,
        )

    @classmethod
    def _get_retryable_exceptions(cls) -> tuple[Type[Exception], ...]:
        return (TimeoutError,)       # retried up to max_retries times

    async def _call_api(
        self,
        inputs: list[str],
        **kwargs: Any,
    ) -> EmbeddingResponse:
        # len(inputs) <= self.batch_size is guaranteed.
        # Call your provider's API and return the vectors.
        ...
```

Bind the generic parameter to the input type your provider supports: `EmbeddingModelBase[str]` for text-only, `EmbeddingModelBase[str | DataBlock]` for multimodal, so IDEs surface the correct `inputs` type to callers.

### Step 3: Add Model Cards (optional)

Drop YAML files into a `_models/` directory next to your implementation; `MyProviderEmbeddingModel.list_models()` then picks them up, exactly like chat model cards.

## EmbeddingModelCard

`EmbeddingModelCard` mirrors the general [ModelCard](/versions/2.0.5dev/en/building-blocks/model/overview#integrate-with-frontend) for the frontend, with embedding-specific defaults: the output type `application/x-embedding` marks a model as producing dense vectors.

| Field                  | Difference from `ModelCard`                                                                                                |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `type`                 | Always `"embedding_model"`                                                                                                 |
| `input_types`          | Defaults to `["text/plain"]`; multimodal cards add `image/*`, `video/*`, ...                                               |
| `output_types`         | Defaults to `["application/x-embedding"]`                                                                                  |
| `dimensions`           | **Required** top-level field: the default output vector size, exposed as a strongly typed `int`                            |
| `supported_dimensions` | Allowed output sizes for Matryoshka-style models (e.g. OpenAI's `text-embedding-3-*`); `None` means the dimension is fixed |
| `context_size`         | Optional; maximum input tokens per request, if known                                                                       |
| `output_size`          | Not present; embedding models have no output token limit                                                                   |

A typical YAML card (the real card for `text-embedding-v4`):

```yaml theme={null}
name: text-embedding-v4
label: Text Embedding v4
status: active

input_types:
  - text/plain

output_types:
  - application/x-embedding

context_size: 8192

# Default output vector size, plus the sizes this
# Matryoshka-style model can be truncated to
dimensions: 1024
supported_dimensions: [2048, 1536, 1024, 768, 512, 256, 128, 64]
```

Retrieve cards from the model class directly, or discover the class from a credential via `get_embedding_model_class()`:

```python theme={null}
from agentscope.credential import DashScopeCredential
from agentscope.embedding import OpenAIEmbeddingModel

# Directly on the model class
cards = OpenAIEmbeddingModel.list_models()

# Or discover the class from a credential
embed_cls = DashScopeCredential.get_embedding_model_class()
cards = embed_cls.list_models()

for card in cards:
    print(f"{card.name}: context={card.context_size}, inputs={card.input_types}")
```
