【高速缓存】RedisVL使用 SemanticRouter 进行智能查询路由指南
2026/7/22 23:08:00 网站建设 项目流程

引言

在构建复杂的 AI 应用时,我们常常需要根据用户查询的主题意图,将请求分发到不同的处理模块。例如,一个客服机器人可能需要将技术问题转给技术专家、将账单问题转给财务系统、将投诉转给投诉处理部门。传统做法是使用关键词匹配或规则分类,但这些方法维护困难、泛化能力弱。

语义路由(Semantic Routing)提供了一种更智能的方式:它将每个可能的目标(称为“路由”,Route)用一组代表性的参考语句(references)来刻画,当用户查询到来时,系统计算查询与所有参考语句的语义相似度,并选择最匹配的一个或多个路由进行分发。

RedisVL 的SemanticRouter类基于 Redis 的向量搜索能力,实现了高效、可扩展的语义路由。它将每个参考语句转换为向量并存储在 Redis 中,查询时通过 KNN 搜索找到最相似的参考,再聚合到路由层面做出决策。

本指南将带你从零开始,掌握如何定义路由、初始化路由器、执行查询路由、动态管理路由引用,以及序列化配置。


前置条件

  • 已安装 RedisVL:pip install redisvl
  • 一个运行中的 Redis 实例(推荐 Redis 8+ 或 Redis Cloud)

概要

  • 定义包含参考语句和距离阈值的路由
  • 初始化和配置SemanticRouter
  • 将查询路由到单个或多个匹配路由
  • 序列化和恢复路由器配置(JSON / YAML)
  • 动态添加、获取和删除路由引用

语义路由的工作原理

语义路由的核心是向量相似度搜索。其流程如下:

  1. 定义路由:每个路由有一个名称、一组参考语句(例如典型问题或关键词),以及一个距离阈值(决定匹配的宽松程度)。
  2. 向量化:所有参考语句通过嵌入模型(如sentence-transformers/all-mpnet-base-v2)转换为高维向量,并存入 Redis 的向量索引中。
  3. 查询:当用户输入查询时,同样将其向量化,并在 Redis 中执行 KNN 搜索,找出距离最近的若干参考语句。
  4. 聚合与决策:根据找到的参考语句所属的路由,采用平均距离最小距离等聚合方法,计算每个候选路由的最终得分(距离)。只有那些距离小于各自路由阈值的路由才会被采纳。

下图直观展示了这一流程:

用户查询

将查询向量化

在 Redis 中执行 KNN 搜索

得到 N 个最近的参考语句及其距离

按路由分组,聚合距离(平均/最小)

距离 < 路由阈值?

将该路由加入候选列表

丢弃

返回排序后的路由列表

这种方式的优势在于:

  • 语义理解:不依赖关键词,能处理同义表达。
  • 灵活阈值:每个路由可单独控制匹配严格程度。
  • 多路由支持:一个查询可以同时匹配多个路由(例如“AI 在篮球中的应用”既匹配技术也匹配体育)。

定义路由

每个路由由Route对象定义,关键属性包括:

  • name:路由的唯一标识。
  • references:字符串列表,代表该路由的语义覆盖范围。可以是问题、关键词或短语。
  • metadata:可选字典,用于存储额外信息(如优先级、分类标签)。
  • distance_threshold:余弦距离阈值(范围 0~2,越小越严格)。只有查询与路由中某个参考的距离小于该阈值时,才视为匹配。

下面定义三个路由:技术、体育、娱乐。

fromredisvl.extensions.routerimportRoute technology=Route(name="technology",references=["人工智能有哪些最新进展?","给我讲讲最新的科技产品","科技领域有什么新趋势?"],metadata={"category":"tech","priority":1},distance_threshold=0.71)sports=Route(name="sports",references=["昨晚谁赢了比赛?","告诉我即将到来的体育赛事","体育界最近有什么新闻?","体育","篮球和足球"],metadata={"category":"sports","priority":2},distance_threshold=0.72)entertainment=Route(name="entertainment",references=["现在最火的电影是什么?","谁获得了最佳男演员奖?","娱乐圈有什么新鲜事?"],metadata={"category":"entertainment","priority":3},distance_threshold=0.7)

说明:距离阈值需要根据实际应用调整。较高的阈值(如 0.72)会匹配更多查询,但可能误召;较低的阈值(如 0.7)更严格,召回率降低。


初始化 SemanticRouter

SemanticRouter在初始化时会自动在 Redis 中创建索引(如果不存在)。你可以指定嵌入模型(默认使用HFTextVectorizer,模型为sentence-transformers/all-mpnet-base-v2)。

importosfromredisvl.extensions.routerimportSemanticRouterfromredisvl.utils.vectorizeimportHFTextVectorizer os.environ["TOKENIZERS_PARALLELISM"]="false"router=SemanticRouter(name="topic-router",# Redis 索引名称vectorizer=HFTextVectorizer(),# 嵌入模型routes=[technology,sports,entertainment],# 初始路由列表redis_url="redis://localhost:6379",overwrite=True# 如存在同名索引则覆盖)

初始化后,可以查看索引信息:

rvl index info-itopic-router

你会看到索引包含reference(文本)、vector(向量)、route_name(标签)等字段。num_docs等于所有参考语句的总数(此处为 11 条)。


简单路由查询

使用router(query)方法,返回最佳匹配的路由(RouteMatch对象,包含名称和距离)。若无匹配,则返回name=None

# 匹配技术路由route_match=router("你能告诉我人工智能的最新进展吗?")print(route_match)# RouteMatch(name='technology', distance=0.419...)# 不匹配任何路由route_match=router("外星人真的存在吗?")print(route_match)# RouteMatch(name=None, distance=None)

如果需要返回多个候选路由(按距离升序),使用route_many方法:

# 返回最多 3 个候选路由matches=router.route_many("AI 如何在篮球中应用?",max_k=3)formatchinmatches:print(match.name,match.distance)# 可能输出: technology 0.556, sports 0.671

聚合方法(Aggregation Method)

当查询匹配到一个路由的多个参考时,需要将这些距离聚合为一个最终距离。SemanticRouter支持两种聚合方式:

  • avg(默认):计算该路由所有匹配参考的平均距离。
  • min:只取最小的距离(即最接近的参考)。

选择min会让路由更容易被匹配(因为只要有一个参考足够接近即可),而avg则更稳健,能避免因个别噪音参考导致的误匹配。

你可以通过更新路由配置来切换聚合方法:

fromredisvl.extensions.routerimportRoutingConfigfromredisvl.extensions.router.schemaimportDistanceAggregationMethod router.update_routing_config(RoutingConfig(aggregation_method=DistanceAggregationMethod.min,max_k=3))matches=router.route_many("勒布朗·詹姆斯")print(matches)# 可能只匹配 sports

序列化与恢复

你可以将路由器配置导出为字典或 YAML 文件,便于保存或跨环境迁移。

# 导出为字典config_dict=router.to_dict()print(config_dict.keys())# 包含 name, routes, vectorizer, routing_config# 从字典恢复router2=SemanticRouter.from_dict(config_dict,redis_url="redis://localhost:6379")# 导出为 YAML 文件router.to_yaml("router.yaml",overwrite=True)# 从 YAML 恢复router3=SemanticRouter.from_yaml("router.yaml",redis_url="redis://localhost:6379")

恢复时,Redis 索引会自动重建(如果不存在)。


动态管理路由引用

在实际应用中,你可能需要动态添加或删除某个路由的参考语句,而不需要重建整个路由器。SemanticRouter提供了相关方法。

添加参考

added_ids=router.add_route_references(route_name="technology",references=["最新 AI 趋势","新科技产品"])print(added_ids)# 返回新增参考的 Redis key 列表

获取参考

你可以按路由名称或参考 ID 获取所有参考语句。

# 按路由名称获取refs=router.get_route_references(route_name="technology")forrefinrefs:print(ref["reference"])# 按参考 ID 获取(示例取第一个)first_id=refs[0]["reference_id"]single_ref=router.get_route_references(reference_ids=[first_id])

删除参考

可以按路由名称删除该路由下的所有参考,或按指定 ID 删除特定参考。

# 删除整个 sports 路由的参考deleted_count=router.delete_route_references(route_name="sports")print(f"删除了{deleted_count}条参考")# 删除特定参考deleted_count=router.delete_route_references(reference_ids=[first_id])print(f"删除了{deleted_count}条参考")

清理资源

  • clear():清空索引中的所有参考数据,但保留索引结构。
  • delete():删除整个索引(包括数据结构),彻底移除。
router.clear()# 清空数据router.delete()# 删除索引

总结

  • 原理:基于向量相似度搜索和聚合,实现灵活的语义路由。
  • 定义路由:通过参考语句和距离阈值刻画每个路由的语义范围。
  • 查询路由:支持单匹配和多匹配,可调节聚合方法(平均/最小)。
  • 动态管理:可以随时增删改路由参考,无需重建索引。
  • 可移植性:配置可序列化为字典或 YAML,方便版本控制和部署。

语义路由是构建智能对话系统、RAG 应用、多任务分发系统的核心组件。RedisVL 提供的高性能向量检索能力,让这一切变得简单而高效。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询