大模型应用:大模型响应缓存技术完全指南:TTL 缓存装饰器的设计与落地.112

简介: 本文详解大模型应用中缓存装饰器的实战实现,直击响应慢、成本高两大痛点。从基础缓存出发,逐步升级为支持TTL过期、线程安全、LRU淘汰、异常防护及哈希键优化的生产级方案,显著提升响应速度、降低Token消耗、增强系统稳定性。

一、前言

       现在我们做AI应用、大模型接口开发,基本都会碰到两个特别头疼的问题:一个是响应太慢,用户点一下要等好几秒,体验特别差;另一个就是调用成本太高,同样的问题反复问,每次都要重新调用大模型,Token哗啦哗啦的像流水一样就这么消耗了。尤其在客服问答、智能助手、内容生成、知识库查询这些真实业务里,大量用户的问题其实是重复、相似的,完全没必要每次都让大模型从头计算。

       缓存这个早就被验证过的经典思路,放到大模型场景里,就特别对症,把已经生成过的回答存起来,下次同样或类似的请求过来,直接从缓存里取,不用再麻烦大模型。既能秒级响应,又能大幅省成本,还能减轻大模型服务压力,提升系统稳定性。在实际应用落地过程中,缓存就是最直接、最有效、性价比最高的优化手段。我们前期通过《大模型数据缓存复用方案:从API请求数据累积到智能融合.50》讲解过基于向量化结合本地数据库的实现方案,今天我们换个思路,基于缓存装饰器的角度来实现。

112.2-大模型响应缓存技术完全指南.jpg

二、缓存技术基础

1. 缓存的本质与价值

       缓存(Cache)本质上是一种数据暂存机制,将高频访问的数据存储在读写速度更快的介质中,从而减少对低速数据源的重复访问。想象一下:我们每天上班都会路过便利店买早餐,如果每次都要重新确认早餐价格、口味,会浪费大量时间;但如果你把常用的早餐信息记在脑子里,相当于缓存,就能快速决策。这就是缓存的核心价值:用空间换时间。

在大模型应用场景中,缓存的价值体现在三个维度:

  • 响应速度:大模型生成文本通常需要数百毫秒甚至数秒,缓存命中可将响应时间降至微秒级
  • 成本控制:大模型 API 调用按 token 计费,重复请求相同 prompt 会产生不必要的费用
  • 系统稳定性:减少对大模型服务的请求量,降低接口限流、服务熔断的风险

112.3-大模型有缓存vs无缓存响应时间对比 llm_cache_response_time.png

2. 大模型缓存的特殊要求

与普通缓存不同,大模型缓存需要满足以下特性:

  • TTL(生存时间):大模型的回答存在时效性问题,可能随时间失效,需设置过期时间
  • 键值设计:prompt 通常包含大量文本,需生成唯一且高效的缓存键
  • 线程安全:生产环境中多线程调用需保证缓存操作的原子性
  • 缓存失效策略:需处理缓存击穿、缓存雪崩等常见问题

3. 缓存在大模型系统中的位置

以下流程图反映了缓存在大模型系统中的核心位置,用户请求首先经过缓存层,命中则直接返回,未命中才调用大模型并更新缓存;

112.4-缓存在大模型系统中的位置 deepseek_mermaid_20260309_b4c36e.png

大模型缓存命中率随请求次数变化:

112.5-大模型缓存命中率随请求次数变化 llm_cache_hit_rate.png

三、缓存装饰器基础

1. 装饰器基础原理

装饰器是 Python 的核心特性之一,用于在不修改函数源代码的前提下增强函数功能。其核心原理基于:

1.1 函数是一等对象

  • 在Python中,函数被视为“一等公民”。这意味着函数可以像整数或字符串一样被赋值给变量、作为参数传递给其他函数,甚至作为返回值从函数中返回。
  • 这种特性是构建高阶函数(如map、filter)和实现回调机制的基础,极大提升了代码的灵活性与复用性。

1.2 闭包

  • 闭包是指嵌套函数中,内部函数引用了外部函数的局部变量,即使外部函数已执行完毕,这些变量仍被内部函数“封闭”保存。
  • 闭包让函数拥有了“记忆”状态的能力,常用于实现装饰器、工厂函数或数据封装,无需使用类即可创建带有私有状态的 callable 对象。

1.3 functools.wraps

  • functools.wraps 是一个装饰器,用于在编写自定义装饰器时,将被包装函数的元数据(如 __name__、__doc__、__module__ 等)复制到包装函数上。
  • 若不使用它,调试或被装饰函数在查看帮助文档时会显示包装器的信息,导致混淆。它是编写规范、透明装饰器的必备工具。

基础装饰器结构:

import functools
def my_decorator(func):
    @functools.wraps(func)  # 保留原函数信息
    def wrapper(*args, **kwargs):
        # 执行前增强逻辑
        result = func(*args, **kwargs)
        # 执行后增强逻辑
        return result
    return wrapper
# 使用装饰器
@my_decorator
def say_hello(name):
    return f"Hello, {name}!"

image.gif

2. 基础缓存装饰器实现

我们先实现一个最简单的无过期时间的缓存装饰器,理解核心逻辑:

import functools
def simple_cache(func):
    """基础缓存装饰器(无过期时间)"""
    # 缓存存储:键=参数组合,值=函数返回结果
    cache_storage = {}
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 1. 生成缓存键:将参数转换为字符串作为唯一标识
        cache_key = (args, frozenset(kwargs.items()))  # 使用不可变类型作为键
        
        # 2. 检查缓存是否存在
        if cache_key in cache_storage:
            print(f"✅ 缓存命中:{cache_key}")
            return cache_storage[cache_key]
        
        # 3. 缓存未命中,执行原函数
        print(f"❌ 缓存未命中,执行函数:{cache_key}")
        result = func(*args, **kwargs)
        
        # 4. 将结果存入缓存
        cache_storage[cache_key] = result
        
        return result
    return wrapper
# 测试基础缓存
@simple_cache
def calculate_sum(a, b):
    """简单的求和函数,模拟耗时操作"""
    # 模拟计算耗时
    import time
    time.sleep(1)
    return a + b
# 第一次调用(缓存未命中)
print(calculate_sum(1, 2))  
# 第二次调用(缓存命中)
print(calculate_sum(1, 2))  
# 不同参数调用(缓存未命中)
print(calculate_sum(2, 3))

image.gif

代码关键说明:

  • cache_storage:字典结构,用于存储缓存数据,生命周期与装饰器绑定
  • cache_key:使用(args, frozenset(kwargs.items()))生成键,避免 kwargs 顺序影响,如func(a=1,b=2)和func(b=2,a=1)应视为同一键
  • functools.wraps:确保被装饰函数的__name__、__doc__等元信息不丢失

输出结果:

❌ 缓存未命中,执行函数:((1, 2), frozenset())

3

✅ 缓存命中:((1, 2), frozenset())

3

❌ 缓存未命中,执行函数:((2, 3), frozenset())

5

装饰器缓存机制的工作过程:

================== 三次调用的执行情况:==================

第一次调用 calculate_sum(1, 2)

  • 缓存中没有这个参数组合,所以显示 ❌ 缓存未命中
  • 执行函数计算(等待1秒),得到结果 3
  • 将结果存入缓存

第二次调用 calculate_sum(1, 2)

  • 缓存中已有 (1, 2) 的结果,显示 ✅ 缓存命中
  • 直接从缓存返回 3,无需重新计算(立即返回)

第三次调用 calculate_sum(2, 3)

  • 参数不同,缓存中没有这个组合
  • 显示 ❌ 缓存未命中,执行计算得到 5
  • 将新结果存入缓存

3. 增加 TTL 过期机制

基础缓存没有过期时间,无法满足大模型场景的时效性要求。我们在基础版本上增加 TTL(Time-To-Live)特性:

112.6-不同TTL过期时间对缓存有效性的影响 llm_cache_ttl_effect.png

import functools
import time
def ttl_cache(ttl=3600):
    """带过期时间的缓存装饰器
    
    Args:
        ttl: 缓存生存时间(秒),默认1小时
    """
    cache_storage = {}
    
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 1. 生成稳定的缓存键
            args_key = tuple(args)
            kwargs_key = frozenset(kwargs.items())
            cache_key = (args_key, kwargs_key)
            
            # 2. 检查缓存是否有效
            current_time = time.time()
            if cache_key in cache_storage:
                cached_time, cached_result = cache_storage[cache_key]
                # 判断是否过期
                if current_time - cached_time < ttl:
                    print(f"✅ 缓存命中(剩余有效期:{ttl - (current_time - cached_time):.1f}秒)")
                    return cached_result
                else:
                    print(f"⏰ 缓存过期,清除旧数据")
                    del cache_storage[cache_key]
            
            # 3. 执行原函数
            print(f"❌ 缓存未命中,执行函数")
            result = func(*args, **kwargs)
            
            # 4. 存储缓存(记录时间戳+结果)
            cache_storage[cache_key] = (current_time, result)
            
            return result
        return wrapper
    return decorator
# 测试TTL缓存
@ttl_cache(ttl=5)  # 缓存有效期5秒
def generate_greeting(name):
    """模拟生成个性化问候语的大模型函数"""
    time.sleep(1)  # 模拟大模型处理耗时
    from datetime import datetime
    now = datetime.now()
    return f"你好 {name}! 今天是 {now.strftime('%Y-%m-%d %H:%M:%S')}"
# 第一次调用(未命中)
print(generate_greeting("小王"))
# 立即第二次调用(命中)
print(generate_greeting("小王"))
# 等待6秒后调用(过期)
time.sleep(6)
print(generate_greeting("小王"))

image.gif

代码关键说明:

  • ttl参数:通过外层函数传递,实现缓存过期时间的自定义
  • 缓存值结构:从单纯存储结果改为存储(时间戳, 结果)元组
  • 过期判断:current_time - cached_time < ttl 检查缓存是否在有效期内
  • 过期清理:主动删除过期缓存,释放内存空间

输出结果:

你好 小王! 今天是 2026-03-09 21:51:45

✅ 缓存命中(剩余有效期:4.0秒)

你好 小王! 今天是 2026-03-09 21:51:45

⏰ 缓存过期,清除旧数据

❌ 缓存未命中,执行函数

你好 小王! 今天是 2026-03-09 21:51:52

四、大模型专用缓存装饰器实现

       在基础缓存装饰器我们实现了基础的 TTL 缓存功能,并使用functools.wraps保留函数元信息,支持参数化 TTL 配置,但还是存在一些问题:

  • 1. 缓存键生成方式不健壮:str(args) + str(kwargs) 可能产生重复键,如args=(1,2)和args=(12,)
  • 2. 无线程安全保护:多线程环境下可能出现竞态条件
  • 3. 无缓存容量限制:可能导致内存泄漏
  • 4. 无异常处理:原函数报错时也会缓存错误结果
  • 5. 缓存键未做哈希优化:长 prompt 会导致键过长

基与以上的分析优化,我们实现一个更健壮的大模型专用缓存装饰器:

import functools
import time
import hashlib
import threading
from typing import Any, Callable, Optional
class LLMResponseCache:
    """大模型响应缓存类(生产级实现)"""
    
    def __init__(self, default_ttl: int = 3600, max_size: int = 1000):
        """
        初始化缓存
        
        Args:
            default_ttl: 默认缓存有效期(秒)
            max_size: 缓存最大容量,防止内存溢出
        """
        # 核心缓存存储
        self._cache = {}
        # 缓存访问时间(用于LRU淘汰)
        self._access_times = {}
        # 默认TTL
        self._default_ttl = default_ttl
        # 缓存最大容量
        self._max_size = max_size
        # 线程锁(保证线程安全)
        self._lock = threading.Lock()
    
    def _generate_key(self, args: tuple, kwargs: dict) -> str:
        """生成稳定且高效的缓存键
        
        步骤:
        1. 将参数转换为有序的字符串
        2. 使用MD5哈希生成固定长度的键
        """
        # 处理位置参数
        args_str = "|".join(str(arg) for arg in args)
        # 处理关键字参数(按key排序保证顺序一致)
        kwargs_str = "|".join(f"{k}={v}" for k, v in sorted(kwargs.items()))
        # 组合并哈希
        raw_key = f"{args_str}||{kwargs_str}"
        # 使用MD5生成16进制哈希值(固定长度)
        return hashlib.md5(raw_key.encode('utf-8')).hexdigest()
    
    def _clean_expired(self) -> None:
        """清理所有过期的缓存项(需要在已获取锁的情况下调用)"""
        current_time = time.time()
        expired_keys = []
        
        for key, (timestamp, _) in self._cache.items():
            if current_time - timestamp > self._default_ttl:
                expired_keys.append(key)
        
        # 删除过期项
        for key in expired_keys:
            del self._cache[key]
            if key in self._access_times:
                del self._access_times[key]
    
    def _evict_lru(self) -> None:
        """LRU(最近最少使用)淘汰策略,当缓存满时删除最久未使用的项(需要在已获取锁的情况下调用)"""
        if len(self._cache) <= self._max_size:
            return
        
        if self._access_times:
            # 找到访问时间最早的键
            oldest_key = min(self._access_times.items(), key=lambda x: x[1])[0]
            # 删除最久未使用的项
            del self._cache[oldest_key]
            del self._access_times[oldest_key]
    
    def get(self, args: tuple, kwargs: dict) -> Optional[Any]:
        """获取缓存值(如果存在且有效)"""
        key = self._generate_key(args, kwargs)
        current_time = time.time()
        
        with self._lock:
            # 检查键是否存在
            if key not in self._cache:
                return None
            
            # 检查是否过期
            timestamp, result = self._cache[key]
            if current_time - timestamp > self._default_ttl:
                del self._cache[key]
                if key in self._access_times:
                    del self._access_times[key]
                return None
            
            # 更新访问时间(用于LRU)
            self._access_times[key] = current_time
            return result
    
    def set(self, args: tuple, kwargs: dict, result: Any) -> None:
        """设置缓存值"""
        key = self._generate_key(args, kwargs)
        current_time = time.time()
        
        with self._lock:
            # 清理过期项
            self._clean_expired()
            # 检查容量,必要时淘汰
            self._evict_lru()
            # 设置缓存
            self._cache[key] = (current_time, result)
            self._access_times[key] = current_time
    
    def clear(self) -> None:
        """清空所有缓存"""
        with self._lock:
            self._cache.clear()
            self._access_times.clear()
# 定义缓存装饰器工厂函数
def cache_llm_response(ttl: int = 3600, max_size: int = 1000):
    """大模型响应缓存装饰器(生产级)
    
    Args:
        ttl: 缓存有效期(秒)
        max_size: 缓存最大容量
    """
    # 创建缓存实例
    cache = LLMResponseCache(default_ttl=ttl, max_size=max_size)
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 尝试获取缓存
            cached_result = cache.get(args, kwargs)
            if cached_result is not None:
                print(f"✅ 缓存命中,直接返回结果")
                return cached_result
            
            # 缓存未命中,执行原函数(捕获异常避免缓存错误)
            try:
                print(f"❌ 缓存未命中,调用大模型")
                result = func(*args, **kwargs)
            except Exception as e:
                print(f"❌ 函数执行出错:{e}")
                raise  # 抛出异常,不缓存错误结果
            
            # 存入缓存
            cache.set(args, kwargs, result)
            return result
        
        # 为包装函数添加清理缓存的方法
        wrapper.clear_cache = cache.clear
        return wrapper
    
    return decorator
# ===================== 测试代码 =====================
from datetime import datetime
# 模拟大模型生成函数
def generate_text(prompt: str) -> str:
    """模拟大模型文本生成(带耗时)"""
    time.sleep(0.5)  # 模拟大模型处理耗时
    now = datetime.now()
    return f"大模型响应:{prompt} - {now.strftime('%Y-%m-%d %H:%M:%S')}"
# 使用缓存装饰器
@cache_llm_response(ttl=10, max_size=5)
def generate_text_with_cache(prompt: str) -> str:
    return generate_text(prompt)
# 测试流程
if __name__ == "__main__":
    # 第一次调用(未命中)
    print("=" * 50)
    print("测试1: 第一次调用(预期:缓存未命中)")
    print("=" * 50)
    print(generate_text_with_cache("你好"))
    print()
    
    # 第二次调用(命中)
    print("=" * 50)
    print("测试2: 第二次调用相同内容(预期:缓存命中)")
    print("=" * 50)
    print(generate_text_with_cache("你好"))
    print()
    
    # 调用不同prompt(未命中)
    print("=" * 50)
    print("测试3: 调用不同内容(预期:缓存未命中)")
    print("=" * 50)
    print(generate_text_with_cache("今天天气怎么样"))
    print()
    
    # 清空缓存
    print("=" * 50)
    print("测试4: 清空缓存后再次调用(预期:缓存未命中)")
    print("=" * 50)
    generate_text_with_cache.clear_cache()
    print(generate_text_with_cache("你好"))

image.gif

核心优化说明:

- 1. 缓存键优化

  • 问题:原始代码使用str(args) + str(kwargs)生成键,存在两个问题:
  • 1. 键长度不可控,长 prompt 会导致键过长)
  • 2. 易产生冲突,如args=(1,2)和args=(12,)的字符串拼接结果可能相似
  • 解决方案:使用 MD5 哈希生成固定长度(32 位)的键,同时对 kwargs 排序保证顺序一致性

- 2. 线程安全保障

  • 问题:多线程环境下,同时读写缓存可能导致:
  • 1. 缓存数据损坏
  • 2. 重复调用大模型,缓存被击穿
  • 解决方案:使用threading.Lock()实现互斥锁,确保缓存操作的原子性

- 3. 缓存淘汰策略

  • LRU(最近最少使用):当缓存达到最大容量时,删除最久未使用的项,避免内存溢出
  • 主动过期清理:定期清理过期缓存,释放内存空间

112.7-大模型缓存容量变化(LRU淘汰策略) llm_cache_capacity.png

- 4. 异常处理

  • 问题:如果大模型因网络错误调用失败,原始代码会缓存异常结果
  • 解决方案:使用 try-except 捕获异常,仅缓存成功的响应结果

输出结果:

==================================================

测试1: 第一次调用(预期:缓存未命中)

==================================================

❌ 缓存未命中,调用大模型

大模型响应:你好 - 2026-03-09 22:18:06

==================================================

测试2: 第二次调用相同内容(预期:缓存命中)

==================================================

✅ 缓存命中,直接返回结果

大模型响应:你好 - 2026-03-09 22:18:06

==================================================

测试3: 调用不同内容(预期:缓存未命中)

==================================================

❌ 缓存未命中,调用大模型

大模型响应:今天天气怎么样 - 2026-03-09 22:18:07

==================================================

测试4: 清空缓存后再次调用(预期:缓存未命中)

==================================================

❌ 缓存未命中,调用大模型

大模型响应:你好 - 2026-03-09 22:18:07

五、缓存装饰器执行流程

我们以上示例中的generate_text_with_cache("你好")调用过程为例,详细解析每一步执行过程:

112.8-缓存装饰器执行流程 deepseek_mermaid_20260309_6004f5.png

步骤 1:装饰器初始化

@cache_llm_response(ttl=10, max_size=5)
def generate_text_with_cache(prompt: str) -> str:
    return generate_text(prompt)

image.gif

  • 执行cache_llm_response(ttl=10, max_size=5),创建LLMResponseCache实例
  • 返回decorator函数,装饰generate_text_with_cache
  • generate_text_with_cache被替换为wrapper函数

步骤 2:第一次调用(缓存未命中)

  • 1. 调用generate_text_with_cache("你好"),实际执行wrapper("你好")
  • 2. wrapper调用cache.get(("你好",), {})生成缓存键:
  • args_str = "你好"
  • kwargs_str = ""
  • raw_key = "你好 ||"
  • MD5 哈希后得到固定长度的键,如:5eb63bbbe01eeed093cb22bb8f5acdc3
  • 3. 检查缓存中无此键,返回None
  • 4. 执行原函数generate_text("你好"),模拟耗时 0.5 秒后返回结果
  • 5. 调用cache.set(("你好",), {}, 结果):
  • 清理过期缓存(此时为空)
  • 检查缓存容量(未满)
  • 存储缓存项:{键: (时间戳, 结果)}
  • 记录访问时间:{键: 当前时间}
  • 6. 返回大模型响应结果

步骤 3:第二次调用(缓存命中)

  • 1. 再次调用generate_text_with_cache("你好")
  • 2. 生成相同的缓存键
  • 3. 检查缓存存在且未过期
  • 4. 更新访问时间,用于 LRU
  • 5. 直接返回缓存结果,无耗时

步骤 4:缓存过期后调用

  • 1. 等待 10 秒后调用generate_text_with_cache("你好")
  • 2. 生成相同的缓存键
  • 3. 检查缓存存在但已过期
  • 4. 删除过期缓存项
  • 5. 重新执行原函数并更新缓存

核心原理总结:

  • 闭包原理:装饰器通过闭包保存缓存实例,使其生命周期与被装饰函数一致
  • 哈希算法:将可变长度的 prompt 转换为固定长度的哈希值,提高缓存效率
  • 锁机制:保证多线程环境下缓存操作的原子性
  • TTL 机制:通过时间戳对比实现缓存自动过期
  • LRU 算法:基于访问时间的缓存淘汰策略,防止内存溢出

六、大模型缓存最佳实践

1. TTL 设置策略

  • 时效性内容(如新闻、天气):TTL 设置为 5-10 分钟
  • 通用知识内容(如常识、教程):TTL 设置为 1-24 小时
  • 静态内容(如固定模板):TTL 设置为 7 天或更长

2. 缓存键优化

  • 对超长 prompt 进行截断或哈希,避免键过长
  • 忽略无意义的参数,如请求 ID、trace ID
  • 对相似 prompt 进行归一化,如去除空格、大小写统一

3. 缓存失效策略

  • 主动失效:当大模型知识更新时,主动清空相关缓存
  • 被动失效:设置合理的 TTL,让缓存自然过期
  • 增量更新:只更新变化的缓存项,避免全量清空

七、总结

       今天结合缓存装饰器原理讲解大模型应用开发里的缓存技术,主要目的是为了解决大模型响应慢、调用贵这两个老大难问题。首先得明确,缓存的核心逻辑很简单,就是用空间换时间,把用户常问的、重复的请求结果存起来,下次再有人问一样的问题,直接从缓存里拿,不用再重新调用大模型,既省时间又省 Token 成本。

       基于Python 装饰器的基本原理,这是实现缓存的基础,然后从简单的无过期缓存,升级到带 TTL生存时间的缓存,解决了大模型回答时效性的问题,总的来说,缓存就是大模型应用落地的必备优化手段,操作不复杂,但能解决大问题,不管是单机还是分布式部署,都能用得上。

附录:完整代码落地实践

"""
大模型缓存装饰器 - 生产级实现
包含:TTL过期、线程安全、LRU淘汰、异常处理、哈希键生成
"""
import functools
import time
import hashlib
import threading
from typing import Any, Callable, Optional
class LLMResponseCache:
    """大模型响应缓存核心类"""
    
    def __init__(self, default_ttl: int = 3600, max_size: int = 1000):
        self._cache = {}
        self._access_times = {}
        self._default_ttl = default_ttl
        self._max_size = max_size
        self._lock = threading.Lock()
    
    def _generate_key(self, args: tuple, kwargs: dict) -> str:
        """生成稳定的哈希缓存键"""
        args_str = "|".join(str(arg) for arg in args)
        kwargs_str = "|".join(f"{k}={v}" for k, v in sorted(kwargs.items()))
        raw_key = f"{args_str}||{kwargs_str}"
        return hashlib.md5(raw_key.encode('utf-8')).hexdigest()
    
    def _clean_expired(self) -> None:
        """清理过期缓存(需要在已获取锁的情况下调用)"""
        current_time = time.time()
        expired_keys = []
        for key in self._cache:
            if current_time - self._cache[key][0] > self._default_ttl:
                expired_keys.append(key)
        for key in expired_keys:
            del self._cache[key]
            if key in self._access_times:
                del self._access_times[key]
    def _evict_lru(self) -> None:
        """LRU淘汰策略(需要在已获取锁的情况下调用)"""
        if len(self._cache) <= self._max_size:
            return
        if self._access_times:
            oldest_key = min(self._access_times.items(), key=lambda x: x[1])[0]
            del self._cache[oldest_key]
            del self._access_times[oldest_key]
    
    def get(self, args: tuple, kwargs: dict) -> Optional[Any]:
        """获取缓存值"""
        key = self._generate_key(args, kwargs)
        current_time = time.time()
        
        with self._lock:
            if key not in self._cache:
                return None
            
            timestamp, result = self._cache[key]
            if current_time - timestamp > self._default_ttl:
                del self._cache[key]
                if key in self._access_times:
                    del self._access_times[key]
                return None
            
            self._access_times[key] = current_time
            return result
    
    def set(self, args: tuple, kwargs: dict, result: Any) -> None:
        """设置缓存值"""
        key = self._generate_key(args, kwargs)
        current_time = time.time()
        
        with self._lock:
            self._clean_expired()
            self._evict_lru()
            self._cache[key] = (current_time, result)
            self._access_times[key] = current_time
    
    def clear(self) -> None:
        """清空缓存"""
        with self._lock:
            self._cache.clear()
            self._access_times.clear()
    
    def stats(self) -> dict:
        """获取缓存统计信息"""
        with self._lock:
            return {
                "total_items": len(self._cache),
                "max_size": self._max_size,
                "default_ttl": self._default_ttl,
                "cache_hit_rate": self._calculate_hit_rate()
            }
    
    def _calculate_hit_rate(self) -> float:
        """计算缓存命中率(简单实现)"""
        # 实际应用中需记录命中/未命中次数
        return 0.0
def cache_llm_response(ttl: int = 3600, max_size: int = 1000):
    """大模型缓存装饰器
    
    Args:
        ttl: 缓存有效期(秒)
        max_size: 缓存最大容量
    """
    cache = LLMResponseCache(default_ttl=ttl, max_size=max_size)
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 尝试获取缓存
            cached_result = cache.get(args, kwargs)
            if cached_result is not None:
                return cached_result
            
            # 执行原函数
            try:
                result = func(*args, **kwargs)
            except Exception as e:
                raise e  # 不缓存异常
            
            # 存入缓存
            cache.set(args, kwargs, result)
            return result
        
        # 暴露缓存操作方法
        wrapper.clear_cache = cache.clear
        wrapper.cache_stats = cache.stats
        return wrapper
    
    return decorator
# ===================== 测试与使用示例 =====================
from datetime import datetime
if __name__ == "__main__":
    # 模拟大模型函数
    def generate_text(prompt: str) -> str:
        """模拟大模型文本生成"""
        time.sleep(0.5)  # 模拟处理耗时
        now = datetime.now()
        return f"Response to: {prompt} (generated at {now.strftime('%Y-%m-%d %H:%M:%S')})"
    # 使用缓存装饰器
    @cache_llm_response(ttl=10, max_size=5)
    def generate_text_with_cache(prompt: str) -> str:
        return generate_text(prompt)
    # 测试流程
    print("=== 第一次调用(未命中) ===")
    start_time = time.time()
    print("执行函数:generate_text_with_cache('你好')")
    print(generate_text_with_cache("你好"))
    print(f"耗时:{time.time() - start_time:.2f}秒")
    print("\n=== 第二次调用(命中) ===")
    start_time = time.time()
    print("执行函数:generate_text_with_cache('你好')")
    print(generate_text_with_cache("你好"))
    print(f"耗时:{time.time() - start_time:.2f}秒")
    print("\n=== 缓存统计信息 ===")
    print("执行函数:generate_text_with_cache.cache_stats()")
    print(generate_text_with_cache.cache_stats())
    print("\n=== 清空缓存后调用(未命中) ===")
    print("执行函数:generate_text_with_cache.clear_cache()")
    generate_text_with_cache.clear_cache()
    start_time = time.time()
    print("执行函数:generate_text_with_cache('你好')")
    print(generate_text_with_cache("你好"))
    print(f"耗时:{time.time() - start_time:.2f}秒")

image.gif

输出参考:

=== 第一次调用(未命中) ===

执行函数:generate_text_with_cache('你好')

Response to: 你好 (generated at 2026-03-09 23:11:38)

耗时:0.53秒

=== 第二次调用(命中) ===

执行函数:generate_text_with_cache('你好')

Response to: 你好 (generated at 2026-03-09 23:11:38)

耗时:0.00秒

=== 缓存统计信息 ===

执行函数:generate_text_with_cache.cache_stats()

{'total_items': 1, 'max_size': 5, 'default_ttl': 10, 'cache_hit_rate': 0.0}

=== 清空缓存后调用(未命中) ===

执行函数:generate_text_with_cache.clear_cache()

执行函数:generate_text_with_cache('你好')

Response to: 你好 (generated at 2026-03-09 23:11:39)

耗时:0.50秒

相关文章
|
3月前
|
存储 缓存 人工智能
大模型应用:大模型数据缓存复用方案:从API请求数据累积到智能融合.50
本文提出一种低成本、高性能的大模型应用优化方案:基于SentenceTransformer本地生成文本向量,实现语义级缓存匹配;结合通义千问大模型智能融合历史与新答案;内置缓存淘汰与异常处理机制。实测缓存命中率超50%,响应提速10倍以上,显著降本增效。
397 4
|
5天前
|
机器学习/深度学习 数据采集 人工智能
田间杂草检测数据集分享(适用于YOLO系列深度学习分类检测任务)
本数据集含4000张真实农田图像(小麦/玉米/水稻田),YOLO格式标注杂草目标,覆盖多天气、光照与视角,适用于YOLO系列等目标检测模型训练,助力智能除草与精准农业研究。(239字)
169 16
|
6天前
|
数据采集 人工智能 监控
医疗AI智能体:整体效能评估可视化:从原理到实践的10大核心量化指标体系.130
本文系统阐述医疗AI智能体的量化评估体系,强调其行业特殊性——关乎生命健康、强合规要求、用户多元、闭环严苛。提出覆盖技术(幻觉率、准确率、响应时间、召回率)与业务(满意度、审核通过率、问诊完成率、交互时长)的8大核心指标,配套数据采集、计算、监控、迭代闭环流程及可落地代码实现,为临床合规落地提供客观依据。
143 9
|
5天前
|
数据采集 存储 算法
视频 RAG 中分块策略:基于停顿、滑动窗口与基于 LLM 的方法
本文探讨视频RAG中的核心挑战——如何为无时间结构的视频转录文本设计有效分块策略。对比传统文本分块,提出基于停顿、重叠窗口、递归切分及LLM驱动的主题分块四层方案,实现细粒度检索与全局理解兼顾,提升视频内容检索准确性与上下文完整性。
114 13
视频 RAG 中分块策略:基于停顿、滑动窗口与基于 LLM 的方法
|
4天前
|
人工智能 缓存 弹性计算
阿里云服务器2核4G5M199元解析:独享型u1实例,性能、适用场景、购买和续费规则介绍
阿里云通用算力型u1实例(ecs.u1-c1m2.large)2核4G、5M带宽、80G ESSD Entry云盘,活动特惠价仅199元/年(官网价3498.36元),企业新老用户同享,续费同价至2027年3月31日,每人限购1台。该实例采用独享型架构,搭载Intel至强可扩展处理器,内网带宽1Gbit/s、收发包30万PPS、云盘IOPS 1万,性能稳定,适合企业官网、中小Web应用、轻量数据库及开发测试等场景。
|
2月前
|
数据采集 运维 监控
绝缘子位置检测数据集(2000张)|YOLOv8训练数据集 电力巡检 无人机检测 输电线路监测 智能运维
本数据集含2000张真实电力巡检图像,专为YOLOv8训练优化,聚焦绝缘子位置检测。覆盖山区、城市等多场景及晴/雾/逆光等复杂条件,采用单类别高精度YOLO格式标注,结构标准、即拿即用,助力无人机巡检、智能运维与输电线路安全监测。
219 11
|
26天前
|
JSON 前端开发 测试技术
Kimi-k2.6 流式回包乱序后,我这样接入 ​D​М‌X​Α‌РΙ
kimi-k2.6 不止于聊天,其核心价值在于“可执行交付”:统一支持代码生成、长时程任务、Agent协作、文档→技能复用及多格式输出,具备工程级组合能力。它契合企业对“单模型多工位”的刚需——在研发、内容中台等场景中,稳定闭环完成需求拆解、编码、文档整理等多步任务。真正落地需依托DMXAPI网关实现标准化API集成,解决Web路径的不确定性,让模型能力成为可度量、可审计、可持续的生产基础执行层。(239字)
|
2月前
|
弹性计算 数据可视化
阿里云服务器管理控制台(后台)在哪登录?统一阿里云后台链接入口整理,一键直达
阿里云服务器管理控制台是ECS与轻量应用服务器的统一可视化后台,支持重启、远程连接、重装系统等操作。主入口为控制台首页(home.console.aliyun.com),亦可直连ECS官网:https://t.aliyun.com/U/AZBUsA 或轻量官网:https://t.aliyun.com/U/dwftch
599 8
|
24天前
|
机器学习/深度学习 IDE 数据可视化
【2026最新】Spyder安装和使用保姆级教程(附安装包+图文步骤)
Spyder(Scientific Python Development Environment)是一款免费开源的Python IDE,专为数据科学、科学计算与机器学习设计。它融合代码编辑、调试、变量浏览与IPython交互式控制台、数据可视化等功能,界面类MATLAB,开箱即用NumPy、Pandas、Matplotlib等库,Anaconda用户可一键启用。(239字)
|
10天前
|
人工智能 缓存 自然语言处理
千问云智能体Agent模型:Qwen3.7-Max列国产模型第一,在编程、推理能力提升,费用限制5折中
Qwen3.7-Max是阿里云2026年发布的旗舰智能体大模型,专注长周期自主执行,在编程(SWE-bench Pro 60.6分)、推理、办公自动化等能力上行业领先。国产模型全球盲测第一,支持MCP集成与Vibe Coding。现限时5折,输入/输出均降50%,并赠100万Tokens免费额度。快速体验:https://t.aliyun.com/U/fPVHqY
399 4

热门文章

最新文章