趋近智
虽然缓存是提升性能和降低成本的有效手段,但也带来了一个新问题:数据陈旧。提供过时信息的缓存可能导致应用程序行为不正确,这往往比完全没有缓存更糟糕。缓存失效是指当底层数据发生变化时,从缓存中移除或更新条目的过程,以确保你的应用程序数据准确且及时。
选择合适的失效策略取决于你的数据如何随时间变化。我们将介绍几种常见且有效的策略供你使用。
最简单的失效策略是存活时间 (TTL)。使用 TTL,你可以为每个缓存条目设置一个过期时间。一旦时间过期,该条目就会被视为无效,并在下次访问时自动或在周期性清理过程中从缓存中移除。
此策略非常适合在可预测时间段后会变旧的数据。例如,天气预报、股票价格或新闻头条都是基于 TTL 缓存的不错选择。如果你正在构建一个报告当前天气的应用程序,你可能会将结果缓存 15 分钟。
在向缓存添加条目时,你可以使用 set 方法中的 ttl 参数来设置存活时间。时间以秒为单位。
from kerb.cache import create_memory_cache, generate_prompt_key
# 为时间敏感数据创建缓存
weather_cache = create_memory_cache()
prompt = "What is the current stock price for AAPL?"
key = generate_prompt_key(prompt, model="gpt-4")
# 模拟 API 调用以获取股票价格
response = {"stock": "AAPL", "price": 180.25, "timestamp": "2024-10-26T10:00:00Z"}
# 将响应缓存,设置 5 分钟 (300 秒) 的 TTL
weather_cache.set(key, response, ttl=300)
print(f"已缓存 '{prompt}' 的股票价格,并设置 5 分钟 TTL。")
300 秒后,对此键的 get 调用将返回 None,从而触发一次新的 API 调用以获取最新的股票价格。
对于变化时间无法预测的数据,手动失效是必需的。这种方法让你能够明确控制何时移除缓存条目。它适用于由用户操作或外部事件更新的内容,例如编辑知识库中的文档、更改产品描述或更新用户档案。
当底层数据变化时,你的应用程序逻辑应显式删除缓存中对应的条目。你可以使用 delete 方法来完成此操作。
from kerb.cache import create_memory_cache, generate_prompt_key
# 产品描述缓存
product_cache = create_memory_cache()
# 总结产品的提示
product_id = "prod_123"
product_description = "A durable, high-performance laptop for professionals."
prompt = f"Summarize this product: {product_description}"
key = generate_prompt_key(prompt, model="gpt-4", product_id=product_id)
# 缓存初始摘要
summary = "A powerful and reliable laptop for professional use."
product_cache.set(key, summary)
print(f"已缓存 {product_id} 的初始摘要。")
# 之后,产品描述被更新...
updated_description = "An ultra-light, high-performance laptop for creative professionals."
# 你的应用程序现在应该使旧的缓存条目失效。
# 我们生成之前使用的相同键来删除它。
was_deleted = product_cache.delete(key)
if was_deleted:
print(f"{product_id} 的缓存因更新而失效。")
else:
print(f"未找到 {product_id} 的缓存条目。")
# 下次请求摘要时,将出现缓存未命中,
# 强制根据更新后的描述生成新摘要。
这种事件驱动的方法确保你的缓存始终与你的数据源(例如数据库或内容管理系统)保持同步。
处理失效的一种整洁方法是将版本标识符整合到你的缓存键中。当你的提示、模型或底层逻辑发生变化时,你只需递增版本号。这会自动创建新的缓存键,从而有效地使所有旧条目失效,而无需删除它们。旧的、未被引用的条目最终将被缓存的替换策略(如 LRU)清除。
此策略对于管理提示更新或应用程序配置变更非常有效。它避免了复杂的删除逻辑,并提供清晰的变更历史记录。
generate_prompt_key 函数旨在处理任意关键字参数,从而轻松添加版本。
from kerb.cache import generate_prompt_key
prompt = "Analyze customer sentiment"
model = "gpt-4o-mini"
# 生成我们提示逻辑的 1.0 版本
key_v1 = generate_prompt_key(prompt, model=model, version="1.0")
print(f"对于 v1.0: {key_v1[:24]}...")
# 改进提示后,我们将版本更新到 1.1
key_v2 = generate_prompt_key(prompt, model=model, version="1.1")
print(f"对于 v1.1: {key_v2[:24]}...")
print(f"\n键不同: {key_v1 != key_v2}")
因为 key_v1 和 key_v2 不同,版本更新后的请求将导致缓存未命中,从而强制使用更新后的逻辑进行新的 LLM 调用。旧的 v1.0 缓存响应会保留,但将不再被访问。
有时你需要一次性使一整组相关条目失效。例如,如果你更新 RAG 系统中的整个文档,你会想要清除所有与该文档相关的缓存块和嵌入。手动删除每个条目将效率低下。
LLMCache 类提供了 invalidate_by_prefix 方法,它会移除所有键以特定字符串开头的条目。这要求在命名时采用规范的方法,即为相关项包含一个共同的前缀。
from kerb.cache import create_llm_cache, create_memory_cache
# 我们使用 LLMCache,因为它具有高级失效功能
llm_cache = create_llm_cache(backend=create_memory_cache())
# 为文档的不同块缓存嵌入
document_id = "doc_abc"
chunks = ["First part of the text.", "Second part of the text."]
models = ["text-embedding-3-small", "text-embedding-3-large"]
# 创建带有共同前缀的键:doc_abc:embedding:
for i, chunk in enumerate(chunks):
for model in models:
# 一个简单的键策略,用于演示
key = f"{document_id}:embedding:{model}:{i}"
llm_cache.cache_embedding(text=chunk, embedding=[0.1, 0.2], model=model) # 模拟嵌入
print(f"已缓存键为 '{key}' 的条目")
# 之后,文档 'doc_abc' 被更新。我们需要使其所有嵌入失效。
prefix_to_invalidate = f"{document_id}:embedding:"
invalidated_count = llm_cache.invalidate_by_prefix(prefix_to_invalidate)
print(f"\n文档 '{document_id}' 已更新。正在使所有相关嵌入失效...")
print(f"已使 {invalidated_count} 个带有前缀 '{prefix_to_invalidate}' 的条目失效。")
这种模式在处理结构化、互联数据的系统中,对于管理缓存一致性非常高效。
选择正确的策略在于理解你的数据生命周期。以下是一些指南:
实际上,应用程序通常会结合使用这些策略,以有效地处理不同类型的缓存数据。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造