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。使用同一模型、同一任务与同一初始工具集,分别进行两组测试:

  1. 中途新增一个工具,但保持其他提示词不变。
  2. 每轮都重新发送完整工具集合。

记录新增前后的缓存命中输入、未命中输入、首个更新请求耗时与账单。如果 Provider 只返回总输入 Token,无法仅靠这个数字证明 KV Cache 命中;应结合官方账单中的缓存分类或请求级用量字段判断。

对插件开发者的建议

  • 稳定工具名称、描述与 Schema,避免无意义的字段顺序或文案变化。
  • 把不常用工具延迟到真正需要时再加载。
  • 插件升级改变 Schema 时,把它当作一次缓存边界与兼容性变更。
  • 记录工具增删发生的轮次,排查成本突增时先对照这些事件。
  • 在 DeepSeek 与其他 Provider 间切换时,不要假设动态更新能力相同。

结论

v0.1.7-rc.2 的动态工具更新本质上是 Session 事实记录与 Provider 请求格式之间的一层投影。它能减少重复工具声明对稳定前缀的破坏,但节省多少取决于共享前缀长度、工具 Schema 稳定性、Provider 缓存计费与任务轮数。正确评估方式是请求级对照测试,而不是看到“支持 KV Cache”就假定所有工具切换都免费。

相关阅读

参考资料