用 dsh-tool-diff 给 DeepSeek Harness 装上结构化差异比较

前言

智能体要对比两份内容时,常见路径是起一个 bash 进程去调系统 diff,或者自己写一段比较逻辑。配置片段、API 响应、表格、文档修订都经常碰到这件事。系统 diff 只看整段文本:JSON 里改了 $.user.name,输出往往是大块加减行,看不出路径;CSV 引号里的逗号、Markdown 标题改名,手写比较又容易漏。Windows 上每次起进程的开销也更明显。

DeepSeek Harness(dsh)把模型、工具、会话和界面都做成插件,官方仓库的说法是 Everything is a Plugin(一切皆插件)。社区因此补了一批给模型调用的确定性工具。dsh-tool-diff 做的事情很具体:在进程内对文本、JSON、CSV、Markdown 做结构化比较,输出 unified diff 或带路径的变更列表,不读盘、不写盘、不联网。

需要先分清来源。DeepSeek Harness 本体在 deepseek-ai/deepseek-harnessdeepseek-harness-plugin.com 是独立的社区插件目录,About 页写明与 DeepSeek / 幻方没有官方从属关系,不能当成官方应用商店。本文按目录详情页、GitHub 仓库 README / package.json / LICENSE,以及官方 Harness 仓库交叉核对,核实日期为 2026-08-18

这是什么

dsh-tool-diff 是一款「工具与能力」插件,由 GitHub 组织 omdsh-dev 维护,源码在 omdsh-dev/dsh-tool-diff,许可证 MIT,主要语言 TypeScript。查阅时目录页与 GitHub 均显示 4 星;package.json 里的包名是 @deepseek-ai/dsh-tool-diff,版本 0.0.1,并标了 "private": true,安装走 GitHub 源,不是公开 npm 包。engines 要求 Node.js ^22.19.0 || >=24.0.0

它向模型注册名为 diff 的工具,profile 里的 row id 是 tool-diff。输入是两段字符串 before / after,按 action 走不同比较器,统一吐出一段 JSON 文本信封。仓库 README 把定位写成:零依赖、纯函数、只读。

它要解决的是这三类麻烦:

  • 不要为一次比较再起系统进程
  • 让 JSON / CSV / Markdown 的变更落到路径或行列上,而不只是整段文本 diff
  • 比较逻辑可复现、有边界:输入超限直接报错,输出超限截断并置 truncated

README 写明已在 @deepseek-ai/dsh@0.1.0-rc.6 的隔离 consumer 里做过全链路验证:配置 dump 能看到该插件 row,工具能注册并执行。这是仓库自己的验证记录,不是第三方评测。

核心功能

安装后只有一个工具:diff。用 action 区分五种比较,所有 action 的信封都带 { equal, truncated, beforeBytes, afterBytes, changes }

action 作用 输出要点
text 行级 Myers diff 默认 unified diff(--- before / +++ after / @@ hunk,无时间戳)加统计;format=structured 则给带行号的操作列表
json 递归比较两个 JSON 值 $ 路径化变更,如 $.user.name$.items[0]$['a.b'],并汇总 add / remove / replace
csv 按 RFC 4180 解析后再比 addedRows / removedRows / changedRows(列级)/ duplicateKeys / 列集合变化
markdown 轻量块级 tokenizer headingChanges(含 rename)/ blockChanges(如 h2[1]/p[0])/ codeBlockChanges,外加全文 diff
patch 生成 unified diff 并在内存中校验 patch 文本 + valid / hunks / targetMatchesAfter / hunk 级错误

常用参数如下,均来自仓库 README:

  • before / after:两侧内容,任意 action 都要给
  • formatunified(text / patch 默认)、structured(json / csv / markdown 默认)、both
  • context:unified 上下文行数,默认 3,范围 0..20
  • key:CSV 主键列名或从 1 起的列号;不给就按行号位置比较
  • delimiter:CSV 分隔符,默认 ,,也可写 tab
  • ignoreWhitespace / ignoreCase:比较时忽略空白或大小写;patch 会拒绝这两个选项,因为补丁必须是精确文本协议
  • sortKeys:JSON 键排序,默认 true,让变更列表稳定
  • maxChanges:最多报告多少条变更,默认 1000,硬顶 10000

安全模型是这条插件的重点,README 写得很死:

  • 零依赖:Myers 行级 diff、RFC 4180 解析、JSON 递归比较都是手写实现,不拉第三方比较库
  • 只读:不读文件、不写文件、不联网、不调 git;patch 只在内存里生成并校验补丁,绝不落盘
  • 预算:单侧输入 ≤ 256 KiB(超限直接报错);输出 ≤ 64 KiB(超限按 maxChanges 和字节预算截断,并置 truncated);行数 ≤ 50K;JSON 嵌套 ≤ 64 层;CSV ≤ 50K 行 / 512 列;timeoutMs: 2000
  • Myers 还有 diagonal 预算 2000、蛇步总预算 2000 万、公共前后缀修剪和 4000 行规模上限,避免恶意重复或全异文本把进程拖死
  • 工具参数会记入会话日志,不要把密钥、token 这类敏感数据当作 before / after 传进去

设计上还有几条边界,用的时候会对上输出:

  • CSV 给了 key 且有表头,就按主键比,行顺序无关;否则按数据行号。两侧重复 key 都进 duplicateKeys,且 equal=false,这些行不参与匹配
  • JSON 在 JSON.parse 前先做非递归括号扫描,超过 64 层直接报错;重复键由状态机扫出来,写进 duplicateKeys.before/after,不会静默丢掉
  • Markdown 按块类型做 Myers:同型块内容变化是 replace,结构增删是 add/remove;同路径同级别标题文本变化记为 rename
  • patchequal 只表示两侧在精确行和末尾换行语义下相等,和 valid 无关;valid 只表示生成的 patch 能从 before 应用到 after。补丁被截断时是 valid:falsepatchComplete:false
  • 入口会拒绝孤立 surrogate,报 invalid Unicode
  • unified diff 不带时间戳,方便复现

仓库 README 写明测试用 vitest,当前有 124 个用例。peer 依赖是 @deepseek-ai/cordis ^4.0.1@deepseek-ai/dsh-tools@deepseek-ai/dsh-invariants>=0.0.1-rc.1 <0.2.0),由 profile 的 profiles/node_modules 回退安装提供,插件自身不再依赖未加 scope 的 cordis

安装与启用

目录页给出的安装命令如下,在 DeepSeek Harness 终端里运行即可:

dsh plugin add github:omdsh-dev/dsh-tool-diff

目录页同时写了:插件以当前 dsh 进程的权限运行,安装时可能执行代码。安装前请检查源代码仓库和许可证;需要可复现安装时,固定 commit 哈希。写法是把 #commit 换成仓库里的完整哈希。查阅时 main 最新提交是 73c142e262275c5a278dc31e80bac7966fba168e(2026-08-14):

dsh plugin add github:omdsh-dev/dsh-tool-diff#73c142e262275c5a278dc31e80bac7966fba168e

仓库 README 推荐按 profile 安装。web 是交互式界面,headless 给 dsh run 用,两者互不覆盖:

# 交互式(web)profile
dsh plugin --profile web add github:omdsh-dev/dsh-tool-diff

# 一次性任务(headless)profile —— dsh run 默认使用 headless
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-diff

也可以先 npm pack 再装本地 tarball:

git clone https://github.com/omdsh-dev/dsh-tool-diff
cd dsh-tool-diff
npm install && npm pack
dsh plugin --profile web add ./deepseek-ai-dsh-tool-diff-*.tgz
dsh plugin --profile headless add ./deepseek-ai-dsh-tool-diff-*.tgz

包内 dsh.bundle.patch(对应仓库里的 cordis.patch.yml)会在安装后把插件插入 profile 的 layer stack,id 为 tool-diff。Windows 路径要用正斜杠,例如 C:/...

验证安装:

dsh --profile web --dump-config | grep tool-diff

README 给的运行验证句是:

dsh run "使用 diff 工具对比两段文本"

注意:dsh run 默认走 headless。只装了 web、没装 headless 时,这条命令看不到工具。README 还提示启动用 npx -p @deepseek-ai/dsh@0.1.0-rc.6 dsh web,不要 npm install -g 全局安装。手动改 profile 层、本地 junction / symlink 只适用于源码贡献或旧 snapshot,日常安装用上面的 bundle 即可。

典型用法

装好之后,模型调用 diff,把 actionbeforeafter 传进去。仓库没有再给一套逐步点击的界面教程,下面的输出和验证句都直接来自 README。

1. JSON 路径级变更

action=json 时,默认 format=structured。README 的示例信封如下:

{"kind":"json","equal":false,"beforeBytes":42,"afterBytes":58,"changes":[
  {"op":"replace","path":"$.tags[1]","before":"b","after":"c"},
  {"op":"add","path":"$.user.email","after":"b@x.com"},
  {"op":"replace","path":"$.user.name","before":"Alice","after":"Bob"}],
 "summary":{"added":1,"removed":0,"replaced":2,"moved":0}}

对照这份输出可以读出三件事:$.tags 数组第 1 项从 b 换成 c$.user 下新增 emailname 从 Alice 换成 Bob。系统 diff 通常只会给你前后两段 JSON 的行级加减,不会给出这些路径。

sortKeys 默认打开,同一组变更的列表顺序稳定,方便写断言或把结果再交给后续步骤。

2. 文本 unified diff

action=text 默认 format=unified。输出是标准 unified diff,文件头固定写成 --- before / +++ after,hunk 带 @@,没有时间戳。需要给模型看「第几行发生了什么」时,把 format 改成 structured。上下文行数用 context 控制,默认 3 行。

只关心逻辑是否相同、空格和大小写可以忽略时,打开 ignoreWhitespaceignoreCase。这两个开关对 text / csv / markdown 有效;patch 会拒绝,不要混用。

3. CSV、Markdown 和内存补丁

表格对齐用 action=csv。有稳定主键(例如 id 列)时把 key 设成列名,行被打乱也能对上;没有主键就按行号比。分隔符不是逗号时改 delimiter,制表符写 tab

文档修订用 action=markdown。它先按标题、代码块、列表、引用、表格切成块,再做块级 Myers:标题改名会进 headingChanges 的 rename,代码块的语言、行数或内容变化进 codeBlockChanges

需要一张能从 before 应用到 after 的补丁、但又不想改磁盘文件时,用 action=patch。返回值里看 validhunks;被输出预算截断时不要拿这份 patch 当真补丁。README 明确写了:补丁只在内存中生成和校验,不会落盘,也不会调用 git。

日常冒烟可以用仓库给的这一句,确认工具已注册:

dsh run "使用 diff 工具对比两段文本"

适用场景与注意事项

适合这些情况:

  • 智能体要对比配置片段、API 响应、CSV 导出或 Markdown 文档,需要路径 / 行列级变更,而不是整段文本 diff
  • 希望比较发生在 dsh 进程内,不额外起 diff / git 子进程
  • 需要 unified diff 或内存中的 patch 校验,但不允许插件改工作区文件

使用时注意下面几条,都来自目录页或仓库 README,不是额外发挥:

  1. 先看源码和许可证再装。 目录页写明:插件以当前 dsh 进程的权限运行,安装时可能执行代码。本插件自称只读,仍应按第三方代码对待。
  2. 社区目录不等于官方商店。 deepseek-harness-plugin.com 是独立站点,与 DeepSeek / 幻方无从属关系。
  3. web 和 headless 要分别装。 只给 web 装,dsh run 默认的 headless profile 里没有这个工具。
  4. 输入输出都有硬顶。 单侧超过 256 KiB 会直接失败;输出超过 64 KiB 会截断。大文件应先自己切片,不要指望一次塞进工具。
  5. 不要传入敏感数据。 参数会进会话日志。
  6. patch 不是落盘补丁工具。 它不写文件、不调 git;ignoreWhitespace / ignoreCase 也不能用在 patch 上。
  7. 运行时版本。 README 验证线是 @deepseek-ai/dsh@0.1.0-rc.6package.json 要求 Node.js 22.19+ 或 24+。更旧的 snapshot 可能要走仓库说的手动安装路径。
  8. 包名带 @deepseek-ai/,并不表示官方插件。 这是社区仓库 omdsh-dev/dsh-tool-diff 的 npm 包名,且 private: true

小结

dsh-tool-diff 给 DeepSeek Harness 注册了一个只读的 diff 工具:文本走 Myers 行级比较,JSON 给出 $ 路径,CSV 按主键或位置对齐,Markdown 按块对齐,需要时再在内存里生成并校验 unified patch。比较逻辑零依赖、有输入输出预算,不碰磁盘和网络。对经常让智能体核对配置、接口返回和文档修订的人来说,它补的是「系统 diff 看不懂结构、手写比较又难验证」这一截。

目录页与源码:

  • 插件目录:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-tool-diff/
  • GitHub 仓库:https://github.com/omdsh-dev/dsh-tool-diff
  • DeepSeek Harness 官方仓库:https://github.com/deepseek-ai/deepseek-harness
羽毛球分组比赛记分
小程序二维码

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

小夜