Files
2026-07-06 23:15:06 -04:00

92 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Redis 响应缓存 — content-addressed SHA256 键,Redis 不可用时静默降级。"""
from __future__ import annotations
import dataclasses
import hashlib
import json
from typing import Any
from loguru import logger
from core.types import LLMResponse
class RedisResponseCache:
"""基于 Redis 的 LLM 响应缓存。
使用 content-addressed 策略:key = sha256(model + json(messages))
值为 JSON 序列化的 LLMResponse。
当 Redis 不可用时静默降级:get 返回 None,set 吞异常并记录 warning。
Args:
redis: 异步 Redis 客户端实例(duck-typed,需支持 get/set 方法)。
ttl_s: 缓存过期时间(秒)。
"""
def __init__(self, redis: Any, ttl_s: int) -> None:
self._redis = redis
self._ttl_s = ttl_s
def _build_key(self, model: str, messages: list[dict[str, str]]) -> str:
"""构造 content-addressed 缓存键。
Args:
model: 模型名称。
messages: 消息列表。
Returns:
sha256 哈希字符串作为 Redis 键。
"""
payload = json.dumps(
{"model": model, "messages": messages},
sort_keys=True,
ensure_ascii=False,
)
digest = hashlib.sha256(payload.encode("utf-8")).hexdigest()
return f"llm_cache:{digest}"
async def get(self, model: str, messages: list[dict[str, str]]) -> LLMResponse | None:
"""从缓存读取 LLM 响应。
Args:
model: 模型名称。
messages: 消息列表。
Returns:
缓存命中时返回 LLMResponse,未命中或 Redis 异常时返回 None。
"""
try:
key = self._build_key(model, messages)
raw = await self._redis.get(key)
except Exception:
logger.warning("Redis 缓存读取失败,降级为未命中")
return None
if raw is None:
return None
data = json.loads(raw)
return LLMResponse(**data)
async def set(
self,
model: str,
messages: list[dict[str, str]],
response: LLMResponse,
) -> None:
"""将 LLM 响应写入缓存。
Args:
model: 模型名称。
messages: 消息列表。
response: 待缓存的 LLMResponse。
"""
try:
key = self._build_key(model, messages)
value = json.dumps(dataclasses.asdict(response), ensure_ascii=False)
await self._redis.set(key, value, ex=self._ttl_s)
except Exception:
logger.warning("Redis 缓存写入失败,跳过缓存")