ByteNoteByteNote
DeepSeek Harness 怎么把超大工具输出落盘
字

字节笔记本

2026年10月6日 · 约 5 分钟读完

DeepSeek Harness 怎么把超大工具输出落盘

API中转
¥120

Agent 一旦开始干活,工具输出就是上下文里最不可控的部分。一个 web_fetch 调用可能拖回整页甚至整个文档站的文本,原样塞进对话,轻则挤掉真正要紧的内容,重则直接顶到上下文上限。DeepSeek Harness 是 DeepSeek 开源的 agent 框架,采用一切皆插件的架构,它在核心循环之外专门放了一条处理这种场景的可选接缝:spill 存储。

一条接缝,三个包

spill 存储是一条能力接缝:它把工具产生的超大文本持久化下来,返回给模型的不是原文,而是一个定位符加检索指引。这套能力拆在三个包里,各管一段。

dsh-spill 是服务定义,声明 SpillStore 抽象服务,以 ctx.spillStore 的形式暴露给所有插件。dsh-spill-local 是服务提供方,把内容写成宿主文件系统中会话作用域的私有文件。dsh-spill-policy 是消费方,以 tools/post-execute 策略的形式,在工具执行完之后把超大结果替换成 spill 引用。

边界也要说清楚:spill 是可选能力,不属于 agent loop 主干;上下文预览机制归 output-retention 所有,spill 接缝只负责保存策略交给它的最终文本,两者互不越界。

spill 存储数据流:从工具超大输出到模型可用的定位符

唯一的操作:saveText

服务面只有一个方法:saveText(input),返回 Promise<SpillRef>。请求里带四样东西。

owner 是保存时的存储命名空间,也就是产生这条输出的 sessionId。会话 fork 之后有个细节:子会话从种子日志继承的既有定位符不会被复制,也不会重新取得所有权,这些产物仍归原会话管;fork 之后新产生的 spill 才记在子会话 id 名下。

source 记录产生内容的工具名、调用 id 和一个短标签,只用于命名和事后检查,不做访问控制。

suggestedName 是调用方建议的文件名,比如 web_fetch.txt。它只是提示,不是路径,后端会把它清洗成单个安全的路径段再用。

content 是要持久化的完整 UTF-8 文本,原样保存。

返回的 SpillRef 有三个字段:locator 定位符、bytes 准确字节数、retrievalHint 检索提示。locator 是品牌化的不透明句柄:本地后端把它渲染成文件系统路径,换成远程或数据库后端,它就可能是 URI、键或命令 token。消费方的纪律是只渲染不解析:用 retrievalHint 生成指引,不能假定 read 永远是正确的取回方式。

错误语义同样明确:权限不足、磁盘空间耗尽(ENOSPC)、后端不可用这类真实存储失败会让 saveText 直接拒绝,如何降级由调用方决定。

本地后端怎么落盘

dsh-spill-local 把文件写成 <root>/session-<hash>/<random>-<safeName>,几处细节都为安全设计。

根目录是配置好的私有目录,权限 0700,延迟创建。会话子目录取 sessionId 的 sha256 哈希前 12 位。文件本身用 open(path, 'wx', 0o600) 排他创建:仅所有者可读写,路径已存在就直接失败,哪怕那是个预植入的符号链接,写入也不会被重定向到别处。文件名由随机前缀加清洗后的建议名拼成,天然防碰撞。

本地后端的 locator 就是这条路径,retrievalHint 会告诉模型可以在该路径上用 read 或 grep 取回内容。

spill 本地落盘布局与硬规则

策略层:尽力而为的替换

dsh-spill-policy 挂在工具后置执行上,检查纯文本的最终结果:超过 maxInlineBytes,就把原文替换成保留库生成的首尾预览,再附上 spill 引用。整个过程是尽力而为:保存失败就保留原始内联结果,绝不会把一次本来成功的调用变成 isError。不配置 maxInlineBytes 时,插件什么也不注册,等于真正的空操作。

设计上值得借鉴的三点

第一,服务只管存储。保留策略、工具结果替换、检索与搜索 API 都不在这条接缝的职责里,切分得非常干净,换后端不影响上游。

第二,面向模型的是不透明句柄加检索提示,而不是裸路径。存储介质从本地磁盘换成对象存储或数据库,消费方代码一行不改。

第三,失败语义前置。存储失败显式拒绝,替换环节保守兜底,超大输出的处理本身不会把正常调用搞失败。

落地方式也简单:SpillStore 是抽象服务,子类实现 saveText 后作为插件加载,即自动注册为 ctx.spillStore;每个上下文只允许一个实现,加载第二个会按 cordis 的标准行为抛错。想给 DeepSeek Harness 换一种 spill 后端,照这条路径做即可。

仓库地址:https://github.com/deepseek-ai/deepseek-harness

相关文章

分享: