当前位置: 首页 > news >正文

【LLM】OpenRouter调用Anthropic Claude上下文缓存处理

背景

在使用OpenRouter调用Anthropic Claude大模型时,部分模型支持上下文缓存功能。当缓存命中时,调用成本会显著降低。虽然像DeepSeek这类模型自带上下文缓存机制,但本文主要针对构建Agent场景下,需要多次调用Anthropic Claude时的缓存设置策略。

缓存机制的价值

根据官方定价策略:

  • 缓存设置:需要支付额外费用
  • 缓存命中:可大幅降低调用成本
  • 成本效益:在大量调用场景下,缓存命中能带来显著的成本节约

提示:可以通过OpenRouter账单中的调用历史费用来验证是否成功命中缓存。

官方缓存设置方法

根据官方文档的说明:

image-20250716150741020

标准的缓存设置通过在消息中添加以下结构实现:

{"cache_control": {"type": "ephemeral"}
}

缓存机制原理:这是一个前缀缓存机制,即设置缓存的消息之前的所有消息都会被缓存。

现有问题与限制

经过实际测试发现:

有效场景:在roleuser的消息中设置缓存控制有效
无效场景:在roletool的消息中设置缓存控制无效(尽管Claude官方API支持)

注意:这个问题在OpenRouter社区中已有反馈,但目前尚未得到修复。

解决方案

针对工具调用后无法在tool消息中设置缓存的问题,我们采用添加用户消息的方式来绕过限制。

原始消息结构

[{"role": "system","content": [ {"type": "text", "text": "..."} ]},{"role": "user","content": [{ "type": "text", "text": "...", "cache_control": {"type": "ephemeral"} }]},{"role": "assistant","content": [ {"type": "text", "text": "..."} ],"tool_calls": []},{"role": "tool", "tool_call_id": "...", "name": "...", "content": "..."}, // 这里无法添加cache_control{"role": "assistant","content": [ {"type": "text", "text": "..."} ],"tool_calls": []}
]

优化后的消息结构

[{"role": "system","content": [ {"type": "text", "text": "..."} ]},{"role": "user","content": [{ "type": "text", "text": "..."}]},{"role": "assistant","content": [ {"type": "text", "text": "..."} ],"tool_calls": []},{"role": "tool", "tool_call_id": "...", "name": "...", "content": "..."},{"role": "user","content": [{ "type": "text", "text": "function called", "cache_control": {"type": "ephemeral"} }]}, // 新增用户消息来设置缓存{"role": "assistant","content": [ {"type": "text", "text": "..."} ],"tool_calls": []}
]

关键改进

  • 在工具调用后添加一个用户消息
  • 消息内容使用"function called"等简单提示,避免改变对话语义
  • 在此消息中设置缓存控制

重要注意事项

  1. 缓存设置上限:Claude的cache_control结构设置是有数量限制的
  2. 最佳实践:只需在最后一个用户消息中设置缓存即可,前面的消息会自动被缓存
  3. 成本优化:在高频调用场景下,合理使用缓存能显著降低API调用成本

总结

通过在工具调用后添加用户消息的方式,我们成功绕过了OpenRouter在tool消息中无法设置缓存的限制。这种方法在保持对话语义完整性的同时,实现了有效的缓存管理,为Agent应用的成本控制提供了实用的解决方案。

http://www.xdnf.cn/news/1130941.html

相关文章:

  • Jenkins Pipeline 中使用 JsonSlurper 报错:cannot find current thread
  • 55. 跳跃游戏
  • 2025年中国品牌全球化发展分析:中国品牌在社交渠道、电商平台及官网流量方面显著增长
  • 语音增强论文汇总
  • IIS网站间歇性打不开暴力解决方法
  • 【数据结构】栈与链表的区别
  • 【Qt开发】Qt的背景介绍(二)-> 搭建Qt开发环境
  • 如何在硬件中进行有效地调试
  • TCP 三次握手与四次挥手笔记
  • 前端vue3获取excel二进制流在页面展示
  • Promise与Axios:异步编程
  • sqli-labs靶场通关笔记:第23关 注释符过滤
  • React -自定义hooks - 封装双向数据绑定
  • 自动控制原理知识地图:舵轮、路径与导航图
  • 2025年C++后端开发高频面试题深度解析:线程安全LRU缓存设计与实现
  • C# StringBuilder源码分析
  • 2025年Java最新社招面试八股文+技术场景题(金九银十)
  • Hadoop架构演进:从1.0到2.0的深度对比与优化解析
  • Hadoop(二)
  • QT技巧之快速搭建串口收发平台
  • Taro.getRandomValues() 用法详解
  • 有哪些好用的原型设计软件?墨刀、Axure等测评对比
  • Elasticsearch+Logstash+Kibana部署
  • Taro.eventCenter 用法详解与实战
  • 深入核心:理解Spring Boot的三大基石:起步依赖、自动配置与内嵌容器
  • 【Qt+error】error: use of undeclared identifier ‘MainWindow
  • uniapp各端通过webview实现互相通信
  • qt 中英文翻译 如何配置和使用
  • Spring AI 系列之十三 - RAG-加载本地嵌入模型
  • 在 CentOS 8 上彻底卸载 Kubernetes(k8s)