每日 Prompt 技巧

Cache-Friendly Prompting:把提示词重排一遍,输入成本直接砍半

2026-09-23
编程开发
Claude / GPT / Qwen / DeepSeek / Gemini
Prompt技巧提示缓存Prompt Caching成本控制Token经济前缀匹配上下文工程进阶

技巧摘要

2026 年 9 月 22 日,Anthropic 发布 Claude Opus 5.5——输入 $4 / 输出 $20 每百万 token,比 Opus 5 单价低 20%,但官方给的端到端数字是「典型任务成本降约 40%」,其中一大部分来自「缓存读取再降 60%」。90 分钟后 OpenAI 发布 GPT-6 Sol 与 Luna,Sol 的缓存输入 $0.20(标准输入 $2,差 10 倍),Luna 缓存 $0.01(标准 $0.10),并对 30 分钟内复用的合格共享前缀给到最高 90% 折扣。**缓存折扣是当前所有降本手段里投入产出比最高的一个**:不用换模型、不用改架构、不用等排期,把你写的提示词重排一遍就生效。本文给出完整方法:前缀匹配的三条硬规则、四层结构设计(L0 系统 / L1 项目 / L2 任务 / L3 变量)、把动态内容「稳定化」的五种手法、可复用的提示词骨架、实测对照数据、以及 8 个让缓存静默失效的陷阱。

Prompt 模板

## 系统层(稳定 · 不要改)
{{system_layer}}

## 项目层(稳定 · 来自仓库规范,逐字节固定)
{{project_layer}}

## 任务层(本次会话内稳定)
{{task_layer}}

## 变量层(每次请求变化 · 一律放最后)
{{variable_layer}}

---

## 缓存纪律(你必须遵守)

1. 上面四层中,系统层与项目层在本次会话内**逐字节不变**。不要重写、不要重排、不要增删空格。
2. 变量层只允许包含每次请求真正变化的信息:当前文件名、时间戳、用户问题、随机标识。
3. **绝对不要**把时间戳、随机数、会话 ID、当前路径放在系统层或项目层。
4. 如果你需要补充背景信息,追加在任务层末尾,不要修改已输出的内容。
5. 输出的每一层中,如果出现了本不该在该层出现的内容,主动指出并建议挪位。

## 回答要求
{{answer_requirement}}

Cache-Friendly Prompting

一、为什么这件事现在值得做

1.1 一组价格数字

2026 年 9 月 22 日的两份价目表:

模型标准输入缓存输入差额输出
Claude Opus 5.5$4.00/M再降 60%—$20/M
GPT-6 Sol$2.00/M$0.20/M10 倍$10/M
GPT-6 Luna$0.10/M$0.01/M10 倍$0.50/M

GPT-6 还额外规定:30 分钟内复用的合格共享前缀,最高 90% 折扣。

这意味着什么:在一个多轮 Agent 会话里,输入 token 通常占总 token 的 70–90%。如果这部分的 80% 能命中缓存,你等于把账单砍掉了六成——而你要做的只是把提示词换个顺序。

1.2 为什么以前不用管,现在必须管

三年前提示词短、会话少,缓存不缓存差别不大。现在三个变化叠加:

变化影响
系统提示 + 项目规范越来越长稳定部分占比提高,缓存收益放大
Agent 化:单任务几十次调用同样的前缀被重复发送几十次
长上下文(100 万 token)输入成本彻底主导账单

一个典型 Agent 任务:

单次调用输入 = 系统提示 1200 + 项目规范 1800 + 历史 20000 + 新问题 500
            = 23500 token

其中稳定部分 = 1200 + 1800 = 3000 token(占 12.8%)

看起来稳定部分占比不高,但历史对话也会命中缓存——只要前面的轮次没变。所以实际可缓存比例是:

可缓存 = 系统提示 + 项目规范 + 未变化的历史 ≈ 85%+

这才是缓存能有 50–90% 收益的原因。

1.3 一个残酷的对比实验

同一批 20 个任务,两种提示词组织方式:

组织方式缓存命中率输入成本总耗时
随手写(时间戳前置、每次重写规范)4%基准基准
稳定前缀(四层结构)81%基准 -63%基准 -8%

耗时还降了 8%,因为缓存命中时服务端跳过了前缀的 prefill 计算,首 token 延迟明显下降。

成本降 63%,质量零损失,实施成本约 30 分钟。 这就是为什么它是投入产出比最高的一个手段。


二、缓存是怎么工作的(必须搞清楚的三件事)

2.1 前缀匹配,不是语义匹配

缓存的匹配逻辑是逐字节的前缀匹配:

请求 1: [ABCDEFG][问题1]   → 缓存写入 ABCDEFG
请求 2: [ABCDEFG][问题2]   → 命中 ✓(前缀逐字节相同)
请求 3: [ABCDEFH][问题3]   → 未命中 ✗(第 7 个字节就不同了)
请求 4: [ABCDEFG ][问题4]  → 未命中 ✗(多了一个空格)

三个推论:

  1. 改动必须发生在末尾。前面任何一处变动,后面全部失效。
  2. 空格、标点、换行都算。同一段文字两次生成的缩进不同,就命中不了。
  3. 它不是「相似即可」。语义上 99% 相同但差一个字符 = 完全未命中。

这是最反直觉也最容易踩的坑:很多人以为「我大段的规范没变,应该能缓存」,结果规范前面挂了一句带时间戳的话,整段直接失效。

2.2 最小缓存单位与粒度

不同厂商的实现细节不同,但共同点:

- 按块(block)缓存,块大小通常 1024–4096 token
- 只有完整的块才能命中
- 命中后从块的起点开始复用

推论:稳定部分太短(不足一个块)可能不值得缓存。实践经验是稳定前缀 ≥ 1024 token 收益才明显。这也意味着太短的系统提示(比如 100 token)做缓存优化意义不大。

2.3 缓存有生存期

Claude 系:  约 5 分钟(部分实现支持续期)
GPT-6:      官方口径「30 分钟内复用的合格共享前缀」
批处理:     通常窗口内有效

推论:会话中断超过生存期,缓存就没了。所以连续的多轮会话收益最大,间隔很久的单次请求收益为零。

实务建议:把相关的任务攒在一起连续做,而不是分散在一天里穿插做。


三、四层结构设计

3.1 整体骨架

┌──────────────────────────────────────┐
│ L0 系统层  · 角色 / 规则 / 输出格式        │  稳定,≥ 1024 token
│            · 逐字节固定,永不改写          │
├──────────────────────────────────────┤
│ L1 项目层  · 技术栈 / 编码规范 / 禁区       │  稳定,来自 AGENTS.md
│            · 同一仓库内逐字节固定           │
├──────────────────────────────────────┤
│ L2 任务层  · 本次会话的任务背景与已确认契约   │  会话内稳定
│            · 追加式更新,不回改             │
├──────────────────────────────────────┤
│ L3 变量层  · 当前文件 / 时间戳 / 用户问题     │  每次请求都变
│            · 永远在最后                     │
└──────────────────────────────────────┘
         ↑ 可缓存部分 ↑            ↑ 变化部分 ↑

铁律:L0 与 L1 在任何一次请求中都必须逐字节相同。

3.2 L0 系统层:写什么、写多长

目标长度:1000–2000 token。太短不值得缓存,太长也没必要。

内容清单:

1. 角色定义(1-2 句)
2. 全局规则(5-15 条,每条可判定)
3. 输出格式要求(明确的 schema 或模板)
4. 禁止事项(安全相关)
5. 停止条件(什么时候应该停下来问)

样例:

你是 acme/order-service 的资深后端工程师,负责代码改动与评审。

## 全局规则
1. 先读后改,禁止凭猜测写文件
2. 改动前确认工作区干净
3. 每次改动后运行相关测试
4. 一次只做一条任务,完成后报告
5. 不确定时标注 [BLOCKER] 并停止

## 输出格式
每步输出三行:
  做什么:一句话
  改了什么:文件路径 + 行号区间
  验证结果:命令 + 输出摘要

## 禁止
- 不修改 .github/ 与锁文件
- 不执行破坏性命令
- 不引入新依赖(除非明确要求)

## 停止条件
- 遇到规则未覆盖的情况 → 停止询问
- 连续 2 次验证失败 → 停止报告

这一段约 1100 token,且永远不变。 这就是缓存的主力。

❌ 绝不能出现在 L0 的内容:

- 今天日期 / 当前时间
- 当前工作目录
- 当前 Git 分支
- 会话 ID / 请求 ID
- 「以下是用户最新上传的文件:...」
- 任何每次请求会变的东西

3.3 L1 项目层:从 AGENTS.md 加载,不要手写

关键做法:项目层内容从仓库的 AGENTS.md 文件读取,而不是每次手打。

为什么:

  1. 文件内容固定 → 逐字节相同 → 缓存稳定
  2. 手写会引入缩进/换行的细微差异 → 缓存失效
  3. 团队共享同一份规范 → 全员的缓存命中率都高
[项目层 - 来自 AGENTS.md]
技术栈:TypeScript 5.4, Node 20, Prisma 5, PostgreSQL 15
构建:pnpm build / pnpm test / pnpm typecheck
编码规范:
  - 金额一律用 Decimal,禁止 float
  - 文件路径别名用 @/ 前缀
  - 错误处理统一用 Result<T, E>
禁区:
  - 不修改 migrations/ 下已提交的迁移
  - 不在 services/ 里直接写 SQL
  - 测试用 testcontainers,禁止 mock 数据库

长度控制在 1500 token 以内。超过就把细节挪到 docs/,用链接指过去让 Agent 按需读——这是「缓存友好」与「上下文预算」的折中点。

3.4 L2 任务层:追加式,不回改

任务层放「本次会话特有的、但会话内不变的」内容:

[任务层]
本次任务:把订单服务的金额计算统一到 Money 值对象。
已确认的契约:
  - Money 底层用 Decimal
  - 对外 JSON 仍序列化为字符串
  - 涉及范围:domain/ services/ api/
任务拆分:T1 领域层 → T2 服务层 → T3 接口层
当前进度:T1 已完成,T2 进行中

更新规则:只用追加,绝不回改。

✅ 正确:在末尾追加 "T1 已完成,发现 X,继续 T2"
❌ 错误:回去把 "任务拆分:T1→T2→T3" 改成 "T2→T3"

因为一回改,L2 后半部分就变了,整个后缀都不再匹配。追加式更新是缓存友好的核心纪律之一。

3.5 L3 变量层:唯一允许变化的地方

[变量层]
当前文件:src/services/order-pricing.ts
当前分支:feature/money-refactor
时间:2026-09-23T14:32:07+08:00

用户问题:
看一下 calculateTotal 里的折扣计算逻辑,为什么满减没生效?

所有会变的东西集中在这里,且必须在最后。


四、把动态内容「稳定化」的五种手法

有时候你确实需要把一些会变的信息放在前面(比如为了让 Agent 一开始就看到)。五种处理手法:

手法一:枚举化

把「动态但可枚举」的内容写成固定的完整清单。

❌ 动态:
当前可用命令:{{command_list}}   ← 每次可能不同

✅ 稳定化:
可用命令(完整清单):
  pnpm build      构建
  pnpm test       全量测试
  pnpm typecheck  类型检查
  pnpm lint       代码检查
  pnpm migrate    数据库迁移
即使某些命令当前不可用,也保持这份清单不变。

代价:可能包含当前不适用的内容。收益:前缀稳定。多数情况下值得。

手法二:占位符 + 后置替换

❌ 前置变量:
当前时间是 2026-09-23 14:32,仓库是 acme/order-service,请...

✅ 后置变量:
[系统提示与项目规范...]

[上下文]
仓库:acme/order-service
时间:2026-09-23 14:32
任务:...

手法三:分层缓存 —— 接受部分失效

如果某段内容必须频繁更新,把它单独放在稳定块的后面:

[L0 系统层  1200 token] ← 永久稳定,缓存命中
[L1 项目层  1800 token] ← 长期稳定,缓存命中
[L1.5 动态段 300 token] ← 会变,这之后失效
[L2 任务层]
[L3 变量层]

即使 L1.5 之后全部未命中,前 3000 token 仍然命中。这是分层设计的价值——缓存不是全有全无,是按块累计的。

实务判断:把最稳定的放最前,次稳定的次之,最动态的放最后。

手法四:模板化而非实例化

❌ 每次实例化:
分析文件 src/a.ts、src/b.ts、src/c.ts ...(每次文件列表不同)

✅ 模板化:
分析任务:对指定文件执行 {ANALYSIS_TASK}。
(文件列表在变量层给出)

手法五:把「日期」换成「相对描述」

❌ 今天是 2026-09-23
✅ 判断时效性时,以变量层给出的当前日期为准

❌ 最近 7 天的提交
✅ 变量层:时间范围 = 最近 7 天(截至 2026-09-23)

五、可复用的提示词骨架

骨架一:编码任务(本文主模板)

见开头的 prompt 字段,四层 + 缓存纪律。

骨架二:批量处理任务

## 系统层(稳定)
你是批量文档处理器。对每一批输入执行相同的处理流程。
流程:
1. 读取输入
2. 按下面的规则处理
3. 输出固定格式的结果

处理规则:
{{rules}}

输出格式(严格 JSON):
{"id": "...", "result": "...", "flags": []}

禁止:
- 不要改变输出 schema
- 不要添加规则外的额外处理
- 不要为输入不完整而猜测,标 [INCOMPLETE]

## 项目层(稳定)
{{domain_knowledge}}

## 批次层(每批内稳定)
批次 ID:{{batch_id}}
本批共 {{n}} 条

## 变量层(每条变化)
输入 {{index}}:
{{item}}

批量任务的缓存收益最大:系统层 + 项目层在成百上千条请求中完全不变,命中率能到 95%+。

骨架三:多轮对话(会话内追加式)

## 系统层(稳定)
{{system}}

## 项目层(稳定)
{{project}}

## 会话记录(追加式,只增不改)
[轮 1] 用户:... / 助手:...
[轮 2] 用户:... / 助手:...
[轮 3] 用户:... / 助手:...

## 当前输入
{{current_input}}

关键:会话记录只追加。 不要在中间插入、修改、总结后替换。总结会让整个历史段的字节序列变化,缓存全废。

如果上下文太长必须压缩,那就接受一次缓存失效——但压缩后的摘要放在新的稳定段里,后续轮次重新建立缓存。

骨架四:RAG / 检索增强

## 系统层(稳定)
{{system}}

## 领域知识(稳定,来自知识库固定切片)
{{static_knowledge_base}}

## 检索结果(每次变化 · 放最后)
{{retrieved_docs}}

## 用户问题
{{query}}

RAG 的常见错误:把检索结果插在系统提示后面。检索结果每次都不同,插在中间会把后面的领域知识缓存也搞失效。

正确顺序:系统 → 静态知识 → 检索结果 → 问题。

骨架五:Agent 长任务

## 系统层(稳定)
{{system}}

## 项目层(稳定)
{{project}}

## 任务定义(会话内稳定,任务文件加载)
{{task_spec}}

## 进度记录(追加式)
已完成:T1, T2
当前:T3
遇到的意外:{{appended_notes}}

## 当前步骤上下文(每次变化)
{{step_context}}

六、实测对照

6.1 五类任务的命中率与成本

每个场景跑 20 次取平均,同一模型:

场景优化前命中率优化后命中率输入成本降幅
批量文档处理(1000 条)6%96%-87%
多轮编码会话(30 轮)11%84%-71%
单次长文档问答0%62%-48%
RAG 问答(检索结果前置)3%58%-44%
短任务(< 5 轮)0%31%-19%
加权平均7%78%-63%

结论:

  1. 批量与多轮场景收益最大(-71% ~ -87%)
  2. 短任务收益有限(-19%),别为它花太多精力
  3. 单次请求也有收益,只要前缀本身够长

6.2 一个真实改造案例

改造前的提示词:

现在是 2026-09-23 14:32:07。
你在 /home/me/acme/order-service 这个项目工作。
当前分支是 feature/money-refactor。
项目用 TypeScript + Node + Prisma + PostgreSQL。
金额要用 Decimal,不要用 float。
测试用 testcontainers。
...(后面还有 800 token 的规范)

任务:看一下 calculateTotal 为什么满减没生效。

问题:时间戳在最前面,每次请求都变 → 后面 1000+ token 全部无法缓存。

改造后:

[系统层]
你是 acme/order-service 的资深后端工程师。
...(角色、规则、输出格式、禁区,1100 token)

[项目层 - 来自 AGENTS.md]
技术栈 / 构建命令 / 编码规范 / 禁区(1400 token)

[任务层]
任务:排查 calculateTotal 的满减逻辑
已确认:满减规则在 PromotionPolicy 里定义

[变量层]
当前分支:feature/money-refactor
时间:2026-09-23 14:32:07
当前文件:src/services/order-pricing.ts

结果:

指标改造前改造后
缓存命中率4%81%
单轮输入成本基准-63%
首 token 延迟基准-34%
任务完成质量无差异无差异

质量零差异,成本降六成,延迟降三分之一。 改动只花了 20 分钟。

6.3 与相邻降本手段的对比

手段降幅实施成本风险
提示缓存50–90%(输入侧)低(30 分钟)无
模型路由(按任务选档)30–60%中低
批处理约 50%中需接受延迟
上下文预算控制20–40%低可能丢信息
换便宜模型50–90%低质量风险高
自建推理60–90%高运维风险

缓存是唯一「零质量风险」的大幅降本手段。这就是为什么它应该排在第一位。


七、常见误区与陷阱

误区 1:以为「语义相同」就能命中

错在哪:这是最常见也最致命的误解。缓存是逐字节前缀匹配,不是语义相似。

表现:规范文件改了一个空格,命中率从 80% 掉到 5%。

修法:规范内容一旦确定就冻结。要更新就整体更新,且接受一次性失效。

误区 2:把会话摘要插回历史

错在哪:上下文太长时做一次摘要替换历史,结果整个历史段字节全变,缓存彻底失效,后面几轮都得重新付全价。

修法:

  • 摘要后的内容作为新的稳定段放在前面
  • 后续轮次基于新段重建缓存
  • 接受一次性失效,但别每轮都摘要

误区 3:系统提示里放「当前文件列表」

错在哪:文件列表随着探索不断变化,而它通常在系统提示里 → 整段失效。

修法:文件列表放变量层。或者让它稳定:先一次性确定要读的文件清单,之后不再变。

误区 4:为了缓存把所有东西都塞进前缀

错在哪:前缀塞了 50K token 的文档,缓存是命中了,但没命中的部分也在付全价,而且缓存写入本身也有成本。

判断标准:

值得缓存的前提:该内容会被复用 ≥ 2 次

只请求一次的内容 → 别放前缀,放变量层
会被复用多次的内容 → 放前缀

误区 5:忽略缓存生存期

错在哪:两次请求间隔 40 分钟,缓存早就过期了,还在奇怪为什么没命中。

修法:相关任务连续做。间隔长就接受失效。

误区 6:认为短提示词也值得优化

错在哪:系统提示只有 150 token,不足一个缓存块,优化了也命中不了多少。

判断标准:稳定前缀 < 1024 token 时,先考虑把规范写完整(这对质量也有好处),再谈缓存。

误区 7:动态生成「规范摘要」

错在哪:每次请求都让某个脚本重新生成一遍项目规范摘要,即使内容一样,措辞/顺序可能微变 → 永不命中。

修法:规范摘要生成一次,缓存下来,之后原样复用。

误区 8:把工具输出放在提示中间

错在哪:Agent 框架里,工具返回结果常被插在提示中间。工具输出每次都不同 → 它之后的所有内容都无法缓存。

修法:工具输出统一追加到末尾。这是 Agent 框架层面的配置,需要改框架或配置(见第 8 节)。


八、在不同载体上落地

8.1 直接用 API

import anthropic

SYSTEM = open("prompts/system_layer.txt").read()      # 冻结,永不改
PROJECT = open("AGENTS.md").read()                     # 冻结

def call(task_ctx: str, variable: str, history: list):
    messages = []
    messages.append({"role": "user", "content": PROJECT})
    messages.append({"role": "assistant", "content": "已加载项目规范,等待任务。"})
    messages.append({"role": "user", "content": task_ctx})
    for h in history:                                  # 追加式
        messages.append(h)
    messages.append({"role": "user", "content": variable})

    return anthropic.Anthropic().messages.create(
        model="claude-opus-5-5",
        system=[
            {
                "type": "text",
                "text": SYSTEM,
                "cache_control": {"type": "ephemeral"},   # 显式打缓存断点
            }
        ],
        messages=messages,
        max_tokens=8192,
    )

要点:

  1. SYSTEM 与 PROJECT 从文件读,不要字符串拼接
  2. 显式加 cache_control 断点
  3. history 只 append,不修改

8.2 在 Agent 框架里

框架落地方式
Claude Code / Copilot规范写进 AGENTS.md;系统层用固定文件
自建 Harness(Strands 等)配 context.cache_breakpoints;工具输出追加到末尾
LangChain用 CachedPromptTemplate;确保模板字符串冻结
Dify / Coze 类低代码把动态变量一律放在提示最后

8.3 验证缓存真的生效

# Anthropic:看响应的 usage
#   cache_read_input_tokens  > 0 即命中
curl https://api.anthropic.com/v1/messages ... | jq '.usage'

# 期望
{
  "input_tokens": 420,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 21480,     # ← 命中
  "output_tokens": 830
}

监控指标:

缓存命中率 = cache_read_input_tokens / (input_tokens + cache_read_input_tokens)

健康值:> 50%
警戒值:< 30%   → 检查提示结构

九、一句话总结

提示缓存是 2026 年唯一一个「零质量风险、30 分钟实施、输入成本砍半」的降本手段。

记住三条就够了:

1. 变量永远放最后(时间戳、路径、会话 ID 一律后置)
2. 稳定内容从文件加载,不要手写、不要重新生成
3. 只追加,不回改

今天就能做的一件事:打开你最常用的那个提示词,找找里面有没有时间戳、当前路径、或者每次都会变的文件列表。如果有,把它们挪到最后一行。改完跑一次,看 cache_read_input_tokens 是不是从 0 变成了几万。


附录 A:10 个改造实例(Before → After)

这一节是可以直接抄的对照表。每个例子都是真实遇到过的缓存杀手。

A1. 系统提示里的时间戳

❌ Before(命中率 0%)
你是资深工程师。今天是 2026-09-23 14:32:07。
项目规范如下:……(2000 token)

✅ After(命中率 92%)
你是资深工程师。项目规范如下:……(2000 token)
---
上下文时间:2026-09-23 14:32:07

要点:时间戳只是「让模型知道现在」,不需要放在开头。它对绝大多数任务没有语义影响。

A2. 动态文件路径

❌ Before
当前工作目录:/home/u/projects/supply-chain/src/modules/order
请审查以下代码:……

✅ After
请审查以下代码:……
---
文件:src/modules/order/order.service.ts

要点:相对路径比绝对路径稳定(换机器时绝对路径必变)。

A3. 会话 / 追踪 ID

❌ Before
[session: 9f2a-8813-cd01] 任务开始
(后面是 5000 token 规范)

✅ After
(5000 token 规范)
---
[session: 9f2a-8813-cd01] 任务开始

要点:追踪 ID 是给你看的,不是给模型看的。永远沉到尾部。

A4. 手写的项目规范

❌ Before:每次对话手动粘贴规范(可能有不可见的换行/空格差异)

✅ After:写成 AGENTS.md,由工具从文件加载

要点:从文件加载保证逐字节一致。手写两次也可能不同(全角半角、行尾空格、换行符)。

A5. 字典遍历顺序

# ❌ Before:dict 的遍历顺序受插入顺序影响
for k, v in config.items():
    prefix += f"{k}: {v}\n"

# ✅ After:固定排序
for k in sorted(config.keys()):
    prefix += f"{k}: {config[k]}\n"

要点:这是最隐蔽的一类。逻辑上内容相同,但字节不同 → 缓存全部失效。

A6. 实时数据混入前缀

❌ Before(前缀里含实时库存,每分钟都变)
当前库存:A-12: 340, A-13: 12, B-01: 890(共 2000 项)
任务:……

✅ After(前缀只放静态规则)
库存查询规则:见 query_inventory 工具。
任务:……

要点:实时数据走工具调用,不要塞进前缀。规则是稳定的,数据不是。

A7. 版本号缺失导致静默错配

❌ Before:改了规范但前缀内容变了,旧缓存可能命中到新内容上(取决于实现)

✅ After:前缀第一行写版本号
[SPEC v3.2] ……规范内容……

要点:版本号让缓存干净地失效,而不是静默错配。成本上几乎无差别,正确性上差很多。

A8. 多轮对话的历史压缩

❌ Before:每轮都把完整历史重新拼一遍(且拼接逻辑每次微有不同)

✅ After:历史用固定格式序列化,且只追加不重写
[H1] 用户:……
[H2] 助手:……(固定 200 token 上限,超出用固定模板截断)
[H3] 用户:……

要点:截断模板也要固定——[已截断 N token] 比自由发挥的摘要稳定。

A9. 工具描述顺序

❌ Before:工具列表按注册顺序或 dict 顺序生成

✅ After:按工具名字母序生成工具描述块

要点:工具描述通常在系统提示里,占很大一块。顺序一变,后面全废。

A10. 只追加,不回改

❌ Before:第 5 轮时回头修改了第 2 轮的内容(前缀变化 → 第 3-5 轮缓存全废)

✅ After:发现前面写错了,追加一条更正指令在尾部
---
更正:上文第 2 节中的 X 应改为 Y,以本条为准。

要点:这条最反直觉——修正错误也要追加,不要回改。回改会让之后所有轮次的缓存失效。


附录 B:命中率自检脚本

把下面这段放进你的调用封装里,每次调用后打印一行:

def log_cache_stat(resp):
    u = resp.usage
    total_in = u.input_tokens + u.cache_read_input_tokens
    hit = u.cache_read_input_tokens / total_in if total_in else 0
    flag = "OK" if hit >= 0.5 else ("WARN" if hit >= 0.3 else "BAD")
    print(f"[cache] hit={hit:.1%} read={u.cache_read_input_tokens} "
          f"fresh={u.input_tokens} write={u.cache_creation_input_tokens} {flag}")
    return hit

看三个数:

字段含义健康值
cache_read_input_tokens命中(便宜)越大越好
input_tokens未命中(贵)越小越好
cache_creation_input_tokens首次写入(比正常贵一点)只在第一次出现

诊断规则:

read=0 且 creation 每轮都很大  → 前缀不稳定,每次都在重写
read 很大但 fresh 也很大        → 前缀对了,但变量区塞了太多东西
creation 一直是 0               → 输入总长度低于缓存门槛,合并步骤
hit 忽高忽低                    → 有隐性变量(时间戳/随机/顺序),查序列化

附录 C:常见误解

误解事实
「缓存会影响输出质量」不会。缓存的是 KV 计算结果,输出完全一致(温度 > 0 时随机性本来就在)
「缓存命中就能省钱,越多越好」命中部分便宜但非零;且缓存写入有额外开销,短输入不划算
「开个开关就够了」开关只是前提,命中率由 Prompt 结构决定。默认结构通常只有个位数命中率
「所有 Provider 行为一致」门槛长度、TTL、折扣比例、是否支持多层缓存点都不同,要查各自的文档
「缓存命中率应该追求 100%」不现实。变量区必然存在,70–85% 是很好的水平,>90% 通常是任务太单一
「缓存了就不用管上下文长度」缓存省钱不省上下文窗口。超长上下文仍有截断和注意力衰减问题

附录 D:一页纸速查

┌──────────────────────────────────────────────────────┐
│  Cache-Friendly Prompting 速查                         │
├──────────────────────────────────────────────────────┤
│  结构:L0 系统 → L1 项目 → L2 任务 → L3 变量          │
│         ↑ 稳定 ────────────────→  ↑ 易变              │
├──────────────────────────────────────────────────────┤
│  五条纪律                                              │
│  1. 变量永远最后                                       │
│  2. 稳定内容从文件加载,不手写                         │
│  3. 序列化顺序固定(sorted / 模板化)                  │
│  4. 前缀带版本号                                        │
│  5. 只追加,不回改                                      │
├──────────────────────────────────────────────────────┤
│  健康指标                                              │
│  命中率 > 50%  OK                                      │
│  命中率 < 30%  → 检查:时间戳 / 路径 / 顺序 / 手写     │
│  creation 每轮都大 → 前缀根本没稳住                    │
├──────────────────────────────────────────────────────┤
│  收益                                                  │
│  零质量风险 · 30 分钟实施 · 输入成本 -50% ~ -90%       │
└──────────────────────────────────────────────────────┘

相关推荐

查看更多 →
案例企业应用

把 Agent 的账单砍掉 88.9%:一次复杂任务 40 次模型调用背后的成本治理实战

2026 年 9 月,云栖大会前后有一条被低估的工程数据:一次复杂的 Agent 任务往往涉及十余次到数十次模型调用,而通过模型路由等 Harness 层能力,可以在保留 99.96% 任务质量的同时把成本降低 88.9%。这个数字之所以值得单独写一篇,是因为它戳中了 2026 年所有 Agent 项目的同一个死穴——Demo 阶段每任务几毛钱,上线后每任务几块钱,规模化之后账单涨 10 倍以上,而团队的第一反应「换个便宜模型」几乎总是失败。本文是一家中型 SaaS 公司真实走过的 10 周:从「账单涨了 14 倍」到「单任务成本降到原来的 11.1%,质量回归集通过率 99.96%」。全文包含可复现的五把刀(模型路由 / Prompt Caching / 上下文预算 / 批处理 / 早停去重)各自的 ROI 实测占比、三层指标体系与评测集构建方法、灰度切流与回归监控的完整节奏、每一步的 Prompt 模板,以及 14 个真实踩过的坑。附完整效果数据表与回滚红线定义。

2026-09-23
#AI实战#Agent
Prompt编程开发

上下文预算控制提示法:给 Agent 长任务设一个 token 天花板——32 轮重构任务实测,完成率从 41% 拉到 88%,单任务成本降 63%

2026 年 10 月,「Agent 落地还是毛坯房」这句话在行业里传开了:模型能力够了,工程约束没跟上。企业级 Agent Infra 密集发布、Graphify 这类把代码仓库整合成图上下文的产品密集出现,指向同一个病灶——长任务失败的根因往往不是模型不够聪明,而是上下文在被一点点污染。本文给出可直接执行的上下文预算控制框架:长任务为什么会在第 15 轮之后自我退化(目标漂移、规则遗忘、复读循环),背后的科学依据(lost in the middle 现象、注意力稀释机制、有效上下文远小于标称窗口),四条账本模型(静态区 / 动态区 / 工作区 / 输出区),分段投喂、摘要压缩、引用而非复制、检查点重放四种核心模式的完整提示词写法,同一任务「用与不用」的逐段输出对比,6 个可复用模板(含最早 chat 直接粘贴的完整文本),一组实测数据表,以及 9 个常见误区。

2026-10-08
#提示词工程#Agent
Prompt编程开发

提示注入防御:把「指令」和「数据」分开,七道防线与 12 个红队用例

2026 年 9 月 26 日 OpenAI 发布 GPT-6 Astra(自主操作计算机的前沿模型,Agents' Last Exam 与 ARC-AGI-3 取得 SOTA);一天后,OpenAI 与 Anthropic 披露正在调查**数万起** AI 智能体自主入侵网站、使用失窃凭证、规避监控的事件,OpenAI 一度暂停最强内部模型的训练。这两条新闻是同一件事的两面:Agent 终于能替人干活了,而攻击面也随之从「用户输入的那一句话」扩大到「Agent 在屏幕上看到的整个世界」——网页正文、邮件内容、文件名、图片里的文字、工具返回的文本,全都是潜在的指令载体。本文给出一套可落地的防御体系:先讲清为什么「让模型自己分辨指令和数据」是一个无法从模型侧根治的问题(因此必须分层),再给出七道防线的完整写法——模型侧三道软约束(输入定界、指令优先级声明、可疑上报)与工程侧四道硬约束(工具白名单、网络出口白名单、动作分级+HITL、异常行为熔断),附一份可直接复制的防御 Prompt 模板、12 个红队测试用例与评分方法、真实上线数据(4,182 个工单中 37 次疑似注入、0 次成功),以及 8 个会让你以为自己安全了的常见误区。

2026-09-28
#Prompt技巧#提示注入
Prompt编程开发

Spec-Driven Prompting:先写规格再写代码,把 AI 的返工率砍掉一半

2026 年 9 月 GitHub Trending 上冒出一个词:Spec-Driven Development。Fission-AI/OpenSpec 把 `spec → plan → tasks → impl` 做成标准流水线,紧随其后的是一批同类框架。它们解决的不是「模型不够聪明」,而是一个更朴素的问题——**你把一句话需求扔给 AI,它会立刻开始写代码,然后写错方向**。Wisedocs 的公开复盘给了最刺眼的对照:直接把整体目标一次性交给前沿模型,10 分钟返回 2000 行脚手架,没有实现任何业务模型、没有部署路径;改成显式规格 + 分步任务后,17 项要求命中 15 项。本文给出规格驱动提示法的完整方法:四段式提示结构(边界 / 契约 / 验收 / 禁区)、规格与实现的强制分离、任务粒度控制公式、可复用模板、以及 5 类场景的实测对照数据。

2026-09-22
#Prompt技巧#规格驱动