You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

5.9 KiB

AI Provider Factory 缓存永不过期机制

日期: 2026-02-14
类型: Bug 修复 + 架构优化
影响范围: 后端 AI Provider 缓存系统
严重程度: 高(影响所有 AI 功能)


问题描述

原问题

应用在运行 5 小时后,用户调用 AI 功能时出现错误:

模型 {model_name} 不存在或未激活。
请检查:1) 模型是否已同步到数据库 2) 模型是否已启用(is_active=True) 3) Redis 缓存是否已初始化

根本原因

  • Redis 缓存 TTL 过短: 原 TTL 为 3600 秒(1 小时)
  • 缓存过期后未自动重建: 应用启动 5 小时后,缓存已过期且未刷新

问题影响

  • 所有 AI 相关功能(文生图、文生视频、配音等)不可用
  • 需要手动重启应用才能恢复

解决方案

技术方案

采用 永不过期 + 懒加载 + 手动刷新 的组合方案:

  1. Redis 缓存永不过期: 彻底解决缓存失效问题
  2. 实现懒加载: 缓存不存在时自动从数据库重建
  3. 手动刷新接口: 模型更新后可主动刷新缓存
  4. 应用启动时强制刷新: 确保数据最新

方案演进

阶段 方案 TTL 问题
阶段 1 原方案 1 小时 1 小时后服务不可用
阶段 2 延长 TTL 24 小时 ⚠️ 24 小时后仍会过期
阶段 3 永不过期 彻底解决缓存失效问题

为什么永不过期是最优解?

AI 模型配置的特点

  • 📊 低频变更: 通常几周/几个月才更新一次
  • 🔒 管理员操作: 模型更新由管理员控制
  • 📈 高频读取: 每次 AI 请求都需要查询模型配置

永不过期的优势

  • 零缓存失效: 彻底消除缓存过期问题
  • 性能最优: 所有请求都从 Redis 读取(< 1ms)
  • 架构简单: 无需管理 TTL,无需定时任务
  • 可控刷新: 主动控制刷新时机

关键改动

1. 移除 CACHE_TTL

class AIProviderFactory:
-   CACHE_TTL = 86400  # 缓存过期时间:24 小时
+   # 注意:缓存永不过期,模型更新后需手动调用 refresh_cache()

2. 使用 redis.set() 替代 redis.setex()

# 应用启动时初始化
- await redis.setex(cls.CACHE_KEY, cls.CACHE_TTL, json.dumps(cache_dict))
+ await redis.set(cls.CACHE_KEY, json.dumps(cache_dict))

# 懒加载重建
- await redis_client.setex(cls.CACHE_KEY, cls.CACHE_TTL, json.dumps(cache_dict))
+ await redis_client.set(cls.CACHE_KEY, json.dumps(cache_dict))

3. 更新日志信息

- logger.info("✅ AI Provider Factory 缓存已初始化(Redis): 已加载 %d 个模型", len(cache_dict))
+ logger.info("✅ AI Provider Factory 缓存已初始化(Redis,永不过期): 已加载 %d 个模型", len(cache_dict))

- logger.info("✅ 缓存重建成功: 已加载 %d 个模型", len(cache_dict))
+ logger.info("✅ 缓存重建成功(永不过期): 已加载 %d 个模型", len(cache_dict))

验证测试

测试 1: 懒加载验证

# 1. 清空缓存
docker exec jointo-server-redis redis-cli DEL "ai_models:provider_cache"

# 2. 执行测试
docker exec jointo-server-app python tests/manual/test_cache_lazy_loading.py

# 预期结果
⚠️ Redis 缓存为空,正在从数据库重建缓存...
✅ 缓存重建成功(永不过期): 已加载 21 个模型

测试 2: 永不过期验证

# 检查 TTL
docker exec jointo-server-redis redis-cli TTL "ai_models:provider_cache"
# 返回: -1 (表示永不过期)

运维指南

何时需要刷新缓存?

当执行以下操作后,需要手动刷新缓存:

  1. ✏️ 新增/删除 AI 模型
  2. ✏️ 修改模型配置(provider、capabilities)
  3. ✏️ 启用/禁用模型(is_active

刷新缓存的方法

方法 1: 代码中调用(推荐)

from app.services.ai_providers.factory import AIProviderFactory

# 在修改模型后立即刷新
await AIProviderFactory.refresh_cache(db)

方法 2: 重启应用

docker restart jointo-server-app

应用启动时会自动刷新缓存。

方法 3: 删除 Redis 键(触发懒加载)

docker exec jointo-server-redis redis-cli DEL "ai_models:provider_cache"

下次 AI 请求时会自动重建缓存。


性能影响

正常情况(缓存命中)

  • Redis 查询: 1 次 GET(< 1ms)
  • 数据库查询: 0 次
  • 性能: 最优

缓存重建(懒加载触发)

  • 数据库查询: 1 次(< 100ms,21 个模型)
  • 频率: 仅在缓存被手动删除或 Redis 重启后触发

架构优势

  1. 零缓存失效 - 永不过期,应用可长期运行
  2. 性能最优 - 所有请求都从 Redis 读取
  3. 架构简单 - 无需管理 TTL,无需定时任务
  4. 可控刷新 - 管理员主动控制刷新时机

风险与缓解

风险 1: 忘记刷新缓存

缓解:

  • 代码规范:模型更新时自动调用 refresh_cache()
  • 应用重启:部署新版本时自动刷新
  • 懒加载兜底:缓存被删除时自动重建

风险 2: Redis 重启导致缓存丢失

缓解:

  • 懒加载:自动从数据库重建
  • Redis 持久化:生产环境已启用 RDB/AOF

后续优化建议

1. 自动刷新集成

在模型更新的 Service 层自动刷新缓存。

2. 监控告警

添加 Prometheus 指标:ai_cache_rebuilds_total

3. 管理后台

添加缓存管理界面(查看状态、手动刷新)


相关文件

修改文件

  • server/app/services/ai_providers/factory.py

新增文件

  • server/tests/manual/test_cache_lazy_loading.py

变更记录

  • 2026-02-14 17:30: 升级为永不过期方案
  • 2026-02-14 17:25: 初版(24h TTL + 懒加载)
  • 修复人员: AI Assistant