从零手写 DeepSeek Harness 插件:保姆级教程,看完你也能给 Agent 造“工具“


从零手写 DeepSeek Harness 插件:保姆级教程,看完你也能给 Agent 造"工具"

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续输出的最大动力。

源码可私信获取。

在这里插入图片描述


一、先说个离谱的开局:5 万星的项目,README 却啥也没说

2026 年 8 月 13 日晚,DeepSeek 一口气放了两颗炸弹:

  1. DeepSeek V4 Pro 正式版全量上线,Agent 能力大幅提升;
  2. DeepSeek Harness(以下简称 dsh)开发者预览版 v0.1 以 MIT 协议开源。

博客发布当天,仓库 star 数约 5 万,一度冲上 GitHub 趋势榜第一;本文成文时该仓库 star 已涨到 13 万+,fork 13.1k。下文的截图即取自当前版本仓库,数据以你打开仓库时的实时数字为准。

一夜之间,GitHub 上这个仓库冲到了 5 万多星,有的统计口径甚至说一天破了 7 万——这是开源历史上最快涨星的项目之一。

我抱着好奇心点进仓库,整个人直接看傻了:README 总共一千七百多字,没截图、没功能列表,连"这玩意儿到底能干啥"都没讲明白,就甩了一句英文口号:

Everything is a Plugin(一切皆插件)。

合着现在开源项目都走"老板画饼"路线是吧?口号喊得震天响,具体内容全靠用户自己悟。开周会都没这么抽象——至少老板还会画个饼的形状,这连饼皮都不给你看。

但等你折腾完一圈就会明白:这句话不是营销,是整个项目设计哲学的全部。

在这里插入图片描述

图:deepseek-ai/deepseek-harness 仓库主页,当前 star 数 13.1k+,MIT 协议。

在这里插入图片描述

图:DeepSeek 官网 Harness 页面首屏,明确写着"开发者预览版:一切皆插件",并提供一键使用 / 源码安装两种入口。

二、先搞清楚:Harness 到底是什么

2.1 一个公式看懂它

DeepSeek 官方给出了极其清晰的公式:

Agent = Model(模型 / 灵魂) + Harness(躯壳 / 执行引擎)

没有 Harness,再强的模型也只是一个"昂贵的自动补全"——它能回答问题,但不能动手干活。

有了 Harness,模型才能:

  • 感知环境:文件系统、终端、网页
  • 调用工具:编辑文件、执行命令、搜索网页
  • 维持状态:会话、记忆、子 Agent 调度
  • 持续执行:多步真实任务闭环

一句话:模型负责"想",Harness 负责"干"。

2.2 它填补了 DeepSeek 的最大短板

DeepSeek V4 系列模型性能强、价格低、权重开源,但Agent 任务的可靠性一直偏弱。这个短板本质不是模型问题,而是运行框架问题——工具调用协议、循环控制、错误重试、状态管理、沙箱隔离,这些都得靠框架层解决。

Harness 就是 DeepSeek 对标 Claude Code / Codex 给出的开源答案

三、核心设计:"一切皆插件"到底有多彻底

3.1 底层是 Cordis 元框架

Harness 的底层不是 Express、不是 Fastify、不是任何你熟悉的 Web 框架,而是基于一个叫 Cordis 的元框架。

Cordis 只负责三件事:

  1. 插件的挂载(mount)卸载(unmount)
  2. 插件之间的依赖关系管理
  3. 通过**服务(Service)事件(Event)**让插件互相通信

关键点:Cordis 内核本身不包含任何 Agent 能力,所有能力全部住在插件里。

3.2 哪些东西是插件?几乎所有东西

插件层具体能力
Models大模型后端本身,可换任意 OpenAI 兼容模型
Tools文件编辑、Shell 执行、文件搜索、网页搜索
Skills可复用的技能包,Agent 可按需调用
Sessions会话状态、运行历史管理
Sandboxes隔离执行环境(Docker / 本地进程等)
Storage状态存储、文件系统抽象
Loops & SchedulingAgent 控制循环、子 Agent 调度、任务编排
UI连用户界面都是插件,可换 Web UI / CLI / 其他

整个框架由约 220 个小型 npm 包组成 monorepo,官方内置了一百多个插件。

仓库的 docs 目录就是官方文档(含中文),从用户指南到插件开发教程一应俱全,结构如下:

在这里插入图片描述

图:官方仓库 docs 目录结构,docs/user/guide 是用户指南入口,docs/user/develop 下按 basic / framework / practice 三层组织插件开发教程。

  • docs/user/guide/:用户指南(安装、配置、四种模式);
  • docs/user/develop/:插件开发教程(基础 / 框架 / 实战三层);
  • docs/cookbook/:常见场景实操配方;
  • docs/cordis-api/docs/cordis-tutorial/:Cordis 元框架的 API 文档与教程。

想深入学习,优先啃官方 docs,比任何二手教程都靠谱。

3.3 插件化的实际意义

  • 想换沙箱? 挂载一个新的 sandbox 插件,不用改源码;
  • 想加自定义工具? 写一个 tool 插件,配置里启用就行;
  • 想换模型后端? 换 model 插件,其他全部不动;
  • 想做自己的 Agent 产品? 基于 Harness 薄内核组装插件,不用从零造运行时。

3.4 一张图看懂 Harness 的整体架构

用户

UI 插件
Web UI / CLI / TUI

Cordis 薄内核
挂载 · 依赖 · 事件

Model 插件
DeepSeek / 任意 OpenAI 兼容模型

Loop 插件
Agent 控制循环

Tools 插件
文件 / Shell / 搜索

Skills 插件
技能包

Sandbox 插件
隔离执行

Storage 插件
会话 / 状态

从这张图可以直观看到:所有箭头都指向 Cordis 内核,但内核本身不干活,活全在插件里。 这就是"薄内核 + 可组合零件"的设计哲学。

这和 Claude Code、Codex 那种"控制循环 + 工具集 + UI 焊死在一起"的单体架构形成本质区别。

打个比方:

  • Claude Code / Codex 是成品家电——买回家就能用,但拆不开、改不了;
  • Harness 是乐高底座——底子给你铺好了,想拼坦克拼城堡全看你自己。

四、安装:两条路,按需自选不踩坑

先把两条安装路线的全局脉络看清楚,再动手不迟:

懒人首选

硬核玩家

Node.js ≥ 22.19 或直接上 24

选哪条路?

npx @deepseek-ai/dsh web

git clone + corepack + pnpm build

浏览器打开 127.0.0.1:3080

填 API Key
切中文
加工作区

4.1 前置条件

  • Node.js:官方声明的版本范围是 ^22.19.0 || >=24.0.0,不确定直接用 Node 24。
  • 验证方法:终端执行 node -v,能看到版本号就说明装好了。

4.2 路线 A:npx 一键启动(懒人首选)

普通用户直接选这个,终端敲一行命令:

npx @deepseek-ai/dsh web

中途会弹一个确认,问你要不要继续安装,输入 y 就完事。

装完自动启动本地服务,地址是 http://127.0.0.1:3080,浏览器打开就能进界面。

4.3 路线 B:源码编译安装(硬核玩家)

想改源码、研究内部逻辑的选这个:

# 如果没装 corepack,先安装:npm install -g corepack
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
corepack enable
pnpm install
pnpm run build

注意:pnpm run build 一定不要省。 我第一次只安装依赖就启动,插件日志虽然出现了,Web 页面却缺少构建产物,白白排查了半天。

4.4 装完先做三步基础配置

进页面后第一件事三连:

  1. 填 API Key:没有的去官网生成一个,这相当于入场门票;
  2. 切中文:左下角 Settings → Language,别硬扛英文;
  3. 加工作区:选个本地目录作为要折腾的项目文件夹,再选模型(要速度选 Flash,要效果选 Pro)。

配置页长这样,照着填就行:

在这里插入图片描述

图:官方仓库 docs 目录自带的模型配置页截图,对应 Settings → Providers / 模型配置。

如果你想接第三方模型(比如国产其他大模型或本地 Ollama),可以配置自定义提供方:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图:自定义提供方表单,需要填 Provider ID、显示名称、API 地址、API 协议和 API 密钥。

4.4.1 配置自定义提供方:把任意 OpenAI 兼容模型接进来

Harness 最爽的一点就是模型不绑定 DeepSeek。只要对方提供 OpenAI 兼容接口,就能在 Settings 里加一个自定义提供方:

  1. 打开 Settings → Providers,点"添加自定义提供方";
  2. Provider ID(自己起个英文名,如 my-ollama);
  3. 显示名称(界面上显示的名字,如 Ollama 本地模型);
  4. API 地址(如 http://localhost:11434/v1);
  5. 选择 API 协议(OpenAI 兼容选 openai);
  6. API 密钥(本地模型随便填,远程服务填真实 Key);
  7. 点击"获取可用模型",勾选你要用的模型,保存。

坑 6 预警:有的厂商能拉出一百多个模型,别全选,挑常用的几个就行,不然下拉菜单长得能拖到屏幕底。

关于 API Key 的一个细节:DeepSeek 官网生成的 Key 是 **Write-only(只写)**的,创建后只显示一次,关闭弹窗就再也看不到了。所以创建后第一时间复制保存。丢失了只能删掉重建,没有找回通道。

4.5 进阶:聊聊 Profile(配置文件)

先理解一个概念:Profile 就是 Harness 的“配置命名空间”。你可以在同一个电脑上配置多套完全不同的 Agent 环境,互不干扰。

比如:

# 默认 Web Profile
dsh web

# 用 --profile 指定一套独立配置
dsh web --profile web2 --port 8080

指定 Profile 后,--port 也要同步指定,否则可能端口冲突。每次启动用 --profile 参数选择,相当于给 Agent 开了不同的“工作台”。

4.6 工作区与项目加载

Harness 以**工作区(Workspace)**为单位组织任务。简单理解:每个工作区绑定一个本地文件夹,Agent 只能在这个文件夹及配置好的沙箱里活动。

  • 新建会话前先选工作区;
  • 会话中 /workspace 命令可以切换当前工作区;
  • 想让 Agent 操作某个项目,先把项目文件夹加进工作区。

这样既安全又不容易把 Agent 搞晕——它永远知道自己该在哪个目录下干活。

五、四种模式怎么选?给你翻译成人话

官方给了四种 Agent 模式,新手看着头大:

模式定位人话翻译
Standard(标准)完整编码 Agent,工具最全全能选手,写代码、改文件、跑命令、搜网页啥都能干,新手直接选这个
Code(代码)工具通过 Code SDK 暴露效率狂魔专属,把多步操作写成一个程序一次执行,省 token
Minimal(极简)只有 Bash + 文件编辑两个工具极简主义狂喜,也是官方发 Agent 跑分时用的模式
Creator(创造)构建自定义预设高阶玩家玩法,能自己写插件、折腾运行时

说直白点,这四个模式就像奶茶点单:

  • 标准是正常杯全糖;
  • Code是浓缩快取;
  • 极简是纯水无糖;
  • 创造是自己 DIY 小料随便加。

硬核提醒:以后看任何大模型的 Agent 跑分,先问一句"在什么模式下测的?"Minimal 模式分数高,不代表复杂生产任务表现好。

5.1 模式背后的工具集差异

四种模式本质是预置工具集不同

模式预置工具适合场景
Standard文件读写、Shell、搜索、子 Agent 调度等全量工具日常编码、文档、调研
Code通过 Code SDK 暴露的程序化工具批量任务、自动化流水线
Minimal仅 Bash + 文件编辑两个工具跑分、极简环境验证
Creator自定义预设自己组装工具链

注意:Windows 平台目前对 Minimal 模式的 JSON-RPC Composition 支持不完整,如果你在 Windows 上跑 Minimal 模式遇到莫名其妙的 JSON-RPC 报错,换 Standard 模式通常就解决了。

六、插件开发实战:从零手写你的第一个工具

理解了"一切皆插件",下面进入本文核心:手写一个最小插件,完整跑通"加载插件 → 注册工具 → Agent 调用 → 返回结果"的闭环。

我们的目标是做一个 greet 工具:Agent 调用它并传入名字,插件返回:

你好,Datawhale!你的第一个 Harness 插件已经运行。

6.1 准备源码环境

开发原始 TypeScript 插件,需要进入 Harness 源码仓库(这也是官方入门文档采用的方式):

git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
corepack enable
pnpm install
pnpm run build

本文实测使用 Node.js v24.19.0。 记住:pnpm run build 不要省,否则 Web 页面会缺少构建产物。

6.2 创建插件文件

在仓库根目录执行:

mkdir -p scratch-plugin/src

新建 scratch-plugin/src/greet-tool.ts

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet someone by name.',
    parameters: {
      name: {
        type: 'string',
        required: true,
        description: 'The name to greet',
      },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      return `你好,${args.name}!你的第一个 Harness 插件已经运行。`
    },
  }))
  console.log('[greet-tool] loaded; tool name: greet')
}

6.3 逐行拆解:这个插件到底在干嘛

先不用研究所有类型,这个插件其实只有四个部分:

组成作用
name插件名称,用于识别和挂载
inject声明需要 Harness 的 tools 服务(依赖注入)
apply(ctx)插件加载入口,Cordis 挂载时调用
ctx.tools.register(...)注册一个模型可以调用的工具

其中 defineTool 内部的五个字段:

  • name:工具名,模型调用时用这个名字;
  • description:工具描述,告诉模型"这个工具是干嘛的、什么时候该用";
  • parameters:参数定义,告诉模型该传什么、哪些必填;
  • output:约定结果的类型和显示方式(schema 定义结构,render 定义展示);
  • execute:真正执行代码的地方,模型把参数传进来,这里干活并返回结果。

为什么 description 这么重要?

因为模型是靠"读"来选择工具的。它不会遍历你的代码,只看你给它的工具描述。所以:

  • 描述写得模糊,模型就不知道该在什么时候调用;
  • 参数定义写得笼统,模型就会传错参数类型;
  • 一个好的工具描述 = 明确的触发场景 + 清晰的参数约束。

这是"提示词工程"在插件开发里的体现——你写给模型看的元数据,和写给人看的代码一样重要。

6.3.1 进阶示例:一个读写文件的小工具

greet 只展示了"输入 → 返回"的最小闭环,实际项目里你更可能写带副作用的工具——比如读写文件。下面这个例子注册两个工具:read_fileappend_file,让 Agent 能读文件并在末尾追加内容。

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
import { readFile, appendFile } from 'node:fs/promises'

export const name = 'file-ops'
export const inject = ['tools']

export function apply(ctx: Context) {
  // 工具一:读文件
  ctx.tools.register(defineTool({
    name: 'read_file',
    description: '读取指定路径的文件内容。当用户需要查看某个文本文件时使用。',
    parameters: {
      path: {
        type: 'string',
        required: true,
        description: '文件的绝对路径或相对工作区的路径',
      },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      try {
        return await readFile(args.path, 'utf-8')
      } catch (e) {
        return `读取失败:${(e as Error).message}`
      }
    },
  }))

  // 工具二:追加写文件
  ctx.tools.register(defineTool({
    name: 'append_file',
    description: '向文件末尾追加内容。注意:不会覆盖已有内容,适合写日志、记笔记。',
    parameters: {
      path: { type: 'string', required: true, description: '目标文件路径' },
      content: { type: 'string', required: true, description: '要追加的内容' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      try {
        await appendFile(args.path, args.content + '\n', 'utf-8')
        return `已追加 ${args.content.length} 个字符到 ${args.path}`
      } catch (e) {
        return `写入失败:${(e as Error).message}`
      }
    },
  }))
}

这个例子展示了两个实战细节:

  1. 一个插件注册多个工具——只要在 apply 里多调几次 ctx.tools.register 就行;
  2. 异常要兜底——文件不存在、权限不足时,把错误转成字符串返回给模型,而不是让插件直接抛异常。记住:工具的错误消息也会被模型读到,写清楚错误原因,模型才知道怎么自我修正。

6.4 把插件插入 Harness

先执行 pwd 拿到当前仓库的绝对路径,然后新建 scratch-plugin/cordis.yml

- insert:
    - id: greet-tool
      name: '/Users/yourname/deepseek-harness/scratch-plugin/src/greet-tool.ts'

name 换成你机器上的绝对路径。

插件最好放在 Harness 源码仓库内。这个示例依赖仓库里的 @deepseek-ai/cordis@deepseek-ai/dsh-tools,放到另一个目录可能出现 Cannot find module 报错。

6.5 启动并检查

pnpm dsh web --patch ./scratch-plugin/cordis.yml

如果 3080 端口已经被占用:

pnpm dsh web --patch ./scratch-plugin/cordis.yml --port 3082

看到下面两行,说明插件和 Web 服务都已就绪:

[greet-tool] loaded; tool name: greet
dsh web: http://127.0.0.1:3082

进入"设置 → 插件 → 插件列表",搜索 greet-tool.ts,状态应为"已启用"。

补充一个常见困惑:如果你把插件写好后用 npx 方式启动(npx @deepseek-ai/dsh web),插件默认不会加载——因为 npx 启动的是发布包,不会去读你 scratch-plugin/cordis.yml 里的本地路径。开发本地插件请用仓库内的 pnpm dsh,而不是 npx。

6.5.1 常见启动报错速查

开发阶段最常碰到的三个报错,先记住解法:

报错信息原因解法
MISSING_CREDENTIAL没有配置 API Key 对应的凭据在设置里填 API Key,或 dsh credentials set 变量名 写入
UNKNOWN_MODEL模型 ID 与当前配置的模型名不匹配去 Providers 检查模型 ID 是否填对
Cannot find module '@deepseek-ai/cordis'插件文件放在了仓库外把插件放回仓库目录,或配置好 node_modules 路径

这三个坑基本覆盖了 90% 的启动失败场景。

6.6 让 Agent 调用它

选择工作区,新建一个标准模式会话,输入:

请调用 greet 工具问候 Datawhale。

展开工具调用,可以看到输入和输出:

IN   { "name": "Datawhale" }
OUT  你好,Datawhale!你的第一个 Harness 插件已经运行。

至此,插件最小闭环已经跑通:加载插件 → 注册工具 → 模型调用 → 返回结果。

6.6.1 会话与 Session ID:调试必备知识

你可能注意到界面里每个会话都有一串 ID,这叫 Session ID。它的用处很大:

  • 恢复:中途断网/崩溃,用 /resume 或指定 Session ID 找回上次会话;
  • 分叉:从历史某步开新分支尝试不同方案(对应第八节的可观测性设计);
  • 定位问题:报错时把 Session ID 贴出来,方便排查历史工具调用。

也就是说,Harness 的会话不是“用完即走”的聊天记录,而是可审计、可追溯、可恢复的运行轨迹。

把整个闭环画成图,就是下面这条链路:

创建 greet-tool.ts 插件

编写 cordis.yml 挂载配置

pnpm dsh web --patch 启动

Cordis 挂载 greet-tool 插件

ctx.tools.register 注册 greet 工具

模型读取工具描述与参数定义

模型决定调用?

execute 执行并返回结果

结果渲染回会话

继续正常对话

七、插件和工具的区别:别搞混了

开发之前先厘清一对关键概念,很多人在这上面栽跟头:

  • 插件(Plugin) = 一个 apply(ctx) 模块,是框架的安装/生命周期单元。它决定"什么时候加载、依赖什么、卸载时清理什么"。
  • 工具(Tool) = 插件通过 ctx.tools.register(...) 注册的能力,是模型可见、可调用的函数。它决定"Agent 能做什么"。

打个比方:

插件是安装的应用程序,工具是应用暴露的函数 / API 端点。 一个应用可以暴露 0 个、1 个或多个函数。

理解了这层关系,你就明白了为什么 Harness 官方说"一个插件可以注册多个工具,但工具不能脱离插件独立存在"。

7.1 常用命令速查表

开发过程中你会反复用到这些命令,先存下来:

命令作用
dsh web启动 Web 界面(默认端口 3080)
dsh web --port 8080指定端口启动
dsh web --profile web2用指定 Profile 启动
dsh --dump-config导出当前配置
dsh plugin --profile web add <包名>给指定 Profile 安装插件
dsh plugin --profile web remove <包名>卸载插件
dsh plugin --profile web update更新所有插件
dsh credentials set 变量名写入凭据(API Key 等)
pnpm dsh web --patch ./cordis.yml开发时挂载本地插件

小技巧:记不住参数没关系,所有子命令后面加 --help 都能看到说明,比如 dsh plugin --help

八、Harness 的可观测性:为什么它调试起来"不像玄学"

插件开发绕不开调试。Harness 的第二大设计原则就是可观测性——这是很多 Agent 框架严重缺失的部分,也是它工程化的底气。

8.1 只追加的事件日志

模型看到的一切全部记录在只追加(append-only)的会话日志中:

  • 系统提示词
  • 模型推理过程
  • 每一次工具调用及返回结果
  • 子 Agent 调度记录
  • 每一次上下文注入

8.2 Trajectory 视图

可以按来源(source)检查这些记录,清晰看到 Agent 每一步做了什么、为什么这么做。

8.3 可恢复、可分叉、可搜索、可重放

因为日志是单一事件流,所以任意一次 Agent 运行都可以:

  • 恢复(Resume):中断后从断点继续;
  • 分叉(Fork):从某个历史节点分出一条新路径,尝试不同方案;
  • 搜索(Search):在历史运行中查找特定操作;
  • 重放(Replay):用相同历史重新运行,对比结果。

这对调试插件意味着什么? 插件跑偏了、参数传错了、返回结果不对——不再是"凭感觉猜",而是把事件日志拉出来,看模型当时到底看到了什么、调用了什么、返回了什么。这是从"玄学调试"到"工程化调试"的关键一步。

8.4 调试插件时的实操技巧

结合上面的设计,调试一个插件时按下面顺序查,效率最高:

  1. 看日志:用 dsh web --verbose 启动,或直接看会话的 Trajectory 视图,定位是哪一步出错;
  2. 看参数:展开工具调用的 IN 参数,确认模型传参是否符合你的 parameters 定义;
  3. 看返回:确认 execute 的返回值结构,是否满足 output.schema
  4. 改描述:如果模型压根不调用你的工具,多半是 description 写得不清楚,模型不知道什么时候该用;
  5. 加日志:在 executeconsole.log 打印中间变量,再重启 web 服务。

这套流程能把插件调试时间缩短一大半。

九、直接安装大佬做好的插件:以 DSH Vision Toolkit 为例

9.1 安装插件

如果终端里已经有 dsh 命令:

dsh plugin --profile web add @dsh-external/dsh-vision-toolkit

如果一直用 npx,可以写成:

npx @deepseek-ai/dsh@0.1.0-rc.6 \
  plugin --profile web add @dsh-external/dsh-vision-toolkit

安装到 web Profile 后,检查配置里是否已经出现它:

dsh --profile web --dump-config | grep vision-toolkit

然后重启正在运行的 Harness Web 服务。 插件的宿主代码和浏览器代码都在启动时加载,只刷新页面通常不够。

9.2 配置视觉模型

Vision Toolkit 要求 Python 3.11 或更高版本。第一次使用 managed 运行时还需要联网安装它锁定的 Python 依赖。

打开 Harness 的"设置 → 视觉工具",配置:

  1. 一个兼容 OpenAI 接口的视觉模型地址;
  2. 对应的视觉模型名称;
  3. 一个 DSH Credential 引用,例如 VISION_API_KEY

密钥可以通过命令写入 Harness 的凭据系统:

dsh credentials set VISION_API_KEY

在设置页面点击"测试连接"。注意:远程图片问答、定位和 OCR 需要视觉服务 Key;裁剪、颜色分析、像素对比等本地工具不需要。

9.3 在会话中使用

把图片复制进当前工作区,例如 ./screenshot.png,在会话中先加载插件附带的 Skill:

/vision-tools

然后直接描述任务:

请用 vision_glance 分析 ./screenshot.png,告诉我页面上出现了什么错误。

也可以做更具体的操作:

请用 vision_ground 定位截图里的发送按钮,并生成带标注的预览图。
请比较 reference.png 和 actual.png,告诉我差异最大的区域。

插件会按需向当前 Agent 暴露对应的 vision_* 工具。生成的裁剪图、热力图和报告会保存在工作区的 .dsh-vision-toolkit/artifacts 目录中。

9.4 更新或卸载

dsh plugin --profile web update
dsh plugin --profile web remove @dsh-external/dsh-vision-toolkit

操作后记得重新启动 Web Profile。

9.5 进阶:用 Python SDK 直接写 Agent 逻辑

除了在 Web 界面里用,Harness 还提供了 Python SDK(deepseek-harness-sdk,适合想用 Python 写测试脚本或自动化流程的同学。

先安装:

pip install deepseek-harness-sdk

然后连接本地的 dsh 服务:

from deepseek_harness_sdk import HarnessClient

client = HarnessClient(base_url="http://127.0.0.1:3080")

# 列出当前会话
sessions = client.list_sessions()
print(sessions)

# 创建一个新会话并发送消息
session = client.create_session(profile="web")
response = session.send("用 Python 帮我写一个快速排序")
print(response.text)

几个要点:

  • SDK 连接的还是本地 dsh 服务,所以先要把 dsh web 跑起来;
  • 每个 session 对应 Web 里的一个会话,天然支持上下文续聊;
  • 适合在 CI/CD 里跑 Agent 回归、批量任务,或者给内部工具接上 Harness 能力。

这相当于给 Python 开发者开了一扇后门:不打开浏览器也能用 Agent。

十、安装第三方插件前的安全自查清单

Harness 插件运行在宿主进程里,属于可信代码。不要因为安装命令只有一行,就跳过源码和权限检查。动手前至少确认四件事:

  • 仓库是否公开?许可证和维护者是否清楚?
  • 安装脚本会下载什么?是否会运行额外程序?
  • 插件需要哪些目录、网络和凭据权限?
  • 是否说明了支持的 Harness 版本、卸载方式和测试方法?

10.1 为什么要这么谨慎?

插件是在宿主进程里运行的。这意味着:

  • 它能读写你工作区里的所有文件;
  • 它能调用你配置的所有凭据(API Key、Token);
  • 它能发起任意网络请求;
  • 它能在你机器上执行任意代码。

所以装第三方插件,本质上等于把部分机器权限交出去。不要因为是“官方生态”就放松警惕。 尤其是从 npm 上装包时,先花 5 分钟看一下它的源码和 package.json 里的脚本字段。

十一、与 Claude Code / Codex 的本质差异

写插件之前,值得先把 Harness 放在行业坐标系里看清楚。它和目前最火的两个 Agent 产品差异极大:

维度DeepSeek HarnessClaude CodeCodex
架构插件化薄内核(Cordis)单体架构单体架构
开源MIT 完全开源闭源闭源
模型绑定模型是插件,可换任意模型绑定 Anthropic 模型绑定 OpenAI 模型
运行模式4 种预设,可自定义单一编码 Agent 模式单一编码 Agent 模式
可观测性只追加事件日志,可恢复/分叉/重放有日志,可重放能力弱有运行记录
UIUI 是插件,可替换固定 CLI/TUI固定 CLI/TUI
沙箱沙箱是插件,可换内置沙箱内置沙箱
模型层模型可替换,可接任意 OpenAI 兼容后端(含本地 Ollama)模型锁定模型锁定
当前状态v0.1 开发者预览,官方警告破坏性变更相对成熟相对成熟

核心差异一句话:Claude Code 和 Codex 是产品,Harness 是平台/内核。前者给你一个成品 Agent,后者给你一堆零件让你组装自己的 Agent。定位不同,不是直接替代关系。

十二、常见坑与踩坑实录

把我(和社区)踩过的坑整理成清单,能帮你省下大量排查时间:

坑 1:pnpm run build 没跑,Web 页面空白

pnpm install 就启动,插件日志虽然会出现,但 Web 页面缺少构建产物。构建步骤不能省。

坑 2:插件放在仓库外,报 Cannot find module

示例插件依赖仓库里的 @deepseek-ai/cordis@deepseek-ai/dsh-tools,放到另一个目录会找不到模块。插件最好放在 Harness 源码仓库内。

坑 3:Node 版本不对

官方要求 ^22.19.0 || >=24.0.0。用 Node 20 会有一堆兼容性报错。不确定就直接上 Node 24。

坑 4:端口被占用

默认 3080 被占用时,加 --port 3082 换一个,别慌。

坑 5:装完插件界面没反应

只刷新页面通常不够。插件的宿主代码和浏览器代码都在启动时加载,需要重启 Web Profile。

坑 6:模型列表过长

自定义提供商"获取可用模型"时,有的厂商能拉出一百多个模型。别全选,挑常用的几个就行,不然下拉菜单长得能拖到屏幕底。

坑 7:插件权限

Harness 插件运行在宿主进程里,属于可信代码。装第三方插件前务必检查源码和权限(见上一节自查清单)。

坑 8:MISSING_CREDENTIAL 报错

启动时提示 MISSING_CREDENTIAL,说明配置引用的凭据不存在或没填。用 dsh credentials set 变量名 写入对应的 API Key 即可。

坑 9:UNKNOWN_MODEL 报错

提示 UNKNOWN_MODEL,通常是模型 ID 与配置不一致。去设置里核对:你选的模型名,是否在模型列表里真实存在?有时厂商改名了,旧 ID 就会失效。

坑 10:danger-full-access 安全警告

部分高权限插件(或使用 --danger-full-access 模式)会弹风险提示。确认风险可控再继续,不然就在沙箱里跑。

十三、总结:把这条链路刻进脑子

自己写插件时,最小结构是:

apply(ctx) → 注册工具 → execute(args) → 返回结构化结果

使用现成插件时,流程是:

plugin add → 重启 Profile → 配置凭据 → 加载 Skill → 调用工具

前者让你理解 Harness,后者让 Harness 真正变得有用。

十四、高频问题 FAQ

Q1:Harness 一定要配 DeepSeek 的模型吗?

不需要。模型是插件,默认预置 DeepSeek,但你可以配置任何 OpenAI 兼容接口,包括本地 Ollama。详见 4.4.1 节。

Q2:Windows 能用吗?

能。官方支持 Windows / macOS / Linux。注意两点:一是 Minimal 模式的 JSON-RPC Composition 在 Windows 上支持不完整,报错就换 Standard 模式;二是部分依赖 Python 的插件(如 Vision Toolkit)需要额外装 Python 3.11+。

Q3:dsh webpnpm dsh web 有什么区别?

dsh 是全局安装的命令;pnpm dsh 是仓库内开发模式。开发本地插件必须用 pnpm dsh(配 --patch),因为 npx/全局安装的 dsh 不会加载你本地新建的插件源码。

Q4:插件装完为什么界面没反应?

插件宿主代码和浏览器代码都在启动时加载。改完插件、装完新插件,必须重启 Web Profile(或重启 dsh web),只刷新页面没用。

Q5:MISSING_CREDENTIAL / UNKNOWN_MODEL 怎么解决?

两个都是配置问题。前者用 dsh credentials set 变量名 补凭据;后者去设置里核对模型 ID 是否真实存在、是否填错。

Q6:能不能只用 Harness 跑 CLI,不打开浏览器?

可以。dsh web 是 Web 模式,还有 CLI 模式可以直接在终端里跑 Agent;Python SDK 也能在脚本里驱动本地 dsh 服务(见 9.5 节)。

Q7:插件写坏了会不会把系统搞崩?

插件运行在宿主进程里,写坏的插件可能导致服务崩溃——但配置和工作区数据都在磁盘上,重启服务即可恢复。开发时建议用独立 Profile 试插件,别直接在正式配置上折腾。

十五、写在最后

最后回看那个"离谱"的 README,你会发现:

"一切皆插件"不是一句空话。 模型是插件,功能是插件,界面是插件,连调度循环本身都是插件。DeepSeek 把 Agent 运行时的每一块骨头都拆成了可替换的积木,这既是它对 Claude Code / Codex 单体架构的釜底抽薪,也是它给 Agent 生态的"安卓时刻"投名状。

GitHub:https://github.com/deepseek-ai/deepseek-harness

官方页面:https://deepseek.com/harness/

下一步:把官方仓库拉下来,试试把 packages/llm/ 换成一个本地 Ollama 模型,看看"模型也是插件"到底是怎么换的——那又是另一篇实战了。觉得有用的话,点个赞让我知道,下篇安排。源码可私信获取。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值