# Semantic Router

```json metadata
{
  "schema_version": 2,
  "title": "Semantic Router",
  "description": "",
  "categories": null,
  "tableOfContents": {"sections":[{"children":[{"id":"class-semanticroutername-routes-vectorizernone-routing_confignone-redis_clientnone-redis_urlredislocalhost6379-overwritefalse-connection_kwargsnone-create_indextrue","title":"class SemanticRouter(name, routes, vectorizer=None, routing_config=None, redis_client=None, redis_url='redis://localhost:6379', overwrite=False, connection_kwargs=None, create_index=True)"}],"id":"semantic-router","title":"Semantic Router"},{"children":[{"id":"class-routingconfig-max_k1-aggregation_methoddistanceaggregationmethodavg","title":"class RoutingConfig(*, max_k=1, aggregation_method=DistanceAggregationMethod.avg)"}],"id":"routing-config","title":"Routing Config"},{"children":[{"id":"class-route-name-references-metadata-distance_threshold05","title":"class Route(*, name, references, metadata={}, distance_threshold=0.5)"}],"id":"route","title":"Route"},{"children":[{"id":"class-routematch-namenone-distancenone","title":"class RouteMatch(*, name=None, distance=None)"}],"id":"route-match","title":"Route Match"},{"children":[{"id":"class-distanceaggregationmethodvalue-namesnone--modulenone-qualnamenone-typenone-start1-boundarynone","title":"class DistanceAggregationMethod(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)"}],"id":"distance-aggregation-method","title":"Distance Aggregation Method"}]}

,
  "codeExamples": [{"id":"semantic-router-api"}]
}
```



<a id="semantic-router-api"></a>

## Semantic Router

### `class SemanticRouter(name, routes, vectorizer=None, routing_config=None, redis_client=None, redis_url='redis://localhost:6379', overwrite=False, connection_kwargs=None, create_index=True)`

Semantic Router for managing and querying route vectors.

Initialize the SemanticRouter.

* **Parameters:**
  * **name** (*str*) – The name of the semantic router.
  * **routes** (*List* *[*[Route](#route) *]*) – List of Route objects.
  * **vectorizer** (*BaseVectorizer* *,* *optional*) – The vectorizer used to embed route references. Defaults to default HFTextVectorizer.
  * **routing_config** ([RoutingConfig](#routingconfig) *,* *optional*) – Configuration for routing behavior. Defaults to the default RoutingConfig.
  * **redis_client** (*Optional* *[* *SyncRedisClient* *]* *,* *optional*) – Redis client for connection. Defaults to None.
  * **redis_url** (*str* *,* *optional*) – The redis url. Defaults to redis://localhost:6379.
  * **overwrite** (*bool* *,* *optional*) – Whether to overwrite existing index. Defaults to False.
  * **connection_kwargs** (*Dict* *[* *str* *,* *Any* *]*) – The connection arguments
    for the redis client. Defaults to empty {}.
  * **create_index** (*bool* *,* *optional*) – Whether RedisVL creates and validates
    the index. When False the constructor issues no index command at
    all and writes nothing: the index must already exist, already
    hold the reference vectors for `routes`, and already have its
    stored config, since none of that is written or verified.
    `routes` must match what is indexed, because each route’s
    distance threshold is applied from this local list – and
    [add_route](#add_route) rewrites the stored config from that same list,
    so attaching with a partial set and then adding a route
    truncates the config every other client reads. See
    [`SemanticCache`](https://redis.io/docs/latest/cache/#semanticcache) for a worked
    example of the flag, and [Install RedisVL](https://redis.io/docs/latest/../user_guide/installation) for the
    ACL details. Defaults to True.
* **Raises:**
  **ValueError** – If both create_index is False and overwrite is True.

#### `add_route(route)`

Add a new route to the SemanticRouter.

Note that this replaces the router’s stored config with this instance’s
route list, so a router constructed with a subset of the indexed routes
will drop the rest from the config that [from_existing](#from_existing) reads.

Embeds the route’s references, writes them to the Redis index,
appends the route to `self.routes`, and persists the updated router
config so the route survives [from_existing](#from_existing).

* **Parameters:**
  **route** ([Route](#route)) – A fully-formed Route (name, references,
  distance_threshold, optional metadata).
* **Returns:**
  The added route’s name.
* **Return type:**
  str
* **Raises:**
  **ValueError** – If a route with this name already exists on the router.
      Use [add_route_references](#add_route_references) to extend an existing route.

#### `add_route_references(route_name, references)`

Add a reference(s) to an existing route.

* **Parameters:**
  * **router_name** (*str*) – The name of the router.
  * **references** (*Union* *[* *str* *,* *List* *[* *str* *]* *]*) – The reference or list of references to add.
  * **route_name** (*str*)
* **Returns:**
  The list of added references keys.
* **Return type:**
  List[str]

#### `async adisconnect()`

Close the async Redis connection opened by the async routing methods.

* **Return type:**
  None

#### `async aroute(statement=None, vector=None, *, aggregation_method=None)`

Async version of calling the router: match a statement or vector to
its best route without blocking the event loop.

Embedding uses the vectorizer’s `aembed` and the lookup runs on an
[`AsyncSearchIndex`](https://redis.io/docs/latest/searchindex/#asyncsearchindex) over the same Redis index, so
it returns the same match as `router(statement)`.

Pass `redis_url` rather than a client to the router if you need
async routing over SSL, a unix socket, Sentinel or Redis Cluster: those
clients cannot be converted to their async form. With a vectorizer that
has no native `aembed`, such as the default `HFTextVectorizer`,
embedding still blocks the loop; only the Redis call is non-blocking.
The async client is bound to the event loop that made the first call,
so call [adisconnect](#adisconnect) before switching loops.

* **Parameters:**
  * **statement** (*Optional* *[* *str* *]*) – The input statement to be queried.
  * **vector** (*Optional* *[* *List* *[* *float* *]* *]*) – The input vector to be queried.
  * **aggregation_method** (*Optional* *[*[DistanceAggregationMethod](#distanceaggregationmethod) *]*) – The aggregation method used for vector distances.
* **Returns:**
  The matching route.
* **Return type:**
  [RouteMatch](#routematch)

```python
match = await router.aroute("hi there")
```

#### `async aroute_many(statement=None, vector=None, *, max_k=None, aggregation_method=None)`

Async version of [route_many](#route_many): return up to `max_k` matching
routes without blocking the event loop. See [aroute](#aroute) for the
connection and vectorizer caveats.

* **Parameters:**
  * **statement** (*Optional* *[* *str* *]*) – The input statement to be queried.
  * **vector** (*Optional* *[* *List* *[* *float* *]* *]*) – The input vector to be queried.
  * **max_k** (*Optional* *[* *int* *]*) – The maximum number of top matches to return.
  * **aggregation_method** (*Optional* *[*[DistanceAggregationMethod](#distanceaggregationmethod) *]*) – The aggregation method used for vector distances.
* **Returns:**
  The matching routes and their details.
* **Return type:**
  List[[RouteMatch](#routematch)]

```python
matches = await router.aroute_many("hi there", max_k=2)
```

#### `clear()`

Delete every route reference, leaving the index in place.

Clears by index membership. Available under `create_index=False`;
dropping the index is [delete](#delete).

> [!WARNING]
> The stored `route_config` is left as it was, here and on the
> default path. A separate process calling [from_existing](#from_existing)
> afterwards will report routes whose reference vectors are gone.
> [remove_route](#remove_route) keeps the two in step.

* **Return type:**
  None

#### `delete()`

Delete the semantic router index and its persisted route config.

* **Raises:**
  **ValueError** – If `create_index=False`. Use [clear](#clear) to
      remove the route references and leave the index standing.
* **Return type:**
  None

#### `delete_route_references(route_name='', reference_ids=None, keys=None)`

Get references for an existing semantic router route.

* **Parameters:**
  * **Optional** (*keys*) – The name of the router.
  * **Optional** – The reference or list of references to delete.
  * **Optional** – List of fully qualified keys (prefix:router:reference_id) to delete.
  * **route_name** (*str*)
  * **reference_ids** (*list* *[* *str* *]*  *|* *None*)
  * **keys** (*list* *[* *str* *]*  *|* *None*)
* **Returns:**
  Number of objects deleted
* **Return type:**
  int
* **Raises:**
  * **ValueError** – If no references match the given route/ids/keys.
  * [**PartialDeletionError**](https://redis.io/docs/latest/exceptions/#partialdeletionerror) – If some keys could not be unlinked. Raised only
        after the surviving references have been reconciled and persisted,
        so a retry picks up exactly what is left.

> [!NOTE]
> Deleting every reference of a route removes the route itself, matching
> [remove_route](#remove_route). A route with no references cannot match anything,
> and [Route](#route) rejects an empty
> reference list, so persisting one would produce a config that
> [from_existing](#from_existing) can no longer load.

> [!NOTE]
> On Redis Cluster keys are unlinked one at a time and a per-key failure
> is logged rather than raised. References whose key failed to unlink are
> deliberately *kept* in the persisted route config: the hash is still in
> the index and the router would keep matching it, so dropping it from
> the config would leave the router claiming a reference is gone while
> still routing to it.

#### `classmethod from_dict(data, **kwargs)`

Create a SemanticRouter from a dictionary.

* **Parameters:**
  **data** (*Dict* *[* *str* *,* *Any* *]*) – The dictionary containing the semantic router data.
* **Returns:**
  The semantic router instance.
* **Return type:**
  [SemanticRouter](#semanticrouter)
* **Raises:**
  **ValueError** – If required data is missing or invalid.

```python
from redisvl.extensions.router import SemanticRouter
router_data = {
    "name": "example_router",
    "routes": [{"name": "route1", "references": ["ref1"], "distance_threshold": 0.5}],
    "vectorizer": {"type": "openai", "model": "text-embedding-ada-002"},
}
router = SemanticRouter.from_dict(router_data)
```

#### `classmethod from_existing(name, redis_client=None, redis_url='redis://localhost:6379', **kwargs)`

Return SemanticRouter instance from existing index.

Reads the stored route config with `JSON.GET`, so unlike
`SearchIndex.from_existing()` this needs no `FT.INFO`. Pass
`create_index=False` to keep it that way through construction, which
makes this the way to attach to a router with a credential that cannot
run index-metadata commands.

* **Parameters:**
  * **name** (*str*)
  * **redis_client** (*Redis* *|* *RedisCluster* *|* *None*)
  * **redis_url** (*str*)
* **Return type:**
  [SemanticRouter](#semanticrouter)

#### `classmethod from_yaml(file_path, **kwargs)`

Create a SemanticRouter from a YAML file.

* **Parameters:**
  **file_path** (*str*) – The path to the YAML file.
* **Returns:**
  The semantic router instance.
* **Return type:**
  [SemanticRouter](#semanticrouter)
* **Raises:**
  * **ValueError** – If the file path is invalid.
  * **FileNotFoundError** – If the file does not exist.

```python
from redisvl.extensions.router import SemanticRouter
router = SemanticRouter.from_yaml("router.yaml", redis_url="redis://localhost:6379")
```

#### `get(route_name)`

Get a route by its name.

* **Parameters:**
  **route_name** (*str*) – Name of the route.
* **Returns:**
  The selected Route object or None if not found.
* **Return type:**
  Optional[[Route](#route)]

#### `get_route_references(route_name='', reference_ids=None, keys=None)`

Get references for an existing route route.

* **Parameters:**
  * **router_name** (*str*) – The name of the router.
  * **references** (*Union* *[* *str* *,* *List* *[* *str* *]* *]*) – The reference or list of references to add.
  * **route_name** (*str*)
  * **reference_ids** (*list* *[* *str* *]*  *|* *None*)
  * **keys** (*list* *[* *str* *]*  *|* *None*)
* **Returns:**
  Reference objects stored
* **Return type:**
  List[Dict[str, Any]]]

#### `model_post_init(context, /)`

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

* **Parameters:**
  * **self** (*BaseModel*) – The BaseModel instance.
  * **context** (*Any*) – The context.
* **Return type:**
  None

#### `remove_route(route_name)`

Remove a route and all references from the semantic router.

Like [add_route](#add_route), this replaces the router’s stored config with
this instance’s route list, so removing one route from a router holding
only a subset drops the rest from the config [from_existing](#from_existing)
reads.

* **Parameters:**
  **route_name** (*str*) – Name of the route to remove.
* **Raises:**
  [**PartialDeletionError**](https://redis.io/docs/latest/exceptions/#partialdeletionerror) – If some of the route’s reference keys could not
      be unlinked. The route is then kept with exactly those references
      and the config persisted before raising, so the router keeps
      describing what the index can still match and a retry removes the
      remainder.
* **Return type:**
  None

#### `route_many(statement=None, vector=None, max_k=None, distance_threshold=None, aggregation_method=None)`

Query the semantic router with a given statement or vector for multiple matches.

* **Parameters:**
  * **statement** (*Optional* *[* *str* *]*) – The input statement to be queried.
  * **vector** (*Optional* *[* *List* *[* *float* *]* *]*) – The input vector to be queried.
  * **max_k** (*Optional* *[* *int* *]*) – The maximum number of top matches to return.
  * **distance_threshold** (*Optional* *[* *float* *]*) – The threshold for semantic distance.
  * **aggregation_method** (*Optional* *[*[DistanceAggregationMethod](#distanceaggregationmethod) *]*) – The aggregation method used for vector distances.
* **Returns:**
  The matching routes and their details.
* **Return type:**
  List[[RouteMatch](#routematch)]

#### `to_dict()`

Convert the SemanticRouter instance to a dictionary.

* **Returns:**
  The dictionary representation of the SemanticRouter.
* **Return type:**
  Dict[str, Any]

```python
from redisvl.extensions.router import SemanticRouter
router = SemanticRouter(name="example_router", routes=[], redis_url="redis://localhost:6379")
router_dict = router.to_dict()
```

#### `to_yaml(file_path, overwrite=True)`

Write the semantic router to a YAML file.

* **Parameters:**
  * **file_path** (*str*) – The path to the YAML file.
  * **overwrite** (*bool*) – Whether to overwrite the file if it already exists.
* **Raises:**
  **FileExistsError** – If the file already exists and overwrite is False.
* **Return type:**
  None

```python
from redisvl.extensions.router import SemanticRouter
router = SemanticRouter(
    name="example_router",
    routes=[],
    redis_url="redis://localhost:6379"
)
router.to_yaml("router.yaml")
```

#### `update_route_thresholds(route_thresholds)`

Update the distance thresholds for each route.

* **Parameters:**
  **route_thresholds** (*Dict* *[* *str* *,* *float* *]*) – Dictionary of route names and their distance thresholds.

#### `update_routing_config(routing_config)`

Update the routing configuration.

* **Parameters:**
  **routing_config** ([RoutingConfig](#routingconfig)) – The new routing configuration.

#### `property aindex: `[`AsyncSearchIndex`](https://redis.io/docs/latest/searchindex/#asyncsearchindex)`  | None`

The AsyncSearchIndex used by the async routing methods, once created.

* **Returns:**
  The async search index, or None before the first
  async call.
* **Return type:**
  [AsyncSearchIndex](https://redis.io/docs/latest/searchindex/#asyncsearchindex)

#### `model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}`

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

#### `name: str`

The name of the semantic router.

#### `property route_names: list[str]`

Get the list of route names.

* **Returns:**
  List of route names.
* **Return type:**
  List[str]

#### `property route_thresholds: dict[str, float | None]`

Get the distance thresholds for each route.

* **Returns:**
  Dictionary of route names and their distance thresholds.
* **Return type:**
  Dict[str, float]

#### `routes: `list[[Route](#route)]

List of Route objects.

#### `routing_config: `[RoutingConfig](#routingconfig)

Configuration for routing behavior.

#### `vectorizer: BaseVectorizer`

The vectorizer used to embed route references.

## Routing Config

### `class RoutingConfig(*, max_k=1, aggregation_method=DistanceAggregationMethod.avg)`

Configuration for routing behavior.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be
validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

* **Parameters:**
  * **max_k** (*Annotated* *[* *int* *,* *FieldInfo* *(* *annotation=NoneType* *,* *required=True* *,* *metadata=* *[* *Strict* *(* *strict=True* *)* *,* *Gt* *(* *gt=0* *)* *]* *)* *]*)
  * **aggregation_method** ([DistanceAggregationMethod](#distanceaggregationmethod))

#### `max_k: Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Strict(strict=True), Gt(gt=0)])]`

Aggregation method to use to classify queries.

#### `model_config: ClassVar[ConfigDict] = {'extra': 'ignore'}`

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

## Route

### `class Route(*, name, references, metadata={}, distance_threshold=0.5)`

Model representing a routing path with associated metadata and thresholds.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be
validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

* **Parameters:**
  * **name** (*str*)
  * **references** (*list* *[* *str* *]*)
  * **metadata** (*dict* *[* *str* *,* *Any* *]*)
  * **distance_threshold** (*Annotated* *[* *float* *,* *FieldInfo* *(* *annotation=NoneType* *,* *required=True* *,* *metadata=* *[* *Strict* *(* *strict=True* *)* *,* *Gt* *(* *gt=0* *)* *,* *Le* *(* *le=2* *)* *]* *)* *]*)

#### `distance_threshold: Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Strict(strict=True), Gt(gt=0), Le(le=2)])]`

Maximum distance for matching the route, inclusive.

#### `metadata: dict[str, Any]`

Metadata associated with the route.

#### `model_config: ClassVar[ConfigDict] = {}`

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

#### `name: str`

The name of the route.

#### `references: list[str]`

List of reference phrases for the route.

## Route Match

### `class RouteMatch(*, name=None, distance=None)`

Model representing a matched route with distance information.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be
validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

* **Parameters:**
  * **name** (*str* *|* *None*)
  * **distance** (*float* *|* *None*)

#### `distance: float | None`

The vector distance between the statement and the matched route.

#### `model_config: ClassVar[ConfigDict] = {}`

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

#### `name: str | None`

The matched route name.

## Distance Aggregation Method

### `class DistanceAggregationMethod(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)`

Enumeration for distance aggregation methods.

#### `avg = 'avg'`

Compute the average of the vector distances.

#### `min = 'min'`

Compute the minimum of the vector distances.

#### `sum = 'sum'`

Compute the sum of the vector distances.

