块协议用了两周,我把九个坑按顺序记下来了
实测两周。环境是 DSH 0.2.1-rc.2,插件 dsh-block-ptc 0.4.0,Node 22,MIT,运行时零第三方依赖,peer 要求 Cordis >=4.0.5 且不设上界。装的是 bundle 形式,装完加了一行预设、重启一次才在列表里看到 Block PTC。两周里断断续续记了九条,下面挑四条按踩到的先后写,都是能让我停下手头活儿的那几条。数字只取插件详情页上有的:star 80、周下载 670、综合分 55.9、最近提交 9 天前。
头两天:装是装上了,然后被自己的程序拒了
第一天的体验其实很顺。选 Block PTC 预设,让模型讲 tokenizer,它每次 run_code 都会带一句 [block: tokenizer] ... 的头部,工具行上显示的就是这个 goal。夜里我按这个套路写了一个稍长的程序,第二天早上被拒了。
坑一 · 程序被 guard 拒了,而且被拒的那次不算数
报错是 "Every run_code call, including the first" 。原因我现在很清楚了:预设在这个插件那一行加了 guard,要求每一次模型直接调用的 run_code 都带 [block: <ids>] <goal> 头部,包括第一条。我那次是手写提示词时省了方括号,模型照着省了。
真正让我懵的不是被拒,是"被拒的调用不会被标记"。我一开始以为重试就行,结果重试那次虽然跑通了,前面那段内容不属于任何块,后面 block_compact 也就压不到它。所以处理方式不是重试一次,是把程序改写带头部再跑,并且接受前一次白跑。头部的 id 逗号分隔、不能为空、不能重复,也不许含逗号方括号和换行------这些细节写在 schema 里,但模型只有被拒一次才会认真读。
第二周升级:0.4.0 把旧调用全废
前一周我在 0.3.x 上攒了一堆调用习惯,周末升到 0.4.0,周一开工全线报错。
坑二 · 升级到 0.4.0 之后,旧调用全废了
0.4.0 是破坏性变更:block_summary 这个工具没了,换成 block_compact({ ids, content });旧的 summary 参数和单 id 参数都不再支持。我那些"关掉一个块"的调用是从旧文档抄的,全部作废。
两件事必须一起做:升级后重启,并且新开一个 Block PTC 会话。我踩的正是第二件------升级完直接在原来那个会话里继续,看着预设是对的,行为还是旧的。历史摘要不会跟着变,它们保持原来的文本,这点倒是符合预期。后来我学乖了:凡是改 bundle,先完全退出重开,再新建会话,最后才去改提示词。
摘要写漏,是慢慢显形的
坑三 · 摘要写漏的部分,后面真的再也拿不到了
这一条最难自查,因为当场没有任何报错。我压掉一个块的时候,content 只写了结论,没写当时定下的两个约束:一个是"不要动公开 API 的签名",一个是"错误码沿用旧的"。当时觉得这两句上下文里还有,结果替换发生之后,下一轮请求里就只剩我那段摘要了。模型按摘要继续干活,签名改了,我回头 review 才发现。
block_compact 的参数说明其实写得很直白:后续还要用的信息要完整保留,写清用户的要求、纠正和约束,记录已完成的工作、结果、未完成的部分和下一步。我现在写 content 有个笨办法------先问自己"如果这个人明天换班,只看这段能不能接着干",不能就补。省下来的 token 是真实的,但省在约束上就是给自己挖坑。
顺带记两个边界,都是这几天撞出来的:摘要会继承区间的剩余 id,可以再被摘要一次,没有剩余 id 的就保留成终态;区间里如果夹着受保护的 system/developer 消息,整个请求会被拒,不做"前缀先换掉"这种妥协。还有一次是用户在我写完摘要之后又补了一句要求,那次摘要被拒,必须读完新消息再改------这个设计我认为是对的,但第一次遇到会以为是 bug。
子代理那一块,我以为是自己写错了
坑四 · 子代理里的块,不跟主会话走
我让主会话起了一个子代理去跑一段独立分析,想让它干完把结果压成摘要回传。结果主会话里怎么都压不到那个块,报的是找不到 id。
原因很简单:块是按会话的。子代理有自己的上下文,也有自己的块,主会话的 run_code 头部在子代理那边不存在。理解这一点之后用法就变了------要么子代理自己内部压,把结果作为普通返回值交给主会话;要么主会话在拿到结果之后,用一个新的 id 把这段包装起来再压。想让两边共享一套 id,目前没有这个能力,也别去试。
两周后我对缓存的理解
刚用的时候我以为"上下文变小 = 便宜",两周下来这个等式不成立。
替换历史会让缓存后缀失效,上下文变小不保证缓存命中率更高,也不保证账单更低。插件返回的 tokensFreed 是"被替换消息的估算大小",不是 provider 的缓存命中测量,而且不含新摘要本身的开销。我一开始拿它当省钱指标,后来改成只看两件事:这一轮请求的输入是不是真的短了,以及后面还有多长的对话要续。如果关掉一个块紧接着就要收尾,省得比较实在;如果后面还有很长的活儿,缓存重建的成本会把收益吃掉一部分。
还有一点值得说:它和内置的压缩是共存的,不是替代。我没关自动压缩,只是把大部分"该收的"提前收了。
我现在固定这么用
开块的时候用短 id,按工作单元而不是按轮次:auth、parser 这种,同一件事继续做就复用同一个 id,别每次新开。关块的时机是"内容不再需要",不是"这一步做完了"------做完但还要用到细节的时候压掉,是最典型的自伤。写 content 按"交接文档"的标准写。装和改 bundle 之后一律完全退出重开。
总结
两周下来我的结论是:它把"压哪段"的决定权交给了模型,收益取决于你会话里的子任务边界清不清楚,代价是摘要写漏了没人替你兜底;同类插件的中文清单和安装形态,我在 DeepSeek Harness Hub 的插件清单页对着看过,那边按分类列了安装方式。
适合与不适合
适合:会话里子任务边界明显、能一句话说清"这块完事了"的人;愿意花时间写交接摘要、并且会回头检查的人;需要会话日志保持可回放、不接受插件自造事件的团队;能接受装完重启一次、升级后新开会话这种节奏的用法。
不适合 :想装完就自动省钱、不改提示词也不改习惯的预期;把 tokensFreed 当考核或账单口径的用法;需要跨会话共享块、或指望子代理自动继承块的场景------这两条目前就是做不到。
标签:dsh-block-ptc、DeepSeek Harness、上下文压缩、PTC
本文是我自己装了两周后按顺序记下来的,数据来自插件详情页与本地会话日志。