DeepSeek Harness 动态工具与 KV Cache
DeepSeek Harness 动态工具与 KV Cache:v0.1.7-rc.2 源码分析
- 作者
- DeepSeekAgent.io 编辑部
- 发布
- 更新
DeepSeek Harness v0.1.7-rc.2 加入动态工具更新。它解决的问题不是“怎样装更多插件”,而是 Agent 运行途中工具集合发生变化时,怎样避免把完整工具定义反复塞回请求前缀,从而尽量保留可复用的 KV Cache。
这项改动同时涉及 Session 历史、Provider 能力声明、请求投影与 DeepSeek API 适配。理解这条链路,有助于判断一次插件增删究竟会不会破坏缓存,以及 Token 成本为什么会突然变化。
为什么工具变化会影响缓存
工具名称、描述与 JSON Schema 通常位于请求前缀。每轮请求都携带一整套工具定义时,只要新增、删除或改动一个工具,前缀就可能变化。长 Session 中,变化越频繁,可复用的稳定前缀越短。
动态工具更新把“当前有哪些工具”与“工具如何变化”分开记录。模型已经见过的定义留在历史中,新增或删除则以更新事件表达,Provider 再按自身能力生成最终请求。
DSH 的实现链路
1. 请求头保存有效工具集合
DSH 在 request/header.tools 中记录该轮实际组装后的工具名称。这个记录独立于具体模型是否支持原生动态更新,因此 Session 可以先保留完整事实,再决定如何投影到不同 Provider。
2. Session 生成增删事件
循环将当前工具名称与上一轮 Header 对比。新增工具会引用包含新定义的 Header;删除工具则记录被移除的名称。Session.toolHistory() 增量归并这些 Header 与 Developer Message,得到可复用的工具历史快照。
3. Provider 按能力投影
适配层读取路由的 toolUpdate 能力,再生成实际请求:
| 模式 | 行为 |
|---|---|
| 不支持 | 发送当前完整工具定义,不发送更新事件 |
addition-only | 保留新增事件,不把删除投影为原生删除块 |
in-history | 在历史中保留工具增删与已出现过的定义 |
当前 DeepSeek Flash 路由声明 addition-only。DeepSeek 适配器会把新增转换为 System Role 的 tool_addition 内容,并在存在更新时添加相应 Beta 请求头。
哪些变化仍会破坏缓存
动态更新不是“永不失效”的缓存开关。以下情况仍可能重建工具声明或缩短可复用前缀:
- 同名工具的描述或 Schema 改变;
- System Prompt、Profile 或前置上下文变化;
- 历史不完整,无法确定工具来自哪个 Header;
- 切换到不支持动态更新的 Provider;
- 压缩、迁移或自定义中间层改变了请求前缀。
尤其是同名 Schema 更新:工具名称没有变化,但模型看到的契约已经不同,DSH 必须重建声明,不能为了保缓存继续沿用旧定义。
如何验证是否真的节省 Token
不要只看 Session 总 Token。使用同一模型、同一任务与同一初始工具集,分别进行两组测试:
- 中途新增一个工具,但保持其他提示词不变。
- 每轮都重新发送完整工具集合。
记录新增前后的缓存命中输入、未命中输入、首个更新请求耗时与账单。如果 Provider 只返回总输入 Token,无法仅靠这个数字证明 KV Cache 命中;应结合官方账单中的缓存分类或请求级用量字段判断。
对插件开发者的建议
- 稳定工具名称、描述与 Schema,避免无意义的字段顺序或文案变化。
- 把不常用工具延迟到真正需要时再加载。
- 插件升级改变 Schema 时,把它当作一次缓存边界与兼容性变更。
- 记录工具增删发生的轮次,排查成本突增时先对照这些事件。
- 在 DeepSeek 与其他 Provider 间切换时,不要假设动态更新能力相同。
结论
v0.1.7-rc.2 的动态工具更新本质上是 Session 事实记录与 Provider 请求格式之间的一层投影。它能减少重复工具声明对稳定前缀的破坏,但节省多少取决于共享前缀长度、工具 Schema 稳定性、Provider 缓存计费与任务轮数。正确评估方式是请求级对照测试,而不是看到“支持 KV Cache”就假定所有工具切换都免费。
相关阅读
- DeepSeek Harness v0.1.7-rc.2 更新
- DeepSeek Harness Sub-agent Token 计费分析
- DeepSeek V4.1 Flash 的 Agent Loop 分析