dsh 更新后怎么验证有没有生效?DeepSeek Harness 升级顺序与回归验证清单
dsh 更新要做对两件事:顺序(先本体、后插件,一次只动一类)和验证(升级前拍版本快照,升级后跑同一条最小回归路径)。 少了任一件,升级成功与升级引入的故障就分不开——尤其版本漂移这类只在升级后才出现的崩溃,靠「能启动」是查不出来的。
dsh 更新三步概览:快照、升级顺序、回归
把 dsh 更新当成一次有前后对照的操作,而不是敲一条命令看它跑完。 三步各自不可省(来源):
| 阶段 | 做什么 | 少了它会怎样 |
|---|---|---|
| 升级前 | 记录版本快照 + 备份数据目录 | 回归失败时没有对照基准,也说不清哪层变了 |
| 升级中 | 先本体、后插件,一次只动一类 | 出问题时无法归因,容易反复重装 |
| 升级后 | 跑固定四步回归 | 「能启动」被当成「升级成功」,缺陷留到干活时才炸 |
三步里最容易被跳过的是第一步和第三步。命令细节(npx 自动 / npm update -g / git pull 三条路)已经单独写过,见《dsh 怎么更新》;本文只讲顺序与验证。
第一步:dsh 更新前拍一份版本快照
快照的价值在于「升级后能逐项对照」,所以记的是三层版本,不是只记本体版本。
- 记本体版本:
dsh --version # 全局安装
npx @deepseek-ai/dsh --version # npx 方式
预期:拿到一个明确版本号,作为回退目标; 2. 记 profile 内的版本清单:
dsh plugin --profile web list
预期:输出当前 profile 的插件包名与版本,这是插件侧的回退目标(来源); 3. 备份数据目录(含配置、会话与插件清单):
cp -r ~/.dsh ~/.dsh.backup-$(date +%Y%m%d)
预期:出现备份目录,出问题时有退路; 4. 把快照存成一处文本 —— 把上面两条命令的输出粘进一个文件。预期:升级后不必靠记忆对比。
第二步:dsh 更新顺序——先本体,后插件
顺序规则只有一条:一次只动一类。 按三步走:
- 先升本体:按你当初的安装方式执行(npx 方式每次运行即最新、全局安装
npm update -g @deepseek-ai/dsh、源码git pull后重新构建); - 重启并确认进程真的换了:更新改的是磁盘上的包,已在跑的进程仍持有旧代码。预期:重启后
dsh --version显示新版本;仍显示旧版时按《dsh 更新了版本没变》排 PATH 与缓存,别在这时继续叠加插件更新; - 确认本体回归通过后,再升插件:
dsh plugin --profile web update(只升一个插件就带包名)。预期:插件升级是本轮唯一的变化,出了事直接指向插件侧。
为什么不能一起升:本体升级引入的问题与插件升级引入的问题症状高度相似(功能消失、加载报错、工具异常),两类同时变,就只能靠逐个回退来二分,代价远高于分两次做。批量更新的命令与注意事项见《DSH plugin 怎么批量更新》。
第三步:dsh 更新后跑四步回归
回归路径要固定,每一步都有一句可验证的预期——四步全过才算升级完成。
- 服务能起来 —— 启动后打开
http://127.0.0.1:3080,或直接探活:
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3080/
预期:页面打得开、返回 HTTP 200;起不来按端口占用与启动失败排查;
2. 模型能回 —— 在会话里发一条不含工具的短消息。预期:正常拿到回复,说明模型与 provider 链路健康(这一步是后面判断「是不是工具层问题」的基线);
3. 工具能跑 —— 让它读一个工作区文件,或执行一条简单的命令。预期:tool/call 有配对的 tool/result,没有报错。这一步是升级回归的关键点:工具分发层的故障常常只在工具调用时才暴露,纯文本回合完全正常(讨论原文);
4. 插件在位 —— 打开「设置 → 插件市场 → 已安装」核对插件仍在、版本与快照对得上;再确认它进了生效层:
dsh --profile web --dump-config | grep -n "^# =="
预期:生效层里仍能看到该插件,层数与升级前一致;插件消失或层数变化,说明升级动到了组合配置。
dsh 更新后才出现的次生故障:版本漂移
有一类崩溃只在升级后才出现,且症状与「更新没生效」完全不像:纯文本正常,一调工具就崩(来源)。 典型表现与判定:
- 症状:报错固定为
Cannot read properties of undefined (reading 'prepare'),出现在工具调用之后;会话日志里tool/call后面从未写出tool/result,且连续多个 turn 复现; - 根因:第三方插件把核心包
@deepseek-ai/dsh-tools声明成直接依赖,profile 里因此解析出一份旧版核心包副本;而调度器键是普通Symbol()而非Symbol.for(),两份副本的键永远不相等,跨份读取就是undefined(根因确认); - 判定方法:对比本体与 profile 内的核心包版本——不一致即漂移:
dsh --version
ls ~/.dsh/profiles/<name>/node_modules/@deepseek-ai/
- 恢复顺序:禁用可疑第三方插件 → 移走 profile 内漂移的核心包副本 → 重启后用新会话验证工具调用。崩溃 turn 遗留的
tool_calls没有结果,旧会话可能被提供方以 400INVALID_REQUEST拒绝,别在同一会话里反复重试。
完整的二分禁用与逐包核对流程见《核心包版本漂移排查》、静态重复副本走《插件重复核心包排查》。这类故障正好说明第三步回归里「让它跑一次工具」不能省——省了它,你会以为升级很成功。
dsh 回归不通过时:单变量回退
回退的原则和升级一样——一次只动一层,把变化量压到最小(来源)。
- 先看快照定位变化层:只有本体版本变了,就先钉回本体旧版本(
npx @deepseek-ai/dsh@<旧版本> web,或源码版git checkout <旧 commit>后重新构建); - 只有某个插件变了,就单独钉回它:
dsh plugin --profile web add <包名>@<旧版本>,其余插件保持不动; - 别同时回退本体和插件:那样等于把问题重新盖住,下次升级还会复发;
- 留下现场再动手:会话日志与
--dump-config输出各留一份,回退后才说得清是哪一层的问题。
回滚与降级的完整做法见《更新后不兼容与版本回滚》。
不想手工对快照:用 DSH Plugin Hub 界面核对版本与状态
把「升级前看版本、升级后看状态」交给界面,比手工比命令输出更省事(来源)。 装好 DSH Plugin Hub 后,「设置 → 插件市场 → 已安装」会列出每个 DSH插件的当前版本与「可更新」徽标,升级前先扫一眼就是一份现成的快照;点更新时会先弹出确认窗口,把要执行的操作与你确认一遍。

升级确认弹窗把「改哪个插件、从哪个版本到哪个版本」摆在一次确认里,比事后回翻终端输出更容易对照快照。访问 https://dsh-plugin.org/zh/ 即可了解详情。
注意事项:dsh 更新的五条硬约束
这五条是让 dsh 更新可归因、可回退的前提,少一条下次故障就说不清原因(来源)。
- 顺序别省:先本体、后插件,一次只动一类——这是让回退能归因的唯一前提。
- 快照别省:本体版本、profile 插件清单、数据目录备份,三样齐全才有对照基准。
- 回归里必须跑一次工具:只确认「能启动」会漏掉整个工具分发层的问题。
- 升级后崩溃先怀疑版本漂移:纯文本正常、工具一调就崩、报错里有
prepare,直接走漂移排查。 - 回退保持单变量:同时回退本体与插件,等于放弃了这次排查的全部信息。
来源:dsh CLI README、官方 Quickstart、Discussion #4601、Discussion #4529
常见问题
dsh 更新要先升本体、后升插件,而且一次只动一类。DSH 本体与 DSH plugin 走两套完全不同的命令,出问题时必须能归因到「只有一类变了」;在本体与插件之间夹一次批量更新,会让回归失败时无法判断是谁引入的。
dsh 更新后按四步回归:服务能起来(页面在 127.0.0.1:3080 打得开)、模型能回(发一条最短消息拿到回复)、工具能跑(读一个文件或执行一条命令)、插件在位(已安装列表与生效层里仍能对上)。四步都过才算升级完成。
dsh 升级前要记三项版本信息:本体版本(dsh --version 或 npx @deepseek-ai/dsh --version)、profile 里的核心包与插件版本(dsh plugin --profile <name> list,或进 profile 目录用 pnpm list)、以及数据目录备份。有了这三项,回归失败时才能判断到底哪一层变了。
dsh 更新后工具调用崩溃报 reading 'prepare',只要升级前没有、升级后每次调用都崩,就该按版本漂移排查。根因是第三方插件把核心包声明为直接依赖,profile 解析到旧版核心包,而调度器键是普通 Symbol(),跨两份副本永远不相等,读取结果就是 undefined;禁用可疑插件并清掉副本即可恢复。
dsh 回归不通过时用单变量原则:一次只回退一类,先看快照里哪一层变了——只有本体变了就先钉回本体旧版本;只有某个插件变了就把它单独钉回旧版本。别同时回退本体和插件,那样等于把问题重新盖住,下次还会复发。
相关术语
- 版本快照
- 版本快照是升级前记录的本体版本、profile 内核心包与插件版本清单。它是升级后回归失败时的对照基准,用来判断「哪一层变了」,也是回退时的目标版本来源。— dsh CLI README
- 回归验证
- 回归验证是升级后按固定的最小路径重跑一遍关键能力——起服务、发消息、跑工具、查插件,确认升级没有破坏原有行为。路径要固定,才能和升级前的状态逐项对照。— DeepSeek Harness 官方文档 - Quickstart
- 版本漂移
- 版本漂移指插件把核心包声明为直接依赖后,profile 里解析出一份旧版核心包副本,与本体自带的那份并存。由于调度器键是普通 Symbol(),两份副本的键不相等,导致工具调用时读取失败并崩溃。— deepseek-harness Discussion #4601
- 单变量回退
- 单变量回退指回退时一次只改一层——只回退本体,或只回退一个插件——把变化量压到最小,这样下一次回归的结果才能明确指向原因,而不是被新的变量污染。— dsh CLI README
来源
- dsh CLI README· deepseek-ai
- DeepSeek Harness 官方文档 - Quickstart· deepseek-harness
- deepseek-harness Discussion #4601:工具调用后崩溃 reading 'prepare',禁用第三方插件后恢复· deepseek-ai(GitHub Discussions)
- deepseek-harness Discussion #4529:TOOL_RUNTIME_SCHEDULER 为普通 Symbol() 的根因确认· deepseek-ai(GitHub Discussions)
- dshplugin/dsh-plugin-hub GitHub 仓库· GitHub