展开本页目录
开始前准备什么
- 当前渠道与模型的缓存能力、字段及计费说明
- 一份允许发送的固定参考文本 prefix.txt
- 三次小规模调用预算,关闭自动重试
- 固定共享前缀
- 记录三次请求
- 核对字段与扣费
- 决定是否继续
稳定前缀哈希、null 缺失字段、原始 usage 与延迟;不声称已命中。
复用的是共享前缀,不是保存答案
提示词缓存复用模型处理过的相同前缀。之后的问题仍需生成新答案;它与在自己数据库里返回上次答案不同,也不保证同样的输入输出完全相同。
有效前缀会受到模型、工具描述、Schema 与消息顺序等影响。把当前时间、随机追踪 ID 或每次改变的用户信息放在最前面,可能破坏原本可共享的部分。
规则与资料固定,问题留到最后
| 位置 | 建议放什么 | 避免的变化 |
|---|---|---|
| 前段 | 稳定的应用规则和授权参考资料 | 时间戳、随机 ID、每次重排的文本 |
| 中段 | 固定工具定义与输出 Schema | 工具顺序和描述随请求变动 |
| 末段 | 本次用户问题、当前状态 | 不必要的整份历史重写 |
- 位置
- 前段
- 建议放什么
- 稳定的应用规则和授权参考资料
- 避免的变化
- 时间戳、随机 ID、每次重排的文本
- 位置
- 中段
- 建议放什么
- 固定工具定义与输出 Schema
- 避免的变化
- 工具顺序和描述随请求变动
- 位置
- 末段
- 建议放什么
- 本次用户问题、当前状态
- 避免的变化
- 不必要的整份历史重写
完整观察脚本,不预先假定命中
将自己的稳定资料写入 prefix.txt,再运行脚本。它发三次 Chat 请求,记录前缀 SHA-256、模型、耗时、终态以及原始 usage。字段未返回时保存 null,不能把缺失写成缓存未命中或 0。
developer-prompt-cache.py
import hashlib
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from uuid import uuid4
from openai import OpenAI
def main():
prefix = Path("prefix.txt").read_text(encoding="utf-8")
if not prefix.strip():
raise ValueError("prefix.txt must contain your unchanged instructions/reference text")
prefix_hash = hashlib.sha256(prefix.encode()).hexdigest()
client = OpenAI(api_key=os.environ["tokenba_API_KEY"],
base_url="https://api.apizt.com/v1", timeout=60, max_retries=0)
records = []
output = Path("cache-observations-" + uuid4().hex + ".json")
def save():
temporary = output.with_suffix(".tmp")
temporary.write_text(json.dumps(records, ensure_ascii=False, indent=2), encoding="utf-8")
temporary.replace(output)
print("records:", output)
for index, question in enumerate(["总结三条核心规则。", "针对第一条规则给一个例子。", "总结三条核心规则。"], 1):
started = time.perf_counter()
record = {"attempt": index, "model": os.environ["tokenba_MODEL"],
"prefix_sha256": prefix_hash, "status": "unknown",
"started_at": datetime.now(timezone.utc).isoformat(), "usage": None}
records.append(record)
save()
try:
result = client.chat.completions.create(
model=os.environ["tokenba_MODEL"],
messages=[{"role": "system", "content": prefix}, {"role": "user", "content": question}])
except Exception as error:
record.update(error_type=type(error).__name__, elapsed_seconds=round(time.perf_counter() - started, 3))
save()
raise RuntimeError("Request outcome unknown; inspect records and console before resubmitting") from None
usage = result.usage.model_dump() if result.usage else None
details = (usage or {}).get("prompt_tokens_details") or {}
choice = result.choices[0] if result.choices else None
valid = choice is not None and choice.finish_reason == "stop" and bool(choice.message.content)
record.update(status="accepted" if valid else "invalid", request_id=getattr(result, "_request_id", None),
elapsed_seconds=round(time.perf_counter() - started, 3),
finish_reason=choice.finish_reason if choice else None,
cached_tokens=details.get("cached_tokens"),
cache_write_tokens=details.get("cache_write_tokens"), usage=usage)
save()
if not valid:
raise RuntimeError("Empty or incomplete output; inspect saved usage before another request")
print(json.dumps(records, indent=2))
if __name__ == "__main__":
main()
运行前先安排可控预算
资料长度应来自真实业务;不要为追求命中盲目复制大段文本。每次运行创建独立 cache-observations-<id>.json,逐次原子保存,异常保留 unknown 后停止;不覆盖旧记录。文件不含 Key 或资料全文。最多三次付费请求,已成功或结果未知的尝试都要纳入对账。
bash
python -m pip install -U openai
export tokenba_MODEL="REPLACE_WITH_SUPPORTED_MODEL_ID"
# tokenba_API_KEY 通过你的终端或部署环境设置
python developer-prompt-cache.pyusage 与费用是两份证据
cached_tokens 表示服务端报告的缓存读取量;部分接口还报告 cache_write_tokens。不同厂商和兼容接口可能使用不同字段。先读原始 usage,再根据该渠道定义映射,避免把所有厂商统一套进一个固定公式。
命中字段、输入费率、缓存读取费率和写入费率要一起看。即使官方提供缓存折扣,apizt 当前渠道是否映射该优惠,仍以价格说明与控制台扣费为准。不要承诺固定节省比例。
未命中时按顺序排查
- 比较 prefix_sha256 和消息顺序,检查工具及 Schema 是否改变。
- 确认三次调用是否为同一模型和预期渠道;路由切换可能改变缓存可用性。
- 查看模型当前支持的缓存策略、保留范围和字段,旧教程的统一门槛可能已失效。
- 如果字段始终缺失,标记无法由响应验证,并查管理后台记录;延迟降低只能作为观察。
按一个完成任务计算收益
保留冷请求和后续请求的全部 usage、成功率、延迟及账单。缓存写入、输出增多或额外重试都可能抵消输入节省。选择方案时比较一次验收通过的任务总成本。
提示词缓存不替代数据处理审核,也不意味着资料永远保存或马上删除。敏感资料先脱敏,并核对实际网关及上游的保留规则。
怎样确认已经完成
- 前三段前缀稳定,变量问题仅在末尾
- 三次请求都有终态与原始 usage
- 缺失缓存字段显示未知,不当 0
- 扣费明细与响应 usage 分开对账
常见问题
重复请求更快,能证明缓存命中吗?
不能。网络、负载和路由也会改变延迟,需要服务端缓存字段或相应后台记录。
所有厂商都用一样的缓存门槛和折扣吗?
不同模型、接口与渠道可能不同。按当前官方文档及实际计费核对,不能统一套旧门槛。