Prompt caching is all we need | Ralph

KV Cache 与 Prompt Cache

近期有用户发现 DeepSeek 存在一个可疑 Bug:输入特定 think 标签时,模型会突然吐出看似"接管他人对话"的内容。

关于这些数据的来源,目前有两种猜测:

可能 分析 结论
训练数据 泄露内容都在对话开头位置,如果是真实对话记录,理应包含对话中途的内容 可能性较大
真实对话泄露 如果真是泄露的用户对话记录,问题将非常严重 可能性较小

如果真是后者,那问题很可能出在提示词缓存上------这也是今天要讨论的主题。


二、KV Cache:单次生成中的 KV 复用机制

KV Cache 是大模型推理优化中最重要的技术之一。"KV"指注意力机制中的 Key 和 Value。

大模型的本质是不断计算下一个 token

复制代码
输入: "宝塔镇河"
输出: "塔"
输入: "宝塔镇河塔"
输出: "正"
输入: "宝塔镇河塔正"
输出: "..."

计算每个 token 时,输入的变量包括:

  • Q(Query):当前 token 的查询向量
  • K(Key):所有 token 的键向量
  • V(Value):所有 token 的值向量

在类似的计算过程中,同一个 token 的 KV 值不会改变。原因:

  • KV 只与当前 token 的向量、模型参数、之前的 token 向量有关
  • 这三个因素在计算过程中都不会变

2.3 计算流程

无 KV Cache 时

复制代码
第1次计算:输入 "宝塔镇河" → 计算全部 KV → 输出 "塔"
第2次计算:输入 "宝塔镇河塔" → 重新计算全部 KV → 输出 "正"
第3次计算:输入 "宝塔镇河塔正" → 重新计算全部 KV → 输出 "..."

有 KV Cache 时

复制代码
第1次计算:输入 "宝塔镇河" → 计算全部 KV 并缓存 → 输出 "塔"
第2次计算:输入 "宝塔镇河塔" → 只计算 "塔" 的 Q,读取已缓存的 KV → 输出 "正"
第3次计算:输入 "宝塔镇河塔正" → 只计算 "正" 的 Q,读取已缓存的 KV → 输出 "..."

2.4 KV Cache 的效果

指标 无 KV Cache 有 KV Cache
首个 token 生成 正常速度 正常速度
第 2+ 个 token 与首个相同 显著加快
整体耗时 累加所有 token 大幅减少
速度变化 越来越慢 保持稳定高效

没有 KV Cache,每个 token 的生成速度都会很慢,而且会**越来越慢**。


三、Prompt Cache:多次调用中的前缀复用

Prompt Cache(提示词缓存) 是指在多次模型调用中,缓存之前提示词的 KV 结果。如果后面的调用和前面的调用有相同的前缀,这一部分不需要重新计算 KV,可以直接复用。

3.2 应用场景:Agent 模式

以 AI 回答"明天天气怎么样"为例:

复制代码
用户: "明天天气怎么样"
模型: 返回工具调用指令 ← 第1次调用
工具调用完成,后台再次发起调用
模型: "天气晴朗,温度15-22°C" ← 第2次调用

问题:第二次调用时,模型实际收到的输入是什么?

python 复制代码
# 实际上需要包含完整的历史对话,模型才能理解上下文
实际输入 = [第1次调用的系统提示词, 第1次用户的问句, 第1次模型回复, 第2次用户的新问题]

3.3 Prompt Cache 的价值

由于第二次调用的前缀部分 (第1次调用的全部内容)与第一次调用的内容相同,这部分的 KV 值已经计算过,可以直接复用

复制代码
第1次调用输入: [系统提示词] + [用户问句] → 计算所有 KV → 返回工具调用指令
第2次调用输入: [系统提示词] + [用户问句] + [模型回复] + [工具结果]
              ↑___________________↑
              这部分 KV 已缓存,可直接复用

3.4 缓存命中(Cache Hit)

缓存命中 是指在多次模型调用中,后面的调用复用了前面调用已计算的 KV 结果

指标 数据
常规对话中缓存命中率 可达 98% 以上
原因 Agent 本质是反复调用模型,每次调用都在之前基础上追加新内容

四、KV Cache vs Prompt Cache

维度 KV Cache Prompt Cache
作用 单次生成过程中 多次模型调用之间
关注 生成下一个 token 时复用之前的 KV 下一次调用复用上一次调用的 KV
场景 生成一句话时的加速 Agent 多轮对话、Claude Code 系统提示词
缓存 当前输入序列的历史 KV 上一次模型调用的完整前缀 KV

两者本质相同,都是通过缓存 KV 值来避免重复计算,只是应用场景和粒度不同。


五、缓存的现状

5.1 DeepSeek:赛博善人

近几个月来,DeepSeek 被称为"赛博善人",原因在于:

  • 缓存命中几乎不收费
  • 用户反馈"用过的都说好"

5.2 Token 中间商

与 DeepSeek 形成对比的是某些"90后 Token 中间商":

复制代码
表面:多优惠大酬宾
实际:吃掉全部缓存命中的差价
操作 说明
常规价格打折 随便打,甚至打骨折
缓存命中偷偷涨价 调成官方的 10 倍
赌的是什么? 赌你眼神不好,看不清少数点

黑心中间商的套路远不止这些:收大模型的钱换小模型、虚报 token 用量......总之"从南京到北京,买的没有卖的精"

5.3 Claude Code 的启示

Claude Code 源码泄露后,有人发现密密麻麻只写着两个字:缓存

官方自己也表示:提示词缓存就是一切

一:静态前缀优先,动态内容靠后

复制代码
┌─────────────────────────────────────────────────────────────┐
│ 静态提示词(可复用)                                        │
├─────────────────────────────────────────────────────────────┤
│ · 身份规则("你是一个专业的代码助手")                      │
│ · 行为守则("始终保持简洁、直接的回答风格")                 │
│ · 安全红线("不允许执行危险命令")                          │
├─────────────────────────────────────────────────────────────┤
│ 动态提示词(可能因人而异)                                   │
├─────────────────────────────────────────────────────────────┤
│ · 环境信息(当前目录、操作系统)                            │
│ · 语言偏好(用户的语言设置)                                │
│ · 输出风格(用户的格式偏好)                                 │
└─────────────────────────────────────────────────────────────┘

静态部分可被所有用户共享缓存,大幅提升命中率。

二:通过标签增量变更,而非修改原始前缀

问题:历史提示词内容发生变化时,如何保持前缀不变?

错误:直接修改系统提示词中的日期

复制代码
[原始系统提示词:当前日期是10号] → [修改后:当前日期是11号]
→ 前缀改变 → KV 需要重新计算

正确 :使用 system_reminder 标签追加变更

复制代码
[原始前缀:当前日期是10号]
[system_reminder:注意,当前时间是11号]
→ 前缀保持不变 → KV 可复用

建议

  1. 尽量把提示词中的变量放在后面,这样前缀更容易保持稳定
  2. 区分静态和动态内容 :静态内容前置,动态内容后置
  3. 使用增量标记:而非直接修改已有提示词
  4. 考虑本地部署:用户数据完全可控,不依赖第三方缓存

附录

概念 作用 关键
KV Cache 单次生成中复用历史 KV 避免重复计算,加速 token 生成
Prompt Cache 多次调用中复用前缀 KV 降低成本,提升效率
缓存命中 复用已计算的 KV 成本可降低到"脚踝价"
Claude Code 策略 优化前缀结构 静态前置 + 增量标记

缓存虽好,但的确危险。

缓存管理没做好可能导致:

  • A 用户的对话缓存被错误地丢给 B 用户的模型调用
  • 模型"说出不该说的话"

重视隐私的时代是非常重大的问题


Ralph + mutil agent

当试图给AI丢一个很长的任务,随着工作展开,模型可用的上下文空间会越来越少,理解负担越来越大,导致工作质量越来越差,最终上下文耗尽,模型停止工作。

Anthropic 官方设想

  1. 制定详细工作计划,把大任务拆分成很多具体任务
  2. 每次启动全新会话执行其中一个任务
  3. 不断重复,直到所有工作完成

每个任务都在新会话中执行,因此每个任务都有独立的全新上下文窗口


二、方案一:Ralph 方案(循环启动新会话)

while 循环不断用 claude 命令启动新会话,通过文件系统衔接上下文。

bash 复制代码
# Ralph 项目核心代码(伪代码)
while [ 任务未完成 ]; do
    claude --no-input --print "根据当前进度执行下一个任务"
    # 通过文件存储上下文信息
done
关键 说明
循环维护 循环由 shell 脚本维护(后续多智能体方案用智能体维护)
claude 命令 在后台静默执行,claude "你好" 等同于在客户端里写"你好"
相同提示词做不同事 每次启动新会话时,AI读取相同提示词,但通过文件了解需求和进度,做不同任务

2.3 提示词设计

每轮会话的工作流程:

  1. 读取文件了解需求和进度
  2. 从待办任务中挑选最重要的执行
  3. 完成后在相关文件中标记任务为已完成

信息传递方式 :前一个会话的AI和后一个会话的AI通过**文件**来交流。

2.4 确保高质量产出

提示词做了几个约束:

  • 提供所有上下文:需求文档、进度文档、工作规范、踩坑记录
  • 要求严格测试确保质量

自己开发自己测试效果一般,更好的办法是另外找子智能体来测试

2.5 应用方式

可以使用原生 Ralph,或 ragfor claude code 框架(在原版基础上增加更多功能)

操作流程

  1. 准备需求文档(越清楚越好)
  2. 用框架生成开发计划、设计规格、提示词等文档
  3. 运行 shell 脚本启动循环

三、方案二:多智能体方案(推荐)

角色 职责
主智能体(协调者) 只负责协调,不负责任何编码工作,保持上下文简洁
子智能体 专门负责制定计划、开发、测试等具体工作
  1. 设计工作流程
  2. 按流程写出主智能体和子智能体的提示词

四、工作流程设计

4.1 示例:视频素材制作

一次视频可能要做几十页PPT,一次性丢给AI经常有布局问题。

解决:拆解任务,每次只开发一个页面,开发一个测一个,然后再开发下一个。

4.2 流程

复制代码
主智能体接收需求文档
    ↓
主智能体把文档路径丢给「计划子智能体」
    ↓
计划子智能体制定计划,返回计划文档路径
    ↓
主智能体取出任务,按模板启动「开发子智能体」
    ↓
开发子智能体完成任务,**返回文件路径**(不是代码内容)
    ↓
主智能体将文件路径提交给「测试子智能体」
    ↓
测试子智能体完成测试,**返回测试结果文件路径**(不是大段内容)
    ↓
┌─ 测试失败 ─→ 将失败信息返回给**刚才负责开发的子智能体**,让它继续修复
│              (不是启动新的开发子智能体,因为历史上下文很重要)
│              ↓
│              修复后让**刚才提出问题的测试子智能体**验收
│              (不是新开测试子智能体)
│
└─ 测试成功 ─→ 更新任务进度,读取新任务,启动新的开发子智能体
                    ↓
                    重复上述循环,直到全部任务完成

谁写的 bug 谁修,谁提的 bug 谁验收

这是保证质量的关键设计


五、提示词设计

5.1 主智能体提示词

markdown 复制代码
【强调】只负责调度,不要阅读具体文件

【初始化】
1. 创建日志文件,记录工作进程
2. 获取子智能体ID(通过子智能体创建时生成的文件名获取)

【执行工作流程】
1. 使用 agent 工具启动计划子智能体(jazen),要求返回文件路径
2. 进入开发循环:
   - 启动开发子智能体
   - 完成开发后,并行启动三个测试子智能体
   - 收集判定结果和测试报告路径
3. 进入修正循环(最多3次,避免无限循环):
   - 修复时启动**之前的开发子智能体**
   - 验收时启动**之前的测试子智能体**
   - 使用 `agent` 方法的 `resume` 参数传入子智能体ID
4. 完成循环后更新日志
5. 全部完成后做总结汇报

技巧:把踩过的坑的经验也写进提示词,让AI不要犯相同的错误。

5.2 子智能体模板结构

Cloud Code 对子智能体有规范,需要做两步:

第一步:按照模板完成子智能体设计

模板分为两部分:

markdown 复制代码
--- 顶部:子智能体配置 ---
name: xxx
model: xxx
skills: xxx
permissions: xxx

--- 底部:系统提示词 ---
[具体的工作指令]

第二步:放置到指定路径

将模板文档放在 .cloud/agent/ 目录下,按子智能体名字命名。后续主智能体可以通过 agent 方法传入子智能体名字,按照模板直接生成。

5.3 子智能体提示词设计要点

两个作用

  1. 衔接流程(不管有没有流程原本都得做的)
  2. 办好事情(根据实际需要设计)

两个重点

重点 说明
文件传递 规定好开始工作前读什么文件,结束后写入什么文
输出格式 只输出文件路径给主智能体,不要输出开发内容或测试内容(占用主智能体上下文空间)

示例(测试子智能体):

  • 开始时:读取开发写的代码文件
  • 结束时:把测试结果写入本地文件,返回文件路径给主智能体

5.4 经验沉淀机制

markdown 复制代码
开发子智能体改完 bug 之后,要把经验沉淀到本地文件。

作用:
1. 同一个大循环中,前面踩的坑马上成为后来者的经验
2. 事后用于完善 skill

效果:有一次AI自己也发现,前面踩完坑后,后面的测试速度明显加快

六、实践

6.1 子智能体

子智能体 数量 用途
计划子智能体 1个 制定计划
开发子智能体 1个 执行开发
测试子智能体 3个 从页面布局、美观、动画三方面测试

6.2 模型配置

子智能体类型 模型 说明
测试子智能体 GLM-1.7(黑户) 测试工作简单,用便宜模型加快速度
其他智能体 GLM-5.1 负责复杂工作

6.3 Skill 分配

给开发和测试分别分配专属 Skill,让他们知道怎么开发、怎么测试。

不要迷信流行的 skill,要根据自己需求量身定制。流行的 skill 注重设计感,但如果更注重传递信息,可能不适合


七、执行流程

复制代码
1. 设计主智能体提示词
2. 设计各子智能体模板和提示词
3. 准备好需求文档
4. 把需求文档 + 主智能体提示词发送给 Claude Code
5. AI 开始执行,你该干嘛干嘛
6. 回来验收成果

只要AI在干活,可以心安理得的吃喝玩乐😋,并没有在浪费时间。


附录

概念 说明
Harness 工程 让 Agent 长时间不间断工作的技术
Ralph 方案 用 shell 循环 + claude 命令不断启动新会话
多智能体方案 主智能体协调 + 子智能体各司其职
Agent Team Cloud Code 的多智能体功能
Resume 恢复子智能体上下文的方法
文件路径传递 子智能体之间通过文件路径而非内容传递信息

问题 解答
子智能体完成任务就退出? 子智能体虽然被销毁,但对话上下文已存储到本地文件,可以从本地文件恢复
主智能体挂了怎么办? 使用 resume 命令恢复
权限怎么设置? 权限全放开即可
设计文档需要人工审阅吗? 视频中提到子智能体可以自己完成计划制定和设计
成本如何? 确实会消耗较多 token,但"不断重复直到任务完成"

多智能体方案的核心

  1. 独立上下文空间:用子智能体创造独立上下文给AI干活
  2. 主智能体协调,子智能体执行:主智能体不干活,只调度
  3. 文件传递信息:子智能体之间只传文件路径,不传具体内容
  4. 谁写 bug 谁修,谁提 bug 谁验收:保证修复质量
  5. 经验沉淀:让AI不犯相同错误
  6. 分层模型:复杂工作用好模型,测试等简单工作用便宜模型

结论:不要迷信框架或流程,多智能体只是帮你把流程维护好,真正决定交付质量的是对子智能体的设计。

相关推荐
AI服务老曹1 小时前
统一视界:基于 Docker+GB28181+RTSP 的边缘计算 AI 视频管理平台协议兼容架构解析(附源码交付)
人工智能·docker·边缘计算
whaosoft-1431 小时前
51c※视觉~合集1-2
人工智能
云天AI实战派1 小时前
ChatGPT/智能体/API 调用掉链子排查指南:7 步定位 AI 失灵根因的全流程实战手册
人工智能·chatgpt·api·智能体
weixin_448841271 小时前
当AI遇上群控:用自然语言指挥手机集群的新时代
人工智能·智能手机
计算机安禾1 小时前
【算法分析与设计】第21篇:回溯法的状态空间树与剪枝函数设计
大数据·人工智能·算法·机器学习·数据挖掘·剪枝
沉下去,苦磨练!1 小时前
机器学习的鸢尾花建模流程
人工智能·机器学习
前端不太难1 小时前
世界模型+强化学习:具身智能的两大核心支柱
人工智能
hsg771 小时前
简述:ResNet34/ResNet50及SENet改进模型
人工智能·深度学习
AI专业测评1 小时前
【炼字工坊x番茄小说 网文风向标】 20260530期 最新题材指南和写作指导(新人必看)
人工智能·ai写作·网文