dsh-longtask-guard:长任务会话的上下文外化与空正文救援

前言

在 DeepSeek Harness(DSH)里跑长任务,会话往往走到几百步。这时常见两类问题叠在一起:整段历史的字符数不断膨胀,请求越来越重;模型又把分析全写进 reasoning,正文只剩一行错误提示,界面上像「什么都没产出」。上游一旦把这种回合判成退化并中止,你连模型当时想了什么也捞不回来。

压缩类插件主要管 token 总量和摘要折叠;单条消息特别肥、或者 reasoning 里藏着整段分析而正文为空,又是另一回事。下面介绍社区插件 dsh-longtask-guard(维护者 zhangyahao,目录分类:记忆):在请求发出前把超大消息正文收成文件索引,并在空正文回合结束时把 reasoning 归档并可选补一条可见摘录。

这是什么

dsh-longtask-guard 是 DSH 的长任务护栏插件:把臃肿的会话历史外化到项目文件,把「只写在 reasoning 里」的分析捞回你能直接看到的地方。

它不替代 billion-context 等压缩插件:压缩管 token 总量与可还原摘要;本插件管单条消息体积,以及空正文时 reasoning 的可见性与落盘。

核心功能

上下文外化

每次请求发出前,插件统计当前消息总字符数。超过阈值时,对符合条件的早期消息做收缩:

  • 只处理 assistant 与工具结果消息,不改动 user 消息
  • 单条不足 minMessageChars 的不收缩
  • 原文写入工作目录下的 archiveDir(默认 .dsh-task/archive/)
  • 消息条数与结构不变,只替换 content,避免破坏下游对消息 id 的引用
  • 收缩后的正文形如:[ctx-externalized] #12 首行摘要…|全文 15382 字符:<归档路径>
  • 两次收缩之间至少间隔 cooldownMessages 条消息,减轻对上游 prompt 缓存的反复冲击

空正文救援

监听会话事件。当一条 assistant 消息满足:reasoning 长度 ≥ minReasoningChars,且正文 text 长度 < minTextChars 时,在回合结束(turn/end)时:

  1. 将 reasoning 写入 .dsh-task/reasoning/turn-<回合>-<时间>.md
  2. 若 appendSummary 为 true,通过 session.append 补一条可见 assistant 消息,含归档路径与摘录(长度受 summaryExcerptChars 限制)

README 中举过真实长会话量级:例如约 165 回合、约 7 MB 日志里,大量 assistant 消息把内容写在 reasoning,其中数百条正文为空——这类回合在界面上几乎看不到结论。插件不能关闭上游的「退化回合中止」逻辑,但能降低上下文压力,并在发生后把分析留在项目目录里。

安装与启用

需要 DSH 0.2.x。官方 README 的安装方式是:先把仓库放到本地,再用插件管理器以目录绝对路径安装 bundle,然后重启 DSH。

git clone https://github.com/zhangyahao/dsh-longtask-guard.git
# 然后在会话里:
plugin_manager(action="install_bundle", target="<克隆目录的绝对路径>")
# 重启 DSH 生效

卸载:

plugin_manager(action="remove_bundle", target="dsh-longtask-guard")

插件在 当前 DSH 进程权限 下运行,会读写会话工作目录下的 .dsh-task/ 以及 $DSH_HOME/data/longtask-guard.json。安装前应自行查看源码与 MIT 许可证,确认路径与数据落盘策略符合你的环境。

配置

默认值在 cordis.patch.yml 中,运行期统计与配置持久化在 $DSH_HOME/data/longtask-guard.json,重启后保留。

config:
  enabled: true
  externalizeAtChars: 1200000   # 消息总字符超过它才外化(约 30 万 token)
  keepRecentMessages: 40        # 最近 40 条消息不动
  archiveDir: .dsh-task/archive # 相对当前会话工作目录
  minMessageChars: 1200         # 单条消息至少这么长才值得收缩
  cooldownMessages: 60          # 两次收缩之间至少间隔的消息条数
  captureReasoning: true        # 是否做空正文救援
  minReasoningChars: 400        # reasoning 至少这么长才救援
  minTextChars: 20              # 正文短于这个长度视为「空正文」
  reasoningDir: .dsh-task/reasoning
  appendSummary: true           # 救援时是否往会话里补一条可见消息
  summaryExcerptChars: 2400     # 补发消息里摘录的长度上限

若与压缩插件并用,README 建议把 externalizeAtChars 设得比压缩插件触发点高一些,只在压缩管不住的单条超大消息上动手。

典型用法与工具

外化与救援默认自动执行,不必先调工具。需要查看状态或手动干预时,插件提供以下工具(名称以 README 为准):

工具 用途
longtask_status 阈值、保留窗口、本次运行的收缩与救援统计
longtask_externalize 手动登记一次外化(force: true 可绕过冷却)
longtask_handoff 把进度写成交接文件 .dsh-task/handoff-<时间>.md
longtask_reasoning 列出或读取救援归档的 reasoning 文件

长任务中途需要换人或新开会话时,可结合 longtask_handoff 与 longtask_reasoning 从归档文件接着做,而不必在界面里翻折叠的 reasoning。

适用场景与注意

适合谁

  • 单会话步数多、历史里有大段 assistant 或工具输出原文
  • 经常遇到正文几乎为空、分析全在 reasoning 的回合
  • 已与或计划使用上下文压缩插件,但仍需处理「单条巨型消息」和「空正文可见性」

边界与取舍(来自 README)

  • 上游退化中止没有配置开关;插件只能减轻触发概率并在事后归档与摘录,不能保证不再发生
  • 外化会改动历史消息正文,动过的那一轮上游 prompt 缓存会失效——这是有意取舍
  • appendSummary: true 时补发的消息会进入会话历史;不需要可见摘录可改为 false
  • 只处理文本正文;图片等非文本块原样保留
  • 救援依赖宿主 session/event 与 session.append;版本不提供时仅外化生效

DSH 生态强调「一切皆插件」;SkillHub 等社区目录独立于 DeepSeek / 幻方,并非官方应用商店。选用插件时以仓库说明与本地审计为准。

结尾

dsh-longtask-guard 针对长任务的两个刚需:用文件索引换掉过长的历史正文,把困在 reasoning 里的分析落到 .dsh-task/ 并可选拉回正文。与压缩插件分工明确,可一并启用并按阈值错开配置。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜