3.4 System Prompt的缓存友好改造


文档摘要

3.4 System Prompt的缓存友好改造 本节摘要:平台缓存只认"从开头连续相同的前缀"。所以提示词怎么摆,直接决定折扣吃不吃得到。核心纪律只有一句:稳定的内容放头部,易变的内容放尾部,大块参考资料紧贴系统设定。本节给出改前改后两份 messages 数组,逐项标注命中与破坏,并用一个完整案例演示改造前后的账单落差。 头稳尾变:提示词的空间秩序 3.3 节说清了失效的三种根源,其中"前缀变化"最该由写提示词的人负责——而它几乎总是结构问题,不是内容问题。平台做前缀匹配,从第一个 token 往后比对,一旦某处不同,后面再相同也接不回缓存。这意味着:你的提示词里只要有一丁点"每次请求都变"的东西出现在稳定内容之前,前面所有缓存就白费。 由此推出空间秩序的三条纪律。

3.4 System Prompt的缓存友好改造

本节摘要:平台缓存只认"从开头连续相同的前缀"。所以提示词怎么摆,直接决定折扣吃不吃得到。核心纪律只有一句:稳定的内容放头部,易变的内容放尾部,大块参考资料紧贴系统设定。本节给出改前改后两份 messages 数组,逐项标注命中与破坏,并用一个完整案例演示改造前后的账单落差。

头稳尾变:提示词的空间秩序

3.3 节说清了失效的三种根源,其中"前缀变化"最该由写提示词的人负责——而它几乎总是结构问题,不是内容问题。平台做前缀匹配,从第一个 token 往后比对,一旦某处不同,后面再相同也接不回缓存。这意味着:你的提示词里只要有一丁点"每次请求都变"的东西出现在稳定内容之前,前面所有缓存就白费。

由此推出空间秩序的三条纪律。第一,稳定内容放头部:系统设定、角色定义、长篇规则,这些写完就不改的,必须排在最前面。第二,易变内容放尾部:时间戳、用户身份、当次会话变量、用户具体问题,这些每次不同,放到数组末尾,不污染前缀。第三,大块参考资料紧随系统设定之后:参考资料也是稳定的,紧贴头部能一起进入命中区间,别被易变内容隔开。

改前:一份让缓存失效的 messages

下面这份数组在真实项目里很常见,但它几乎吃不到任何折扣。注意时间戳和用户档案被塞进了头部。

[ { "role": "system", "content": "当前服务器时间:2024-06-01 09:13:22。你是电商客服助手。我们的退货政策为:签收后七日内无理由退货……(约八千字规则正文)" }, { "role": "system", "content": "当前用户档案:id=88231,会员等级=金牌,所在城市=杭州。" }, { "role": "user", "content": "我上周买的鞋子什么时候发货?" } ]

逐项标注:

  • 第一段 system 的 "当前服务器时间" 在头部且每次变 —— 这一项直接破坏整段前缀缓存,后面八千字规则再稳定也无用。
  • 第二段 system 的 用户档案每次请求不同 —— 即便头部时间戳修掉了,它仍会切断前缀,使规则正文无法进入命中区间。
  • 第三段 user 是当次问题,本就该放尾部,位置没问题,但被前面的易变内容连累。

结论:这份数组在 Anthropic 的显式断点下,如果不打点,自动对齐后命中率也极低;在 OpenAI 自动模式下,前缀从时间戳起就变,缓存基本不命中。

改后:把稳定前缀堆到头部

同样的信息,换个摆法,折扣立刻生效。

[ { "role": "system", "content": "你是电商客服助手。我们的退货政策为:签收后七日内无理由退货……(约八千字规则正文,完全稳定,不含任何动态字段)" }, { "role": "system", "content": "客服知识库参考文档:……(约三千字产品手册,稳定,紧贴系统设定)" }, { "role": "user", "content": "用户档案 id=88231 金牌杭州。我上周买的鞋子什么时候发货?" } ]

逐项标注:

  • 第一段 system 纯稳定规则正文,从开头连续相同 —— 进入命中区间,按读价结算。
  • 第二段 system 稳定知识库,紧跟头部 —— 与第一段落一起构成可复用前缀,命中。
  • 第三段 user 动态信息并入尾部问题 —— 易变内容只在末尾,不破坏前面任何缓存;它本身不在前缀里,每次全价但量小。

在 Anthropic 上,你可以对第二段末尾打一个 cache_control 断点,把"规则 + 知识库"锁成一段长期缓存;在 OpenAI 上,只要这份前缀跨过 1024 token 对齐且稳定,自动命中。无论哪家,命中范围都从开头覆盖到知识库结尾。

图 3-4:改前改后的消息布局与命中范围对比

图 3-4:改前改后的消息布局与命中范围对比

常见破坏缓存的写法清单

把坑汇总成一份清单,写提示词时逐条自查:

  • 时间戳嵌入系统提示:把"当前时间"写进 system 头部,每次请求都变,前缀从第一句就废。时间若必须告知模型,放到 user 消息尾部。
  • 用户信息插在中间:把用户 id、会员等级、地理位置塞进 system 中段,等于在稳定规则里凿了个洞,洞之前命中、洞之后全废。用户相关字段应随问题一起放末尾。
  • 动态工具列表排前面:tools 定义参与缓存键,若把"按用户动态生成的工具集"放在请求前部,每次工具集不同就重算。工具集应尽量固定,确需动态时放在稳定前缀之后。
  • 版本号/环境字符串写进前缀:"env=prod build=20240601"这类字段若进头部,每次发布即失效。版本信息可放进尾部或干脆不入请求。
  • 在参考文档里拼请求序号:给文档加"第 N 次请求"标记,看似无害,实则让整段文档失活。

改造的成本与收益小测算

改造不是零成本:你要动 messages 的组装逻辑、把动态字段从头部搬尾部、可能重写一部分中间件。但收益用 3.2 的模型可估。仍用教学价目(常规 1.0、读价 0.1、写价 1.25,元/百万 token),系统前缀 8000 token、每次新增 500 token、100 万次请求:

  • 改前命中率约 30%(时间戳与用户档案破坏):有效单价 ≈ 0.941×0.3×0.1 + 0.941×0.7×1.25 + 0.059 ≈ 0.028 + 0.824 + 0.059 = 0.911;百万次成本 ≈ 8500×0.911 = 7744。
  • 改后命中率约 95%:有效单价 ≈ 0.941×0.95×0.1 + 0.941×0.05×1.25 + 0.059 ≈ 0.089 + 0.059 + 0.059 = 0.207;成本 ≈ 8500×0.207 = 1760。
  • 节省 ≈ 7744 − 1760 = 5984 计价单位,相当于把账单砍掉约七成。

一次性的代码改造,换每百万请求省下近七成前缀成本,对高频业务是稳赚。低频业务改造收益小,但结构正确的提示词几乎不增加维护负担,所以我倾向默认就这么写。

完整案例:客服机器人的前缀整理

下面用"背景→操作→结果→解读→变式"把这个改造讲成一段完整过程。

背景:某电商客服机器人,每次请求在 system 头部拼"当前时间 + 用户档案 + 八千字规则",实测缓存命中率仅两成多,月度前缀账单偏高。问题不在模型,在摆法。

操作:把头部的时间戳、用户档案移除,规则正文与产品知识库原样保留并紧邻;时间戳与用户档案并入 user 消息尾部,作为"问题 + 上下文"一并发出。Anthropic 用户在知识库段末打一个 cache_control 断点;OpenAI 用户靠 1024 对齐自动命中。

结果:改造后一周观测,前缀命中率从两成升到九成五,按上面模型估算每百万请求省下约六千计价单位,首字延迟也因少重写而下降。

解读:省下的不是"开了某个开关",而是"把易变内容请出前缀"。命中率从 0.22 到 0.95 的跃迁,全部来自结构挪动,模型、价目、平台都没变。这印证了 3.2 节的判断——有效单价由前缀稳定度决定。

变式:若业务需要按用户个性化系统提示(如不同会员看到不同话术),则不能把用户字段简单丢尾部,因为那样会让每段前缀都不同、等于无缓存。此时改用 3.5 节的思路:把"公共规则"做稳定前缀命中折扣,把"个性化话术"放进尾部;或当用户分层有限时,为每类会员各维护一份稳定前缀,用请求路由命中对应那一份。

关键直觉:缓存友好不是给提示词加功能,而是把"会变的东西"挪到它该在的末尾。你不写更多,只是摆得更对。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U