用 dsh-tool-json 在 DeepSeek Harness 里按路径查询 JSON

前言

DeepSeek Harness(命令名 dsh)是 DeepSeek AI 开源的智能体运行时,目前仍是开发者预览。官方仓库 deepseek-ai/deepseek-harness 写明核心理念是「一切皆插件」:模型、工具、技能、会话、沙箱和界面都可以在配置层替换,不必改核心源码。社区里还有一份独立的插件目录站点 deepseek-harness-plugin.com,它和 DeepSeek / 幻方没有官方从属关系,不能当成官方应用商店。

智能体处理 JSON 是高频操作。API 返回值、配置文件、其他工具的输出,几乎都是 JSON。常见做法是起一个 bash 进程去跑 node -ejq,每次都有进程开销,还要把对象先序列化成字符串。DSH 内置的 grep 可以做正则匹配,但不理解 JSON 结构。对 {"items":[{"id":1}]} 这种数据,字符串搜索很容易把值、键名,以及嵌套对象里的同名键混在一起。

社区插件 dsh-tool-json 做的事情比较克制:给当前 profile 注册一个名为 json 的工具,用 JMESPath 风格的路径子集做结构化查询。解析器是手写的递归下降实现,不依赖第三方查询库。本文按插件目录页、GitHub 仓库 README / package.json / 源码,以及 DeepSeek Harness 官方仓库交叉核对后整理。

这是什么

dsh-tool-json 是一款面向 DeepSeek Harness 的「工具与能力」插件,由 GitHub 组织 omdsh-dev 维护,仓库地址是 omdsh-dev/dsh-tool-json。社区目录于 2026-08-14 收录,许可证为 MIT(LICENSE 版权声明为 2026 whiteicey),主要语言是 TypeScript。截至 2026-08-18,目录页和 GitHub 仓库都显示 3 颗星。仓库 package.json 里的版本号是 0.0.1,要求 Node.js ^22.19.0 || >=24.0.0,README 写明适配 DSH 0.1.0-rc.6(npm 线)。

一句话定位:安装后,模型可以调用 json 工具,对 JSON 对象或 JSON 字符串执行路径查询,返回匹配到的值。

需要先分清包名和来源。Cordis 插件名和 package.jsonname 都是 @deepseek-ai/dsh-tool-json,但这是社区仓库自己用的包名,private 字段为 true,并不表示它由 DeepSeek 官方发布到 npm。第三方清单里偶见 dsh plugin add @deepseek-ai/dsh-tool-json 这种按包名安装的写法;目录页和仓库 README 均使用 GitHub 源,本文以这两处为准。

同一维护组织还有合集仓库 omdsh-dev/dsh-toolkit,会把包括 json 在内的多个工具做成 vendored 快照。合集里的测试数量和独立仓库不一定同步。只需要 JSON 查询时,按本文安装独立仓库即可。

核心功能

插件入口在 src/index.ts,通过 ctx.tools.register() 注册工具;查询逻辑在 src/query.ts,分成解析、执行和输入归一化三块。面向模型的工具名是 json,两个必填参数是:

  • input:要查询的 JSON 值,或一段 JSON 字符串
  • query:路径表达式,例如 data.items[0].name

输出按 JSON 返回,渲染时用 JSON.stringify 变成文本。工具声明里的 timeoutMs 是 1000 毫秒。

双形态输入

input 有两种形态,由 normalizeInput() 统一校验:

  1. 对象直传:模型直接生成 JSON 参数,少一层转义。
  2. 字符串透传:bash、read 等拿到的原文可以原样送进来,内部先 JSON.parse

两种路径都会做 JSON 兼容性检查。只接受 null、布尔、有限数字、字符串、数组和纯对象;undefinedBigInt、函数、Date、非有限数、带 accessor 或不可以枚举的自有属性会被拒绝。循环引用也会报错。

查询语法

语法是 JMESPath 启发下的自定义子集,不是完整 JMESPath。仓库 README 给出的表达式如下:

表达式 示例 说明
点号访问 foo.bar 嵌套对象属性;标识符允许 [A-Za-z0-9_$ 以及 BMP 非 ASCII]
方括号索引 items[0] 数组索引,必须是安全整数
方括号属性 items['key'] / items["key"] 含特殊字符的属性名
通配符投影 items[*].name 仅作用于数组,提取元素上的属性
组合嵌套 a.b[0].c.d 以上写法可以组合

测试里还能看到:空查询返回整个输入;中文键名如 数据.名称 可以走点号访问;items[*] 没有后续路径时,返回数组里的全体元素。

有意和标准 JMESPath 不一致、并且已经锁定的语义包括:

  • 多级通配符 items[*].tags[*] 返回嵌套数组,例如 [['a','b'],['c']],不做标准投影扁平化。
  • 通配符只作用于数组,不支持按对象字段枚举。
  • 投影时,非对象元素会跳过;属性缺失(MISSING_PROPERTY)也会跳过;合法的 null 结果会保留。
  • 类型错误、越界、非法查询会抛出,不会在投影里被吞掉。
  • 引号属性支持 \\\'\" 三种转义;非法转义报错。

过滤器 [?downloads > 1000]、管道 | 和函数调用都不支持。README 的建议是:这类低频场景继续用 bash 加 node 兜底。

安全边界

解析器是手写递归下降,源码注释写明不用 eval / new Function;读取属性时用 Object.hasOwn,访问 constructor / __proto__ 不会顺着原型链走。测试里对这两类键名都按「属性不存在」处理。

资源上限在对象输入和字符串输入两条路径上统一执行,仓库 README 与 src/query.ts 一致:

  • 查询表达式长度不超过 200 字符,解析深度不超过 20 层
  • 字符串输入不超过 1,000,000 字节(UTF-8);输入嵌套深度不超过 100
  • 单次通配符投影不超过 100,000 个元素
  • 输出还有 4 MB 的保险丝(JSON.stringify 后的 UTF-8 字节数)

每次查询前会对输入做全量校验(类型、深度、字节、循环、枚举性)。这是有意的安全成本:即使只取一个小字段,也会先完整扫描输入。README 特别写明:timeoutMs 中断不了这段同步校验。

错误类型是 JsonQueryError,带统一的 json: 前缀,分类为 MISSING_PROPERTYTYPE_MISMATCHINDEX_OUT_OF_BOUNDSINVALID_QUERY

安装与启用

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

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

dsh CLI 会从 GitHub 解析插件并装进当前配置。如需可复现安装,目录页要求固定 commit 哈希,写法是:

dsh plugin add github:omdsh-dev/dsh-tool-json#<commit>

截至 2026-08-18,仓库 main 最新提交是 902bdf60da4d85bc014e46d32070970a62bb5532(2026-08-14)。固定到这一次可以写成:

dsh plugin add github:omdsh-dev/dsh-tool-json#902bdf60da4d85bc014e46d32070970a62bb5532

仓库 README 推荐按 profile 安装。DSH 0.1.0-rc.6 下,web 和 headless 是两套不同的配置:

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

# 一次性任务(headless)profile;dsh run 默认走 headless
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-json

包内的 dsh.bundle.patch 指向 cordis.patch.yml,安装后会往 profile 的 layer stack 插入 tool-json 条目。patch 必须用 - insert: 列表包裹;写成裸的 - id: 会报 entry not found

验证 web profile 是否装上:

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

README 还提供了本地 npm pack 再按 tarball 安装的路径,以及把源码拷进 DSH monorepo 的旧快照调试步骤。日常使用按上面的 GitHub 源即可。启动 DSH 时,官方仓库建议用 npx -p @deepseek-ai/dsh@0.1.0-rc.6 dsh web 这类指定版本的方式,不要 install -g 全局安装。

典型用法

仓库 README 给出的调用形态是:

json { input: <JSON>, query: "items[0].name" }        → "hello"
json { input: <JSON>, query: "items[*].name" }         → ["a", "b"](合法 null 保留)
json { input: <JSON>, query: "items['complex-key']" }  → "ok"

装到 headless profile 之后,可以用一次任务做冒烟:

dsh run "使用 json 工具查询 {"a":{"b":1}} 的 a.b"

下面几个例子来自仓库测试,便于对照语义,而不是额外编出来的业务故事。

点号和数组下标:

input:  {"foo":{"bar":42},"items":[{"name":"a"},{"name":"b"}]}
query:  foo.bar              → 42
query:  items[0].name        → "a"
query:  items[1].meta.version  (若该元素带 meta.version)

数组投影。items 里如果混有数字或 null,这些非对象元素会被跳过;缺 name 的对象也会跳过;值为 nullname 会保留:

query:  items[*].name

特殊键名用方括号:

query:  ['complex-key']

字符串输入同样可以:

input:  "{\"a\":1}"
query:  a                    → 1

插件是只读的,不能改 JSON 字段。README 写明:原地修改继续用 str_replace_editor / write;仓库把 set 模式列为以后可能考虑的方向,当前版本没有。

适用场景与注意事项

比较适合这些情况:

  • 智能体拿到 API、配置或上游工具的 JSON 后,只需要按路径取出某个字段或一组字段
  • 希望查询走结构化路径,而不是用 grep 在整段文本里碰同名键
  • 不想为一次取值再拉起 jqnode -e

不适合、或需要自己兜底的情况:

  • 要按条件过滤([?...])、管道或 JMESPath 函数
  • 指望多级通配符自动扁平化
  • 需要改写 JSON
  • 输入可能超过 1 MB、嵌套超过 100 层,或单次数组投影超过 10 万元素

安装前还有几条需要自己核对:

  1. 插件以当前 dsh 进程的权限运行,安装时可能执行代码。目录页和 GitHub 源码、MIT 许可证都要先看过再装。
  2. 包名带 @deepseek-ai/ 前缀,只说明它按官方工具包的命名习惯接入 Cordis,不代表官方维护。
  3. web 装上不会自动出现在 headless 里;dsh run 默认用 headless。两边都要用,就两边都装。
  4. DeepSeek Harness 仍是开发者预览,官方 README 写明会有破坏兼容性的变更。本插件明确对齐的是 npm 线上的 0.1.0-rc.6。

小结

dsh-tool-json 给 DSH 补的是一件很具体的能力:在进程内按路径读 JSON,语法小、依赖为零,并且把长度、深度、原型链和输入形态都收在明确上限里。它不是通用 JMESPath 引擎,也不改数据。若日常只是让智能体从工具输出里取出 items[0].nameitems[*].id,这个插件的范围和目录页上的安装命令是对齐的。

目录页:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-tool-json/

GitHub:https://github.com/omdsh-dev/dsh-tool-json

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

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

小夜