Semantic Router
Build fast decision models that run directly in Redis. The extensions/router package classifies incoming statements against a set of routes — each defined by example reference phrases — using vector search and FT.AGGREGATE, a port of the Python library’s SemanticRouter.
Defining routes
A Route is a named topic described by reference phrases:
import "github.com/redis/redis-vl-golang/extensions/router"
routes := []router.Route{
{
Name: "greeting",
References: []string{"hello", "hi", "good morning"},
Metadata: map[string]any{"category": "smalltalk"},
DistanceThreshold: 0.3,
},
{
Name: "technical",
References: []string{
"a for loop", "code error", "debugging an application",
},
Metadata: map[string]any{"category": "support", "priority": 1},
DistanceThreshold: 0.7,
},
{
Name: "farewell",
References: []string{"bye", "goodbye", "see you later"},
Metadata: map[string]any{"category": "smalltalk"},
DistanceThreshold: 0.3,
},
}
Route fields:
| Field | Description | Default |
|---|---|---|
|
Route name (required, non-empty). |
— |
|
Example phrases for the route (required, non-empty). |
— |
|
Arbitrary data associated with the route. |
none |
|
Maximum distance for matching this route, in |
|
Creating the router
NewSemanticRouter creates the index, embeds every reference phrase with the given vectorizer, and stores them in Redis:
sr, err := router.NewSemanticRouter(ctx, client, "topic-router", routes, vectorizer)
A vectorize.Vectorizer is required — the Go port has no default local embedding model. See Vectorizers.
|
Options are passed with SemanticRouterOptions:
sr, err := router.NewSemanticRouter(ctx, client, "topic-router", routes, vectorizer,
router.SemanticRouterOptions{
Config: router.RoutingConfig{
MaxK: 2, // matches returned by RouteMany (default 1)
Aggregation: router.Min, // router.Avg (default), router.Min, router.Sum
},
Overwrite: true, // recreate the index if it already exists
})
Routing statements
Route classifies a statement to the single best route. A zero-value RouteMatch (empty Name) means no route matched within its threshold:
match, err := sr.Route(ctx, "Hi, good morning")
if match.Name != "" {
fmt.Printf("route=%s distance=%.4f\n", match.Name, match.Distance)
}
// >>> route=greeting distance=0.2739
RouteMany returns up to Config.MaxK matches, ordered by distance:
matches, err := sr.RouteMany(ctx, "my code is throwing an error")
// >>> [{Name: "technical", Distance: 0.41}, ...]
Both methods accept an optional precomputed vector to skip the embedding step:
match, err := sr.Route(ctx, "", vector)
How matching works
Each route may have several references, so the router aggregates the vector distances of all matching references per route inside Redis (FT.AGGREGATE with GROUPBY route_name). The Aggregation method controls how distances are combined:
| Method | Behavior |
|---|---|
|
Average distance across matching references — balanced. |
|
Closest single reference wins — most permissive. |
|
Sum of distances — favors routes with many close references. |
Per-route distance thresholds are enforced server-side, so a route only matches when its aggregated distance is below its own DistanceThreshold.
Semantic routing uses vector similarity inside FT.AGGREGATE, which requires Redis 7.x or greater.
|
Updating configuration and thresholds
// inspect and update the routing config
cfg := sr.Config()
sr.UpdateConfig(router.RoutingConfig{MaxK: 3, Aggregation: router.Avg})
// inspect and tune per-route thresholds
thresholds := sr.RouteThresholds() // map[string]float64
sr.UpdateRouteThresholds(map[string]float64{
"greeting": 0.4,
"farewell": 0.35,
})
Managing routes
// add a new route (or extra references to an existing route name)
err = sr.AddRoute(ctx, router.Route{
Name: "billing",
References: []string{"invoice question", "refund request"},
})
// remove a route and its references from Redis
err = sr.RemoveRoute(ctx, "billing")
// accessors
name := sr.Name() // router name
routes := sr.Routes() // configured routes
Cleanup
err = sr.Clear(ctx) // delete all route references, keep the index and route definitions
err = sr.Delete(ctx) // remove the router index and all references
See also
-
Vectorizers — embedding providers for the router
-
Semantic Caching — cache LLM responses by prompt similarity
-
Querying with RedisVL — the query primitives the router builds on