RedisVL 阈值优化

发布于:2025-06-26 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、背景与挑战

  • 初始阈值难以兼顾
    一开始往往只能使用经验值(如 0.5)进行设置,但对不同业务场景与数据分布,有时过松会导致误命中,过紧又会漏命中。
  • 手工调参成本高
    传统做法需要编写大量脚本,手工跑多次 A/B 测试,耗时且易出错。
  • 自动化需求
    希望提供一种轻量级、可复现的阈值调优流程,兼顾准确率和召回率。

二、CacheThresholdOptimizer:语义缓存阈值优化

1. 场景描述

假设已经搭建了一个语义缓存 sem_cache,最初将阈值设为 0.5,并在其中存储了以下条目:

from redisvl.extensions.cache.llm import SemanticCache
from redisvl.utils.vectorize import HFTextVectorizer

sem_cache = SemanticCache(
    name="sem_cache",
    redis_url="redis://localhost:6379",
    distance_threshold=0.5,
    vectorizer=HFTextVectorizer("redis/langcache-embed-v1")
)

paris_key = sem_cache.store(prompt="what is the capital of france?", response="paris")
rabat_key = sem_cache.store(prompt="what is the capital of morocco?", response="rabat")

此时对无关问题(如 “what’s the capital of Britain?”)仍能命中,说明阈值过于宽松。

2. 定义测试数据

构造一个包含“正例”、“反例”与“多个正例”的列表:

test_data = [
    {"query": "What's the capital of Britain?",        "query_match": ""          },  # 反例
    {"query": "What's the capital of France??",       "query_match": paris_key   },  # 正例
    {"query": "What's the capital city of Morocco?",  "query_match": rabat_key   },  # 正例
]
  • "query_match" 为空字符串表示该 query 应该命中任何缓存条目。

3. 运行优化器

from redisvl.utils.optimize import CacheThresholdOptimizer

print(f"优化前阈值:{sem_cache.distance_threshold}\n")
optimizer = CacheThresholdOptimizer(sem_cache, test_data)
optimizer.optimize()
print(f"优化后阈值:{sem_cache.distance_threshold}\n")
  • 内部原理:遍历多个可能阈值,通过计算 F1 分数(兼顾准确率与召回率)来选出最佳阈值。
  • 优化结果:例如阈值从 0.5 优化为 ~0.1037,使得“Britain”反例不再命中,而“France”与“Morocco”正例仍可命中。

4. 验证效果

# 反例不再命中
assert sem_cache.check("what's the capital of britain?") == []

# 正例仍可命中
hits = sem_cache.check("what's the capital city of france?")
assert hits[0]["response"] == "paris"

三、RouterThresholdOptimizer:语义路由阈值优化

1. 场景描述

假设有一个简单的“问候/告别”语义路由器:

from redisvl.extensions.router import Route
from redisvl.extensions.router import SemanticRouter
from redisvl.utils.vectorize import HFTextVectorizer

routes = [
    Route(name="greeting",  references=["hello", "hi"],      metadata={}, distance_threshold=0.5),
    Route(name="farewell",  references=["bye",   "goodbye"], metadata={}, distance_threshold=0.5),
]

router = SemanticRouter(
    name="greeting-router",
    vectorizer=HFTextVectorizer(),
    routes=routes,
    redis_url="redis://localhost:6379",
    overwrite=True
)

当前两个路由的阈值都为 0.5,但在遇到多种问候与告别表达时,需要细粒度调优。

2. 定义测试数据

列举大量同义表达与“非路由”反例:

test_data = [
    # Greeting 同义扩展
    {"query":"hello",    "query_match":"greeting"},
    {"query":"good morning","query_match":"greeting"},
    {"query":"yo",       "query_match":"greeting"},
    # Farewell 同义扩展
    {"query":"bye",      "query_match":"farewell"},
    {"query":"see you later","query_match":"farewell"},
    {"query":"peace out","query_match":"farewell"},
    # 反例
    {"query":"what's the capital of britain?","query_match":""},
    {"query":"tell me a joke",              "query_match":""},
]

3. 运行优化器

from redisvl.utils.optimize import RouterThresholdOptimizer

print(f"优化前阈值:{router.route_thresholds}\n")
optimizer = RouterThresholdOptimizer(router, test_data)
optimizer.optimize()
print(f"优化后阈值:{router.route_thresholds}\n")
  • 内部原理:同时对所有路由阈值进行随机搜索与 F1 评分,选出最优组合。
  • 优化结果:如 {"greeting": 0.58, "farewell": 0.75},使更多同义表达被正确分类,同时避免将无关句子误路由。

4. 测试效果

# 匹配 “hi there” 到 greeting
match = router("hi there")
assert match.name == "greeting"

# “goodbye!” 匹配到 farewell
match = router("goodbye!")
assert match.name == "farewell"

# 反例不命中
match = router("what's for dinner?")
assert match.name is None

四、优化流程总结

  1. 准备初始实例

    • 对于缓存:SemanticCache(distance_threshold=初始值)
    • 对于路由:SemanticRouter(routes=..., route_thresholds=初始值)
  2. 构造测试数据

    • 正例:应命中某条缓存或对应路由
    • 反例:不应命中任何条目或路由
  3. 调用优化器

    • CacheThresholdOptimizer.optimize()
    • RouterThresholdOptimizer.optimize()
  4. 验证效果

    • 使用 .check() 或直接调用路由器,确保正例命中且反例不命中

五、最佳实践

  • 多样化测试样本:涵盖同义表达、噪声文本与边界情况,确保优化结果稳健。
  • 定期复训:当缓存或路由的参考集更新后,需重新运行优化器。
  • 性能监控:记录优化前后命中率、错误率与延迟,评估实际业务效果。
  • 自动化集成:将优化流程纳入 CI/CD 管道,保持阈值与数据同步演进。

通过上述两种优化器,RedisVL 帮助你从经验值调参,过渡到基于实际业务样本的自动化阈值搜索,大幅减少人工成本,并显著提升语义缓存与路由系统的准确性与鲁棒性。


网站公告

今日签到

点亮在社区的每一天
去签到