用 dsh-custom-tool 在 DeepSeek Harness 设置页编写沙箱自定义工具

前言

给 DeepSeek Harness(以下简称 DSH)加一项能力,常规路径是写一个 harness 包:声明工具 schema、实现 execute、打进 profile。这套流程适合正式插件,但对「今天临时要调一个天气接口」「这个工作区反复做同一类文件整理」来说,成本偏高。改完还要重启、重新挂载,模型这一侧也不能在会话中途自己补一把工具。

官方仓库把架构写成「一切皆插件」:模型、工具、技能、会话、沙箱、UI 都可以在配置层装卸,不必改 Harness 源码。社区里有人把「写工具」这件事收进设置页:用 Monaco 编辑器填名字、描述、参数和 JavaScript 代码,保存后热注册进 ctx.tools;同一套工具,模型也可以通过 custom_tool_create / custom_tools_list / custom_tool_remove 增删。这个插件叫 dsh-custom-tool,收录在独立的社区插件目录 deepseek-harness-plugin.com 中。该目录与 DeepSeek / 幻方没有官方从属关系,不是官方应用商店。

本文按插件目录页、GitHub 仓库 README / README.zh.md、package.jsondsh.plugin.json 交叉核对后整理:它是什么、装哪条命令、工具代码怎么写,以及沙箱边界和 harness 前置条件。

这是什么

dsh-custom-tool 是一款面向 DeepSeek Harness 的开发与运行时插件,由 GitHub 组织 omdsh-dev 维护,仓库地址为 omdsh-dev/dsh-custom-tool。当前版本为 0.1.2package.jsondsh.plugin.json 一致;仓库在 2026-08-16 打了 git tag v0.1.2)。许可证为 MIT,LICENSE 版权声明写的是 2026 FSMargoo。主要语言是 TypeScript;仓库已提交 lib/,按 README 用 GitHub tarball 安装时不必本地构建。截至 2026-08-17 查询,GitHub API 显示 24 stars(社区目录页当时标注为 23)。package.json 要求 Node.js ^22.19 || >=24

目录页给它的一句话是:用 Monaco 编辑器创建和管理沙箱 JavaScript 工具,模型驱动工具生命周期。仓库 README 写得更具体:用户在设置界面的「Custom Tool」页编写工具;模型通过上述三个工具接口扩展和修剪同一套工具集。工具持久化、热注册,并在下一步写入模型提示词。

它要填的坑,README 列了三条:以前加能力要发布 harness 包,现在一张表单保存即生效;模型可以在会话中途持久化工具,且与 UI 共用同一道校验门;用户写的代码在受限 worker 里跑,而不是直接进当前 Node 进程。

核心功能

下面几条都来自当前仓库 README、README.zh.md 与 dsh.plugin.json,不额外发挥。

1. 设置页里的 Custom Tool

插件在 Web 设置里加了一个「Custom Tool」分区,带专属导航图标。可以列表、新建、编辑、启用 / 停用、删除。模型创建的工具、以及工作区作用域的工具会打徽章。文案接入 harness 的中文 / English 语言体系,随界面语言切换。

编辑器是 Monaco(VS Code 引擎)加 TypeScript 语言服务:args 按你声明的参数 schema 生成类型,env 和沙箱全局量有声明,补全与诊断即时出现。编辑器和 TS worker 内联打包,客户端是单文件 bundle。package.json 声明浏览器半通过 dsh.client 提供,README 写明路径是 /plugins/dsh-custom-tool/client.js

2. 持久化与热注册

工具存在 custom-tools 设置命名空间,分层方式和 harness 其他设置一样:schema 默认值、组合 base、用户文档。改动提交后立刻生效,重启后按存储恢复。

启用的工具在设置写入提交的瞬间注册进 ctx.tools;停用或删除会立即注销。工具 schema 由 harness 自动汇入系统提示词,模型下一步就能看见。

3. 模型自助:创建、列出、删除

dsh.plugin.json 声明贡献的工具是:

  • custom_tool_create:按名字 upsert
  • custom_tools_list
  • custom_tool_remove

这三条与设置 UI 共用校验门。归属规则 README 写得很清楚:

  • 模型可以创建、列出、删除 自己创建 的工具(source: model
  • 创建 global 位置 的工具需要用户明确授权:custom_tool_create 会发起 harness 审批请求(GUI 弹窗);拒绝或审批不可用则创建失败关闭
  • workspace 位置的工具,模型可以自主创建
  • 模型 不能 删除用户创建的工具(source: user):custom_tool_remove 会拒绝,提示词会引导模型请用户在设置界面删除

设置界面管理全部来源、作用域、位置,以及启停和删除。

4. 两套作用域、两套存放位置

每个工具声明一种执行作用域。这是插件的核心安全契约:

global(默认) workspace
用途 纯计算、外部数据、工作流 工作区内重复性的文件任务
fetch allowNetwork 控制 allowNetwork 控制
console、定时器、TextEncoderURL
fs readFile / writeFile / list,限定在本会话 workspace 根目录内
require / import / process 永不 永不

workspace 作用域的根目录是发起 agent 的 cwd,调用时解析。相对路径从根解析;绝对路径必须落在根内;越界路径会被显式拒绝。没有会话上下文时,workspace 工具直接报 no workspace root,不会在无边界下运行。

隔离是词法级的(resolve + 前缀检查)。README 明确写了:工作区内的符号链接仍可能指向外部——workspace 作用域按可信代码处理,不是对抗恶意宿主的沙箱。

存放位置是另一维:

  • location: 'global':存在共享设置命名空间,所有工作区都可用,直到被删除
  • location: 'workspace':存在按工作区根路径哈希命名的独立文件里(README 写在 workspace-tools/ 目录下),只对该工作区的会话可见

两维可以自由组合。README 举的例子是:location 为 global、scope 为 workspace 的文件类工具(例如 PDF 读取),在任意被调用的工作区上执行 fs

5. 沙箱执行与预算

每次调用在独立 worker 线程里跑,环境是全新的 node:vm 领域,配合白名单、Node Permission Model 和硬预算。worker 不继承环境变量,也不能访问配置范围之外的文件或创建子进程。超时、取消或完成后,该 worker 被终止。

README 给出的可调预算(cordis.ymldsh-custom-tool 条目的 config 字段)默认值如下:

字段 默认值 含义
timeoutMs 30000 单次调用墙钟上限(毫秒)
memoryLimitMb 128 单次调用 worker 老年代堆上限(MB)
maxResultChars 16000 结果渲染文本字符上限
maxCodeBytes 65536 单个工具代码的 UTF-8 字节上限
maxTools 100 可存储的工具数上限
allowNetwork true 是否允许工具代码调用 fetch

安装与启用

插件目录页给出的安装命令是:

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

目录页同时提醒:插件以当前 dsh 进程的权限运行,安装时可能执行代码。安装前请检查源代码仓库和许可证。若需要可复现安装,固定 commit 哈希:

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

<commit> 换成仓库里实际的提交哈希,不要照抄占位符。当前 tag v0.1.2 指向提交 7cb95649dca9b380c9a30af96bdbef87a76a2259

仓库 README 面向 Web 界面,写法是按 web profile 安装固定版本的 tarball,然后重启:

dsh plugin --profile web add https://github.com/omdsh-dev/dsh-custom-tool/archive/refs/tags/v0.1.2.tar.gz
dsh web

包声明了 dsh.bundle.patch(挂载 host 插件)与 dsh.client(提供浏览器半)。lib/ 已提交,因此这份 tarball 安装后无需再构建。

Harness 前置条件(README 原文):设置命名空间要通过 packages/host/apiproxy/src/api-proxy.ts 中的 WEB_SETTINGS_NAMESPACES 白名单暴露给 web 配置客户端,名单里必须有 'custom-tools'。上游 harness 提交 d6ea05b5 已加入该项。缺少它时界面能渲染,但保存会被静默拒绝,错误为 settings-not-exposed

典型用法

在设置页新建工具

启动 Web 界面并打开设置里的 Custom Tool:

  1. 新建一条工具,填写名字、描述、参数 schema、作用域和存放位置。
  2. 在 Monaco 里写代码。代码字段是 一个异步函数体,契约是 async (args, env) => value,不是完整的源文件。
  3. 保存。启用状态下,工具立刻注册进 ctx.tools,下一步会出现在模型提示词里。
  4. 不需要时可以停用或删除;停用会立即注销。

README 给出的示例是按城市拉天气(需要 allowNetwork 为 true,这是默认值):

// args 按你声明的参数 JSON Schema 生成类型。
const url = `https://api.example.com/weather?city=${encodeURIComponent(args.city)}`
const response = await fetch(url)
if (!response.ok) throw new Error(`upstream returned ${response.status}`)
return await response.json()

返回值必须是 JSON 值:string、number、boolean、null、array 或普通对象。undefined 或非 JSON 值会使调用失败。

参数是 object 根的 JSON Schema,且只接受 harness 子集:typepropertiesrequireditemsenumconstoneOfadditionalPropertiesdescriptiontitledefaultexamples

沙箱全局量包括:fetchallowNetwork: false 时被禁)、consoleTextEncoder / TextDecoderURL / URLSearchParamsatob / btoastructuredCloneAbortControllersetTimeout / setInterval 及对应的 clear。env{ tool, scope }。workspace 作用域额外提供 fs

界面目前没有「试运行」按钮。README 写明:工具通过模型调用或 headless 运行来验证。

让模型自己补工具

会话里可以直接要求模型创建一条可复用的工具。模型会走 custom_tool_create。若目标是 global 位置,界面会弹出 harness 审批;拒绝则创建失败。workspace 位置不走这道审批。

查看当前自定义工具用 custom_tools_list。自定义工具名不能遮蔽其他包已经注册的工具;冲突会以逐工具注册失败的形式出现在这份列表里。

删除时,模型只能删 source: model 的条目。用户在设置页写的工具,需要人在 UI 里删。

适用场景与注意事项

比较适合这些情况:

  • 已经在用 dsh web,希望给当前环境加几条小工具,又不想为此发一个正式插件包
  • 需要模型在会话中途把反复出现的步骤沉淀成可调用工具,并在下一步立刻看见
  • 工具逻辑是纯计算或受控的 fetch;若要碰文件,明确使用 workspace 作用域,并接受词法隔离的边界
  • 希望用户写的工具和模型写的工具分权:人删人的,模型只能动自己创建的那批

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

  1. 先看源码和许可证再装。 目录页写明:插件以当前 dsh 进程权限运行,安装时可能执行代码。这是社区插件,不是 DeepSeek 官方组件。
  2. 确认 custom-tools 已进入 harness 白名单。 否则设置页能打开,保存会静默失败(settings-not-exposed)。需要上游提交 d6ea05b5 或等价改动。
  3. 沙箱不是万能隔离。 require / import / process 不可用;global 作用域没有 fs;workspace 的路径检查不防符号链接。README 把 workspace 代码按可信代码对待。
  4. 网络默认是开的。 allowNetwork 默认 true。不希望工具访问外网时,要在 cordis.yml 里关掉。
  5. 预算有上限。 单次 30 秒、堆 128 MB、结果 16000 字符、代码 64 KiB、最多 100 条工具,都是文档给出的默认硬限制。
  6. 不要把目录页当成官方商店。 deepseek-harness-plugin.com 是社区目录;DSH 本体以 deepseek-ai/deepseek-harness 为准。安装命令以目录页原文为准;Web 固定版本安装以仓库 README 的 tarball 写法为准,不要凭插件名自行拼接路径。

小结

dsh-custom-tool 做的事情很集中:把「写一个 JavaScript 工具」放进 DSH 设置页,用 Monaco 编辑、热注册、持久化;同时把同一套生命周期交给模型,但用审批和归属规则把用户工具保护起来。执行侧是带白名单和预算的 worker,不是把任意脚本直接跑进当前进程。

目录页与仓库:

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

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

小夜