Week2 day1 实现提示缓存(Prompt Caching)
环境前提:
- 安装依赖:
pip install litellm python-dotenv.env写入GOOGLE_API_KEY=你的key- 准备
hamlet.txt(哈姆雷特全文文本,你可以自行下载放到同目录)
python
运行
from dotenv import load_dotenv import os from litellm import completion # 加载环境变量 load_dotenv(override=True) os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY") # 读取长文本哈姆雷特 with open("hamlet.txt", "r", encoding="utf-8") as f: hamlet = f.read() # 定位一小段文本用于验证 loc = hamlet.find("Speak, man") print("文本片段预览:") print(hamlet[loc:loc+100]) print("-" * 60) # ========== 第一次提问:不带长篇上下文 ========== question = [ { "role": "user", "content": "In Hamlet, when Laertes asks 'Where is my father?' what is the reply?" } ] response = completion( model="gemini/gemini-3.1-flash-lite", messages=question ) print("【第1轮|无长上下文】") print("回答:", response.choices[0].message.content) print(f"输入token: {response.usage.prompt_tokens}") print(f"输出token: {response.usage.completion_tokens}") print(f"总token: {response.usage.total_tokens}") cost = response._hidden_params.get("response_cost", 0) print(f"费用: {cost*100:.4f} 美分\n") # ========== 第二次提问:追加完整哈姆雷特文本(首次加载大上下文,构建缓存) ========== question[0]["content"] += "\n\nFor context, here is the entire text of Hamlet:\n\n" + hamlet response = completion( model="gemini/gemini-3.1-flash-lite", messages=question ) print("【第2轮|首次载入全文,缓存预热】") print("回答:", response.choices[0].message.content) print(f"输入token: {response.usage.prompt_tokens}") print(f"输出token: {response.usage.completion_tokens}") cached_tokens = response.usage.prompt_tokens_details.cached_tokens print(f"缓存命中token: {cached_tokens}") cost = response._hidden_params.get("response_cost", 0) print(f"费用: {cost*100:.4f} 美分\n") # ========== 第三次提问:完全相同prompt,触发缓存复用 ========== response = completion( model="gemini/gemini-3.1-flash-lite", messages=question ) print("【第3轮|完全相同prompt,复用缓存】") print("回答:", response.choices[0].message.content) print(f"输入token: {response.usage.prompt_tokens}") print(f"输出token: {response.usage.completion_tokens}") cached_tokens = response.usage.prompt_tokens_details.cached_tokens print(f"缓存命中token: {cached_tokens}") cost = response._hidden_params.get("response_cost", 0) print(f"费用: {cost*100:.4f} 美分")
运行现象说明
- 第 1 轮:只有简短问题,没有超长原文,无缓存;
- 第 2 轮:带上几万字哈姆雷特全文 → 缓存预热;
- 第 3 轮:一模一样的消息数组 →
cached_tokens > 0,大量文本走缓存,价格更低。
拓展:OpenAI 提示缓存使用要点(代码示范片段)
OpenAI 要求:静态内容放在prompt 前缀,只有前缀完全一致才能触发缓存
python
运行
from openai import OpenAI client = OpenAI() # 静态长文本放在最前面(固定前缀,用于缓存) static_context = """【大量固定知识库、指令、参考文档……】""" dynamic_query = "用户实时问题,放在最后" messages = [ {"role": "user", "content": static_context + "\n" + dynamic_query} ] resp = client.chat.completions.create( model="gpt-4o", messages=messages )
拓展:Claude 提示缓存(需要显式标记缓存区块)
Claude 和 Gemini/OpenAI 不一样,必须手动标记哪一段开启缓存,不能自动隐式缓存:
python
运行
from anthropic import Anthropic client = Anthropic() message = client.messages.create( model="claude-3-5-sonnet-20240620", max_tokens=1024, messages=[ { "role": "user", "content": [ { "type": "text", "text": "大量固定参考文本...", "cache_control": {"type": "ephemeral"} # 显式开启缓存 }, {"type": "text", "text": "你的问题"} ] } ] )
重要实操提醒
- 缓存不是永久的,各家都有生存时间限制;
- 只要前缀文本改动一个字符,缓存失效;
- 适用场景:RAG、长知识库、固定系统提示 + 动态用户问题;
- 示例使用 Gemini + LiteLLM,是最简演示方案。

浙公网安备 33010602011771号