中转平台Redis缓存模型回复,降低上游调用成本实践
中转平台如果每次都直接请求上游大模型 API,相同问题也会重复计费,费用高不说,响应还慢。
本文将带你用 Redis 缓存模型回复,把相同参数的请求直接命中缓存,跳过上游调用,从而降低上游调用成本、提升响应速度。
你只需要一台装了 Redis 的服务器和一段可改动的中转服务代码,跟着操作即可落地。
哪些中转场景最适合做缓存
缓存不是万能药,先确认你的业务是否匹配:
- 用户重复提问相似问题,比如常见咨询、知识问答、固定格式生成。
- 同一套
model + messages + temperature组合会被多次请求。 - 上游按 token 计费,且对相同结果没有强制实时性要求。
如果你的平台大量请求都是随机对话、内容每次都不同,缓存收益会很低;
如果存在明显热点词或重复固定 prompt,缓存就能大幅节省成本。
落地前需要准备什么
- Redis 服务:建议 6.x 以上,确保支持
SETEX、NX等基础命令。 - 中转服务代码:不管你是用 Python、Node.js 还是 Go,只要能读取请求参数和返回结果即可。
- 上游 API 密钥:继续保留原有调用逻辑,缓存只作为前置拦截。
准备好后,先确认 Redis 连接正常:
redis-cli -h 127.0.0.1 -p 6379 ping
返回 PONG 就表示连接可用。
核心实现:写一个带缓存的中转请求逻辑
这里以 Python 为例,演示如何按请求参数生成缓存 key,并在命中缓存时直接返回。
import hashlib
import json
import redis
r = redis.Redis(host='127.0.0.1', port=6379, db=0, decode_responses=True)
CACHE_TTL = 3600 # 缓存1小时,按业务调整
def build_key(model, messages, temperature):
raw = json.dumps({
"model": model,
"messages": messages,
"temperature": temperature
}, ensure_ascii=False, sort_keys=True)
return "llm:reply:" + hashlib.md5(raw.encode("utf-8")).hexdigest()
def get_model_reply(model, messages, temperature=0.7):
key = build_key(model, messages, temperature)
cached = r.get(key)
if cached:
return json.loads(cached) # 已缓存,直接返回
# ---------- 原有上游调用代码 ----------
# 这里替换为你的真实请求逻辑,例如 openai.ChatCompletion.create(...)
# reply = upstream_request(model, messages, temperature)
# ------------------------------------
reply = "模拟的模型回复内容" # 实际请使用上游返回值
# 只缓存成功回复,避免错误结果被复用
if reply:
r.setex(key, CACHE_TTL, json.dumps(reply, ensure_ascii=False))
return reply
关键点:缓存 key 必须把影响输出结果的参数全部放进去,包括 model、完整的 messages、temperature、max_tokens 等。
忽略任何一项,都可能让不同请求拿到错误缓存。
避坑:缓存穿透、击穿和一致性
不要缓存错误响应。
上游返回 4xx、5xx 或空内容时,应该直接放行或做短时间内熔断,不能把错误结果存进 Redis。
避免缓存穿透。
大量请求携带的 key 不存在时,会全部打到上游。
可以为空结果设置极短 TTL(比如 60 秒),或加布隆过滤器。
避免缓存击穿。
某个热点 key 过期瞬间,并发请求会同时穿透到上游。
建议用 Redis SETNX 加锁:
import time
def acquire_lock(key, timeout=10):
lock_key = key + ":lock"
result = r.set(lock_key, "1", nx=True, ex=timeout)
return result
# 在缓存未命中时,先抢锁,抢到才请求上游,抢不到则等待后重读缓存
一致性怎么处理。
如果上游模型有更新版本,你可以把版本号拼进 key,比如 llm:reply:v2:;
或者直接清空对应前缀的缓存。
普通场景下设置合理 TTL 就够了。
验证成本是否真的降下来
上线后不要只看 Redis 内存,要关注三层指标:
- 上游调用数:在日志里统计同一时间段内真实发往上游的请求数,和总请求数对比,计算缓存命中率。
- 响应耗时:命中缓存的请求通常在 10ms 内返回,远低于上游的 1-3 秒,用监控工具对比平均耗时。
- 费用变化:通过上游 console 查看 token 消耗,看相同业务量下费用是否明显下降。
如果命中率低于 30%,说明你的请求多样性强,可以考虑调整 key 的粒度,比如只缓存 system prompt 固定的知识问答,而不是全部请求。
两个常见疑问
缓存回复会不会导致用户看到旧答案? 会,所以 TTL 不要设置过长。对时效性敏感的场景,建议 TTL 设为 300-1800 秒,或提供强制刷新参数跳过缓存。
多轮对话怎么缓存? 直接把整个 messages 数组作为 key 的一部分,只有上下文字符串完全一致才命中。你也可以只缓存单轮问答,多轮不做全量缓存。
按这套思路落地后,遇到 Redis 内存暴涨、命中率低或回复串号等问题,先检查 key 是否包含了所有影响输出的参数,再排查 TTL 和淘汰策略。
如果你正在处理中转平台 Redis 缓存模型回复降本,建议先从一个小范围的热点请求开始验证,确认稳定后再逐步放开缓存范围。