loading

Loading

探索与发现

首页 AI 开发实战

Agent工具结果缓存:三处缓存键设计让复用变废纸

字数: (1929)
阅读: (5)
0
摘要:贴代码级复盘工具结果缓存的三个真正痛点:稳定序列化、分类 TTL 和写后失效。分享键中塞时间戳导致命中、长内容不再复用、以及给无状态模型补命中说明的具体工程取舍。

上周给一个内部 Agent 加工具结果缓存,上线两天后回滚。原因不是缓存没命中,而是命中了不该命中的——一份上一轮已经把文档删掉的结果,被当成有效数据复用了一次。问题不在 Redis,也不在 TTL 设得太长,而在缓存键把不该区分的东西写在了一个随时变化的层面上。

我的判断是:工具调用结果复用时绝大多数收益可用轻量级方案支撑,把它做成通用中间件反而容易翻车。以下是踩过的坑和取舍。

缓存键是一个契约,不是一根管道

一个很典型的反例来自缓存键里塞了时间戳。团队每轮生成对话摘要,把当前时间放进 key,单看只是顺手操作,但它向整个缓存层声明了一个含义:每次调用的结果都不同,无需复用。这个单行改动能通过 CR(变更请求)代码审查,说明很多工程队伍还只是把缓存键当成命名容器,尚未把它当成语义判断。

我们出问题的那次更隐蔽。键长这样:tool:doc_update:user_id:session_id,参数只取了部分变体。同一会话里,前一轮 doc_update(path="a.md", content="...") 和下一轮 doc_update(path="a.md", content="新内容") 撞进同一个键,缓存把旧结果当成了新写入的返回。第三轮读 a.md 时拿到旧内容,模型据此推理,多绕了四个工具调用才把问题纠正回来。

正确做法是把参数序列化成确定性串。排序并展平嵌套字段,不能把 Pydantic 模型的 repr 直接塞进 Redis——同一份参数如果 repr 字段顺序不固定,缓存会全量 miss;如果最后恰好恒定,缓存命中又变成了错误复用。同理,写操作的键必须是「工具名 + 全量参数」,不带会话、不带时间、不带请求 ID。

TTL 不能只有一档

把工具缓存放在同一个 Redis 实例里,用同一个 EXPIRE 值,是第二阶段踩的坑。我们的工具大致分两类:搜公开文档,结果变动很少;查工单状态,缓存 30 分钟就可能滞后。当初统一给了 10 分钟——对前者命中率上不来,对后者过于乐观。

后来让每个工具注册自己的数据波动档案:搜索类 30 分钟到 2 小时,状态查询类 30 到 60 秒,汇率这类不接、工具直接透传。工程上只需要维护一张表,代码不到 30 行,但缓存层级从「有没有命中」变成了「本类结果是否合适复用」。

跟 KV Cache 有部分相同思路的来源里提到缓存的两道校验腿——存在性加过期——但差异在密钥组织。序列化的确定性比 TTL 更早决定复用价值。键不稳定,TTL 再精确也没有意义。

写操作要直接让同域读结果失效、不能只等 TTL 失效

1。可用两档 TTL 做服务路径上的兜底,写路径上用依赖监听严格释放。

读结果命中与「精简提示文本」

数据来源里有一篇 AI 笔记讲了个细节,我觉得被低估了:命中后需要给无状态大模型一句极简文本,比如「缓存命中:北京今日天气晴,无需调用天气工具」,否则模型根本不知道本地有结果,会自己再调一次工具。我们实测里被坑得最多的就是这一步——缓存确实返了 5,120 token 的原始工具结果,但模型只看见它在上下文里睡着,进还是走了工具调用。

问题不在不执行工具,它至少白付了 Token 成本;更痛的是旧结果在批量工具模式下反复堆积让上下文失真。加上约 20 token 的命中说明后,跳过工具完成任务的检出稳定。我没有实测过由这个过程文档给出具体收益,但与提示工程经验一致:对无状态模型来说,提示文本就是传接口,不能缺。

成本收益对照大概是什么量级

动作落地上更值得先做常见误判
工具键去时间戳/请求 ID第一次改动就该做以为键唯一就好
按类别注册 TTL第二处可以上线TTL 统一设置
写-读依赖失效遇到真实脏读就可以加等待自然过期
命中提示文本生成在 70B 以下模型上优先把缓存响应当成模型可感知上下文

没有给准确节省比例——各工具冷热分布不同,没有通配估算可信。我实际看到的切面是:搜索类工具在开发会话里重复率很高,命中率两三成;状态查询类基本不到一成,不值得早期把全部精力压这里。

分档实现的收益取决于每家的具体工作负载,不来自搜索材料给出的数字。我没有把缓存包装成透明中间件的判断也依赖这一点:行为对模型不可见的表现层在多语会话下已经多次证明不可靠。

取舍检查单

  • 键值对真正敏感、对分页游标和全量参数都进键;把数字取整、参数置换成稳定字符可以考虑服务端签名。
  • 分类 TTL 让工具作者可注册,不允许中间件一刀切。
  • 写/读组合,要让类型知道的依赖失效先上线,再讨论依赖关系跨工具搜索。
  • 命中的提示文本作为独立路径验证,不要押在检索后端免费碰巧对上。

转载请注明出处: 皮哈皮阿

本文的链接地址: https://blog.phpat.com/ai-dev/660.html

手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

您可能对以下文章感兴趣
1 / 1
预览图