DeepSeek Harness 插件

dsh-large-proj-perf

DSH 大会话性能插件:零拷贝 fork + fast initFor + 投影分片预热 + fork 缓存回填 + 分片 materialize + 冷会话 LRU 裁剪 + heap 检测(DeepSeek Harness / DSH)(英文原文)

跳到安装方式

来源信息

GitHub 仓库
orangeofcarl0-sys/dsh-large-proj-perf
最近更新
2026年8月21日
分类
记忆
GitHub stars
1
载体类型
plugin
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/orangeofcarl0-sys/dsh-large-proj-perf
插件名:dsh-large-proj-perf
作者:orangeofcarl0-sys

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器3 个文件
README.md来源说明 · 只读预览

dsh-large-proj-perf

![Version]() ![dsh]() ![License: MIT](LICENSE)

DSH(DeepSeek Harness)大会话性能插件:零拷贝 fork、投影分片预热、分片 materialize, 一次装齐,消除 fork/历史加载对超大会话的事件循环阻塞。

> ⚠️ 版本兼容性警告:本插件通过 monkey-patch dsh 内部方法实现(SessionStore.fork、 > PersistenceCoordinator.initForJsonlSessionPersistence.encodeMaterialization、 > SessionPreparations 等),与 dsh 版本高度耦合,当前针对 0.1.0-rc.6 / rc.7 / rc.8 > / 0.1.1-rc.1 开发并验证(rc.7 逐一核对无结构变化;rc.8 仅一处变更且是上游原生 > 实现了插件的 fastInitFor 优化——initFor 的 seed 从 structuredClone 深拷贝改为 > 直接引用 session.events,插件该补丁在 rc.8 起预期退役0.1.1-rc.1 发布说明 > 无插件相关改动,结构断言与全套测试全过)。 > dsh 升级后这些内部方法签名可能变化——所有补丁都带源码特征校验,不匹配时自动跳过 > 优化并回退官方行为(不会导致崩溃),但优化会静默失效。 > > 运行时版本探针:插件启动时自动探测 dsh 实际版本——已知版本(rc.6/rc.7/rc.8/0.1.1-rc.1)打 > dsh version: x.y.z (verified),列表外版本打告警并提示跑 tests/verify_compat.mjs。 > 版本也经 stats.get 暴露(value.dshVersion)。升级 dsh 后请确认启动日志无告警 > 与 signature mismatch,必要时重新适配本插件。

> ⚠️ 能力边界(重要):本插件只能缓解超大对话的性能/内存问题(分片、零拷贝、 > LRU 裁剪、预热等),无法彻底解决。根本原因在 dsh 的架构——live 会话事件树全量 > 驻留内存(每个超大会话 ~700MB)、历史加载全量解码 + 逐事件深拷贝。这些是上游架构 > 问题,插件 monkey-patch 触及不到。真正的根治依赖 dsh 上游支持事件分页加载/按需驻留, > 或主动控制会话规模(见下文「避免超长对话」)。

问题

dsh 0.1.0-rc.6 在大会话(数十万事件)上存在三类同步阻塞,导致 fork 卡顿、 历史加载报 signal timed out (internal)、严重时 OOM:

问题环节实测
A. fork 深拷贝Session 构造器逐事件 snapshotJsonValue(纯 JS 深拷贝)+ persistence initForstructuredClone(seed)18.2MB/20k 事件合计 ~480ms 同步阻塞(rc.8 已原生消除其中 initFor 那次,构造器深拷贝仍在)
B. projection 冷折叠SessionProjectionRegistry.cellFor() 冷时同步 buildCell 全量折叠74 万事件冷折叠阻塞 20+ 分钟(100% 单核)
C. fork 全量序列化fork 子会话首次落盘 encodeMaterializationeventLines = map(JSON.stringify).join("\n") 一次性序列化整个 seed60 万事件 = 501MB 单字符串;74 万事件直接 RangeError: Invalid string length

为什么「单个会话没事、fork 后出事」:普通会话持久化走增量 appendLines (每次序列化几十个事件),而 fork 子会话是全新 id,走 materialize 全量序列化 整个 seed——这是唯一会一次性序列化整条日志的路径。

rc.7 / rc.8 上游修了什么(为什么根因仍在)

rc.7:「修复大历史消息分页栈溢出」(commit 5201b848,PR #1371)。 session.history 分页时用 Math.min(event.seq, ...sourceEventSeqs) 展开溯源数组—— 一条定稿的 assistant 消息可以通过 sourceEventSeqs 引用数十万个流式分片, 展开超出 JS 引擎函数参数上限(~65535),历史分页请求直接 HTTP 500。修复改为循环 逐项扫描取最小 seq(复杂度仍线性),分页语义不变。上游问题笔记明确声明「本决策 不限制历史记录页面的字节大小,也不限制浏览器回放该页面的开销」——这是 api-proxy 层对已全量解码事件列表的切片逻辑,历史加载全量解码 + 逐事件深拷贝、live 事件树 全量驻留等根因一个都没碰。

rc.8:「改善大历史会话执行分叉操作上的性能耗时」——落实在 PersistenceCoordinator.initFor:seed 从 session.events.map((e) => structuredClone(e)) 改为直接引用 session.events上游原生实现了本插件的 fastInitFor 优化,连插件 补丁的 slice() 都比它多一次拷贝)。另「改善 SQLite 后端读写与分叉性能并降低存储 体积,数据结构不兼容」在 dsh-session-query-sqlite(插件不涉及 SQLite 后端,无影响)。 注意:这只消除了 A 类的一半——fork 流程的两个深拷贝里,initFor 那次被上游 原生消除(fastInitFor 补丁退役),但 fork 构造器逐事件的 snapshotJsonValue 深拷贝 仍在(rc.8 源码核实),它正是 zeroCopyFork 补丁走 fromRestore 通道绕过的核心, 在 rc.8 上仍然必要。B/C 类(投影冷折叠、fork 全量序列化)与历史加载的根因同样仍在, 插件继续兜底。

两版修复都是「可用性 / 单一热点」层面,未触碰架构根因:历史加载仍是 zstd 全量解码 + 逐事件深拷贝,live 会话事件树仍全量驻留(~700MB/会话)。根治仍依赖上游做事件 流式解码与按需驻留(另见「能力边界」与「避免超长对话」)。

方案

1. 零拷贝 forkzeroCopyFork,A):fork 的 seed 事件本就是 deepFreeze 不可变纯 JSON 树。补丁改走 Session.prepare(..., { seedSource: 'persistence' })fromRestore 通道——原地冻结复用引用,跳过整树深拷贝(346ms → 19ms)。 子会话 header(parentSession/seedLength/cwd)与官方 fork 逐字段一致。 rc.8 起仍必要:上游只原生消除了 initFor 那次拷贝,fork 构造器的 snapshotJsonValue 深拷贝依旧存在(rc.8 源码核实)。 2. fast init-forfastInitFor,A):PersistenceCoordinator.initFor 里那次 structuredClone(seed) 替换为冻结引用复用(135ms → ~0ms)。带 rc.6 源码特征 校验(structuredClone(e) 标记),内部结构不匹配时自动跳过并告警。rc.8 起上游 已原生实现(const seed = session.events),补丁预期退役——特征缺失但检测到 上游零拷贝形态时打 info 说明,不再误报漂移。 3. 投影分片预热warmupEnabled,B):会话进入(created/resume)且事件数超过 阈值时,抢在首次同步冷折叠前,分片重放 cells——每 chunkSize 个事件 setImmediate 让出事件循环,折叠完成后直写 registration.cells(WeakMap), 此后 snapshot()/drive() 全部命中热 cell。可用时从投影缓存行取基线跳过已折叠 前缀。实测 74 万事件:冷折叠 20 分钟 → 预热 200ms。 4. fork 缓存回填(B,随预热自动执行):fork 子会话(header.parentSession 存在) 预热完成后立即 cache.write(child) 建立投影缓存行——否则它被放弃时永远没有 缓存行,下次打开历史 coldSnapshotreadFrom(0) 全量读。 5. 分片 materializechunkedMaterialize,C):encodeMaterializationmaterializeChunkEvents 个事件一个 zstd frame(多帧是 dsh 解码端 scanZstdFrames 的原生格式,字节兼容),消除单巨字符串与 RangeError。 6. 冷会话补行backfillOnBoot,B 辅助,默认关):磁盘缺缓存行的大会话流式 补写。默认关的原因:readRaw 的 zstd 全量解码是同步的、插件层不可分片, 大文件仍会冻结事件循环数秒~数十秒。 7. 冷会话 LRU 裁剪preparedCacheTrim/preparedCacheSize,D):persistence 的冷会话 LRU 默认缓存 5 个完整事件树(每个大会话 ~700MB,5×700MB 叠加是 OOM 主因之一)。插件运行时把容量降到 preparedCacheSize(默认 1)并淘汰最旧的 ready 条目,主动释放冷会话事件树——省 ~2.8GB。无需手动改 cordis.patch.ymlconfig.set 运行时改这两个键即时生效;dispose 恢复原 capacity(已淘汰条目 不复活)。 8. heap 上限检测heapWarnBytes,D):--max-old-space-size 是 V8 启动期 参数、进程内改不了。插件检测 heap 上限低于阈值(默认 6GB)时告警,并引导用 scripts/start-dsh.ps1(内置 --max-old-space-size=8192)重启。

安全性

  • 共享引用等价于深拷贝:事件在进入源会话时已通过完整 JSON 边界与 surface 验证并

深冻结,任何代码都无法修改。

  • 所有补丁带 rc.6 源码特征校验,内部结构不符自动跳过并告警,绝不盲补。
  • 三层回退:(a) 调用时能力探测缺失 → 官方实现;(b) 补丁内运行时异常 → try/catch

回退官方实现;(c) 配置开关 → 永远官方路径。

  • dispose 完整还原所有补丁(冷会话 LRU 裁剪恢复 capacity 原值,已淘汰的缓存

条目不复活)。

安装

# 从 GitHub 安装(推荐)
dsh plugin --profile web add github:orangeofcarl0-sys/dsh-large-proj-perf
# 或
dsh plugin --profile web add https://github.com/orangeofcarl0-sys/dsh-large-proj-perf

# 本地开发
dsh plugin --profile web add file:<本仓库路径>

> 注意:每次修改仓库代码后,需把 lib/cordis.patch.ymlpackage.json > 同步到 <DSH_HOME>/profiles/web/node_modules/dsh-large-proj-perf/file: 安装 > 不会自动跟随源文件更新),或重新执行 dsh plugin add

重启 dsh web 生效。日志出现 [dsh-perf] installed (...) 即成功。

> 环境要求:Node ≥ 22.15.0node:zlib 的 zstd 接口所需,低版本加载插件 > 会直接失败)。package.json 已声明 engines

大会话内存(推荐启动方式)

多个超大会话(数十万事件)的 live 事件树每个 ~700MB,默认 V8 heap 上限 ~4GB 会让 dsh 在内存叠加时 OOM。插件已自动做冷会话 LRU 裁剪(省 ~2.8GB),但 heap 上限是 V8 启动期参数、进程内改不了,推荐用仓库自带脚本启动:

powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\start-dsh.ps1

它等价于 node --max-old-space-size=8192 .../dsh/lib/bin.js web(停止旧进程 → 重启 → 打开浏览器)。若不使用该脚本,插件启动时会打 V8 heap limit ... < ... 告警提醒你加参数。

避免超长对话(主动规避)

本插件做的是「被动优化」——把 fork/历史加载/落盘的大会话阻塞降下来,但无法削减 正在使用的 live 会话事件树(每个 ~700MB,dsh 架构决定全量驻留)。要从根上避免 超长对话的内存/卡顿,推荐配套使用:

输入 /fresh 一键「总结当前对话 → 开启新对话 → 归档老对话」。在一个会话工作 一段时间后用它归档,释放 live 事件树内存,而不是让会话无限增长到 70 万+ 事件。

dsh plugin --profile web add github:orangeofcarl0-sys/dsh-fresh-start

两者配合:dsh-large-proj-perf 兜底性能,dsh-fresh-start 主动控制会话规模。

API

POST http://127.0.0.1:3080/dsh-large-proj-perf/api/<method>

  • stats.get — dsh 版本探针(dshVersion)、fork 次数/零拷贝占比/回退、

预热计数、补行计数、最近记录

  • stats.reset — 清零
  • config.get / config.set — 运行时开关,config.set 同时写 settings 持久化;

数值项带下限钳制(如 materializeChunkEvents ≥ 1000chunkSize ≥ 1), 非法值(类型不符/NaN/低于下限取下限)被拒绝或收敛,不会进入危险区间

curl -X POST http://127.0.0.1:3080/dsh-large-proj-perf/api/stats.get
curl -X POST http://127.0.0.1:3080/dsh-large-proj-perf/api/config.set \
  -d '{"zeroCopyFork": false}'

验证

测试依赖真实的 dsh 内部包(@deepseek-ai/dsh-session 等),它们不在本仓库依赖里, 而是全局 dsh 安装的嵌套依赖,Node 解析不到。先链接再跑:

powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\link-deps.ps1
npm test   # 或单独跑:node tests/smoke_fork.mjs
  • tests/smoke_fork.mjs(17 断言):官方 fork 基线 / 零拷贝 fork 功能等价 /

header 平价(含 origin 不继承)/ seed 前缀逐字节等价 / dispose 还原 / 版本漂移回退 —— ALL PASS

  • tests/test_fast_initfor.mjs(10 断言):initFor 补丁安装 / 源码特征漂移跳过 /

无 persistence 服务存活 / rc.8 上游原生零拷贝形态 → 补丁预期退役(不误报)—— ALL PASS

  • tests/smoke_warmup.mjs(11 断言):分片预热与同步折叠一致 / checkpoint 基线 /

并发 drive 让位 / dispose 中止 —— ALL PASS

  • tests/test_backfill.mjs(8 断言):fork 回填 / 磁盘冷会话补行 —— ALL PASS
  • tests/test_chunked_materialize.mjs(5 断言):分片多帧解码等价 / 阈值不变 —— ALL PASS
  • tests/test_cache_trim.mjs(18 断言):LRU 裁剪 / dispose 恢复 capacity / 运行时

开关 / config.set 数值钳制 / 版本探针(stats.get 暴露 dshVersion)—— ALL PASS

  • tests/verify_compat.mjs(16 断言):对真实安装的 dsh 源码做特征断言——

fork/initFor/encodeMaterialization/toHeaderLine 字段集/SessionPreparations/ 投影注册表与缓存接口/packChunkRuns 导出;版本不在已知列表时打 WARN

局限

  • 版本高度耦合(重要):补丁绑定 dsh 内部结构(_forkSeed

initFor/encodeMaterialization 源码特征、SessionPreparations.capacity 等)。 已在 0.1.0-rc.6 / rc.7 / rc.8 / 0.1.1-rc.1 上验证;dsh 升级后,特征校验会自动跳过优化并 回退官方行为(不崩溃、不误补),但优化会静默失效——升级后务必跑 node tests/verify_compat.mjs(或确认启动日志无 signature mismatch),并按需 重新适配。本插件不适合在 dsh 版本频繁变动时依赖其优化。

  • enqueue 的逐事件 structuredClone(fork 第三次拷贝)在插件层无法安全消除——

它在 write-behind 闭包内部,且承担"persistence 独立于生产者"的所有权语义。根治需 上游改为按需快照。

  • 冷会话 coldSnapshot 的全量 readFrom(0)(zstd 解码 + 逐事件

snapshotStoredEvents 深拷贝)无法在插件层安全分片——readRaw 的同步解码是硬伤。 根治需上游把 readFromCore/loadStored 改成分片让出事件循环。

  • 超大会话(70 万+ 事件)加载本身有内存 OOM 风险,与插件无关;建议配合

dsh-fresh-start 主动归档。