JOTO
Contact us
← AI 智库
开源模型

DeepSeek Harness 保姆级使用教程

2026 年 9 月 4 日

DeepSeek Harness保姆级教程,照做即通「装→配→跑→写插件」全流程,0.1.2-alpha.1版本官方源码实操指南。 核心内容: 1. DeepSeek Harness的定义与架构(Agent=Model+Harness,插件化设计) 2. 环境准备要求(Node.js/pnpm版本、API key、DSH_HOME配置) 3. 安装启动双路径(npm快速入门与源码运行)

这份教程的目标只有一个:让你照做一遍就走通「装 → 配 → 跑 → 写插件 → 加载 → 批处理」的完整闭环。版本快照是官方源码 0.1.2-alpha.1(开发者预览,官方已明示未来会有破坏兼容性的变更)。

下面就跟云朵君一起开始吧~

01先搞清它是什么

DeepSeek Harness(简称 dsh)是 DeepSeek 开源的 agent harness(智能体框架),核心公式一句话:Agent = Model + Harness。模型是可替换的部件,Harness 负责模型之外的几乎所有东西——工具注册、任务规划、沙箱、会话存储、agent 循环。

DeepSeek Harness 保姆级使用教程

它不是模型,也不是又一个「成品编码工具」:它构建在 Cordis 元框架之上,slogan 是 「一切皆插件」(Everything is a Plugin)。模型适配器、会话存储、工具集、沙箱、agent 循环本身,全都是可以热插拔的插件。想给它的某个 session 换一套能力,就「挂一个插件在旁边」,而不是去 fork 源码改核心。

我们后面所有操作,都会反复碰到这几个词:插件(plugin)、profile(具名组合)、bundle(分发包)、patch(改/插一行的配置文件)。

02环境准备

依赖
要求
Node.js
^22.19.0
 或 >=24.0.0(官方 engines 声明)
pnpm
插件 / 从源码构建需要(官方 packageManager 为 pnpm 11)
DeepSeek API key
官方平台申请;同时覆盖模型调用与内置联网搜索

两点提前说明:

  • DSH_HOMEdsh 把 profile、凭据、session 等持久化内容放在 Harness home 里(默认相关目录可被环境变量 DSH_HOME 显式覆盖)。手动安装会用 ~/.dsh;用 Python SDK 时官方故意不读 ~/.dsh,要求你显式传 dsh_home,这一点后面会说。
  • 安装体积不小:因为「一切皆插件」是真的按包拆分,@deepseek-ai/dsh 及其同类插件包的依赖树比较大,受限环境(无 root / 沙箱)下 npm install 可能明显变慢,这是正常现象,不是装错。

03安装并启动:两种路径

路径 A:直接用 npm(最快入门)

npx @deepseek-ai/dsh web

DeepSeek Harness 保姆级使用教程 配图 2

默认会在 http://127.0.0.1:3080 启动 Web UI,本机启动时还会用默认浏览器自动打开。只想起服务、不自动开浏览器就加参数:

npx @deepseek-ai/dsh web --no-open

路径 B:从源码跑(想读源码 / 改插件时)

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

DeepSeek Harness 保姆级使用教程 配图 3

说明:pnpm run build 负责准备构建产物,pnpm dsh web 直接使用这些产物,不会再重新构建。

DeepSeek Harness 保姆级使用教程 配图 4

首次跑通

浏览器打开 http://127.0.0.1:3080 后:

DeepSeek Harness 保姆级使用教程 配图 5

DeepSeek Harness 保姆级使用教程 配图 6

  1. 打开 Settings → Models,填入 DeepSeek API key 并保存。官方文档说明 key 保存后立即生效,不用重启服务;凭据存在 $DSH_HOME/.credentials.yaml,页面只显示脱敏后的描述,不显示明文。
  2. 点击 Choose workspace,加入你启动 dsh 的那个项目目录并选它。没选 workspace 之前,会话输入框是不可用的。
  3. 新建一个 session,发一句最简单的任务,比如「Summarize this repository and identify its main packages.」。它就能读、改 workspace 文件、跑命令、委派子任务,并在需要审批的操作前问你。

DeepSeek Harness 保姆级使用教程 配图 7

DeepSeek Harness 保姆级使用教程 配图 8

好了,到此咱们就可以初步使用了,再进一步就是插件的使用和开发了~

04认识 profile / bundle / patch

一台跑起来的 dsh,本质上是一个「插件树」,启动时按固定的层叠顺序组装:

profile 中的每个 bundle(按声明顺序)
  → profile 自己的 cordis.patch.yml
  → home 级 $DSH_HOME/cordis.patch.yml
  → 命令行 --patch 覆盖层

三个概念:

  • profile:一个「具名组合」,躺在 Harness home 里。列出堆叠哪些 bundle、装了哪些 out-of-tree 插件、以及你自己的 cordis.patch.yml。内置模板:webheadlesssdksdk-minimalacp
  • bundle:一组 Cordis 配置行 + 它们挂载的代码,是「分发包」格式。比如 @deepseek-ai/dsh-base 提供模型接入、完整工具集、持久化会话、沙箱与权限策略;@deepseek-ai/dsh-web-app 追加浏览器应用;@deepseek-ai/dsh-headless 追加无 server 的一次性 runner。
  • patch:一个「按 id 改一行或插一行」的 YAML 文件。插件路径必须是绝对路径;对同一条配置,后应用的层优先,patch 替换的是目标行的整个 config,不是深度合并。

看效果用这条命令:

dsh --profile web --dump-config

DeepSeek Harness 保姆级使用教程 配图 9

它会把你机器实际装配出来的插件树打印出来;--dump-default-config 打印的是默认树(不启动)。每一行都是「id + 包名 + config」,也就是「一切皆插件」最直观的现场——模型、工具、会话、agent 循环全是一排可以 patch 的插件行。

DeepSeek Harness 保姆级使用教程 配图 10

05写你的第一个插件

先建个 scratch 项目(假设你已经在仓库根目录,dsh 默认把运行目录当 workspace):

mkdir -p scratch-plugin/src

一个插件就是一个 TypeScript 模块,导出一个 apply(ctx) 函数:

// scratch-plugin/src/my-plugin.ts
import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello-plugin'

export function apply(ctx: Context) {
  console.log('[hello-plugin] plugin loaded!')
}

这就是完整的配置。dsh 加载插件时调用 apply 并把 ctx 传进来,你通过 ctx 注册能力。

插件有三种写法,功能场景不同:

// 对象形式
export default {
  name: 'my-plugin',
  inject: ['tools'],
  apply(ctx: Context) { /* ... */ },
}

// 类形式:当你要把自己的服务提供给别的插件用时,通常用这种
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MyService extends Service {
  static inject = ['tools']
  constructor(ctx: Context) {
    super(ctx, 'myService')
  }
}

函数形式在大多数场景够用;类形式主要用于「你提供了一个 service 给其他插件消费」。

声明依赖:inject

如果插件要用某个 service(比如 tools 或 llm),在 inject 里声明:

export const name = 'my-tool-plugin'
export const inject = ['tools']

export function apply(ctx: Context) {
  // 到这里 ctx.tools 一定已就绪
  ctx.tools.register(/* ... */)
}

Cordis 会等 inject 里声明的依赖全部就绪再加载你的插件,所以 apply 里不用判空

自动清理:ctx.effect

凡是经 ctx 注册的东西——事件监听、工具、定时器——插件卸载时都会自动清理:你不用手动 removeListener 或 clearInterval。需要显式释放心智资源(比如一个网络连接)时,用 ctx.effect 返回 disposer:

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

export function apply(ctx: Context) {
  ctx.effect(() => {
    const timer = setInterval(() => {
      console.log('heartbeat')
    }, 5000)
    // 插件卸载时执行
    return () => clearInterval(timer)
  })
}

06用 defineTool 写一个工具插件

工具是「模型能看到的插件」。一个最小工具长这样:

// scratch-plugin/src/my-plugin.ts(覆盖前面 hello 版本)
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 `Hello, ${args.name}!`
    },
  }))
}

带异步 I/O 的经典例子是读文件(adding-a-tool),注意 exec.signal 被直接透传:

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

export const name = 'read-file-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'read_file',
    description: 'Read a file from disk.',
    parameters: {
      path: { type: 'string', required: true, description: 'Absolute path' },
      limit: { type: 'number' }, // 非必填
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args, exec) {
      return readFile(args.path, { encoding: 'utf8', signal: exec.signal })
    },
  }))
}

parameters 一个 schema 干三件事

  1. 推断 args 的 TypeScript 类型(execute 里直接拿到类型安全的参数);
  2. 在 execute 运行之前,校验模型生成的参数(类型、必填、字面量约束等);
  3. 自动注入进 system prompt,让模型知道有这样一个工具。

execute 的执行契约(写之前必读)

官方在 tool authoring reference 里写死了五条规则:

  1. args 已校验execute 里拿到的参数一定已按 parameters schema 校验过。
  2. 返回一个 canonical JSON 值:不是内容块,也不要让调用方去解析一段散文来拿 id 和字段。
  3. 抛错或返回非法值 = isError:只有基础设施故障才 throw;非理想的业务结果(比如进程非零退出)应放进返回值里表达。
  4. 尊重 exec.signal:用它取消进行中的工作(上面的 readFile 就是直接透传)。
  5. UI 卡片与 output.render 分离presentCall/presentResult 必须是 args(加结果)的纯函数,不能做 I/O。

长任务不要走前台 execute,而是走 ctx.jobs.start(...)(后台 job)。工具注册是 effect 式的:插件卸载,工具自动注销,不留「还挂在那儿但没人管」的孤儿状态。

07加载插件的三步闭环

光有 apply(ctx) 不行,dsh 得知道插件文件在哪、什么时候加载。官方教程的最小闭环是三步,每一步都能复现:

第一步:落插件文件。 把上面的 greet-tool(或 read-file-tool)存成 scratch-plugin/src/my-plugin.ts

第二步:写挂载点 cordis.yml 一个 patch 文件往插件树里插一行,name 必须是绝对路径

# scratch-plugin/cordis.yml
- insert:
    - id: hello
      name: '/绝对路径/到/deepseek-harness/scratch-plugin/src/my-plugin.ts'

第三步:用 --patch 叠加启动。 装的是 npm 包就跑:

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

从源码跑就是:

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

启动时终端会打印 [hello-plugin] plugin loaded!(如果你还留着 hello 版)或工具注册完成。接着在浏览器里问模型:

Use the greet tool to greet Ada.

模型调用 greet 后会拿到 Hello, Ada! 作为工具结果。

想确认插件树确实多了一行,用:

dsh --profile web --dump-config

拉到最后,会看到 id: hello(或你的插件 id)这一行。

卸载同样干净。 去掉 --patch 重启,或从 cordis.yml 删掉那一行,插件注册会随插件一起 unwind。不用手动清任何东西——这就是可逆 effect 最直观的一次兑现。

PTC mode(脚本优先模式)

DSH_TOOLS_MODE 环境变量为进程选择 nativeptc 或 both(其他值会导致启动失败)。PTC 模式下,模型先出脚本再把脚本交给执行能力跑,更贴合「确定性一步一步执行」的批处理业务。对应地,注册过的工具也能被脚本直调,参数与返回类型都从同一个 schema 推出来,走的是正常执行管线(含权限策略)。

08服务与 seam:能力怎么拆

「工具」只是插件的一种。真正的扩展单元叫 seam(能力缝),一个可替换的能力由三个角色组成:

角色
职责
Service Definition
声明接口(能力的契约)
Service Provider
实现它并挂到 ctx 的一个 key 上
Consumer
按 key 取用,不 import 具体实现

官方原话:只写一个角色不算 seam,加一个能力要把三个都设计全。("one role alone is not a seam; adding a capability means designing all three.")

Consumer 侧的写法值得记住,因为它体现了「硬依赖 vs 可选依赖」:

export const inject = ['tools', 'shell', 'systemPrompt', 'shellEnv']

// 已 inject 的 service,直接属性访问,缺了就起不来
const defaultMode = ctx.shell.sandboxMode

// 未 inject 的可选 service,可能返回 undefined,要自己判空
const sandboxPolicy = defaultMode === undefined ? undefined : ctx.get('sandboxPolicy')

inject 声明 + 直接属性访问 = 硬依赖;ctx.get(...) = 可选依赖。拦截与策略走事件(ctx.on / waterfall),直接能力调用走 service 方法,别混。

共享执行世界是这个设计最值钱的地方:文件系统和子进程 provider 共享同一个「执行世界」。你把沙箱 provider 指到远程环境,Bash、PTY、LSP 会一起跟着搬,不用给每个能力单独写一份 provider 分叉。

09agent loop 与四个内置入口

一个 agent 循环的基本单位:

  • step:一次模型请求 + 它调用的那些工具。
  • turn:零个或多个 step。在第一个输入被 claim 之前打开,在「不再欠任何东西」时关闭。

循环内部跑一系列事件瀑布(agent/pre-step → agent/request → llm/stream → tools/pre-execute → tools/execute → tools/post-execute → tool/result → turn/end),其中 agent/* 和 tools/* 大多是 waterfall(监听器要调 next() 委托给下一个),agent/turn-stopping 是 serial(没有 next())。

对使用者来说,更常打交道的是一套内置 profile 入口

命令
用途
dsh web--profile web
 的别名,浏览器交互式 Web UI
dsh --profile headless "任务"
跑一次一次性任务,打印最终答案并退出
dsh --profile sdk
给 SDK 客户端提供 JSON-RPC stdio 服务
dsh --profile sdk-minimal
独立极简 agent 树(持久 bash + str_replace_editor)
dsh --profile acp
通过 ACP stdio 服务自动化客户端
dsh plugin --profile
管理某 profile 的插件(转发给 pnpm)

内置 webheadlesssdksdk-minimalacp 首次使用会从随附模板自动初始化;自定义 profile 才需要 dsh plugin 创建。给某个 session 组合一套不同的能力集,就 compose 一个 agent preset——preset 里的 service 行需要一个 isolate realm,保证这套能力不污染其它 session 的作用域。

10headless:命令行一次性任务

dsh 相对交互式套装最实在的一个入口是 headless:无 GUI、无 server、一次一个任务、跑完退出

dsh --profile headless "run the tests"

输出契约(官方文档明确写死):

  • 每个非空推理增量写到 stderr(带 dsh: reasoning: 前缀);
  • 最终答案写到 stdout
  • 正常完成 exit 0;中止或出错 exit 1(错误会在 stderr 打 dsh: :);
  • 任务缺失或为空,还没开始跑就 exit 1;
  • 一次运行只有一个任务,没有交互式 follow-up;要拆开多段工作就分多次运行。

dsh --profile headless --help 只打印帮助、不运行任何任务。它很适合脚本、CI 和一次性批处理:进程不监听端口,跑完自己就退。

由于官方尚未安全审计,headless 等于把未审计能力放在无人值守模式下跑,所以请先拿它做可回滚的迁移/实验任务,别让它去执行不可逆的批量写操作。

11Python SDK:给你的代码一个 agent 入口

dsh 本体是 TypeScript/Node 栈,但官方提供了一个 Python SDK 作为批处理入口(注意:是入口,不是 dsh 本体)。

安装:

python -m pip install deepseek-harness-sdk

它会自动带上同版本的原生 runtime wheel 和 dsh 命令,正常 SDK 运行不需要系统 Node.js。最小用法:

from deepseek_harness import DeepSeekHarness

with DeepSeekHarness(
    dsh_home="/absolute/path/to/isolated-dsh-home",
    cwd="/absolute/path/to/workspace",
    provider="deepseek-official",
    model="deepseek-v4-flash",
) as harness:
    result = harness.run("Inspect the repository and fix the failing tests.", session_id="example-001")

print(result.final_response)

几个关键点,缺了都会踩坑:

  • dsh_home 必须显式传(或设 DSH_HOME),SDK 故意不读 ~/.dsh
  • cwd 是 agent 的 workspace;provider/model 在初始化握手时发送;
  • DeepSeekHarness 是懒启动的,复用一个 runtime 直到 close() 或退出 with 块;
  • profile 默认 sdk,极简用 profile="sdk-minimal"(后者只组合持久 bash + str_replace_editor,系统提示词固定为 You are a helpful software engineer assistant.)。

想给 Python 用的 run 装持久插件,走 profile 管理:

export DSH_HOME=/absolute/path/to/isolated-dsh-home
dsh --profile sdk --dump-default-config >/dev/null
dsh plugin --profile sdk add file:/absolute/path/to/my-plugin-bundle

命令级 patches=("/path/to/foo.patch.yml",) 则用于「本次 run 生效、不持久化」的临时变更。harness.run() 返回 RunResult(session_id, final_response, finish_reason, events, notifications)final_response 是该区间最后一个根会话 assistant 文本。

12会话日志:model-visible means logged

会话日志是 dsh 里一个架构级硬约束,而不是事后补的仪表盘:模型看到的一切,必须能从会话日志重建("Model-visible means logged")。

DeepSeek Harness 保姆级使用教程 配图 11

日志是 append-only 的。每一条 prompt 片段、每一次工具调用的输入输出、原始响应都在。fork、回放、转录、telemetry、持久化,全部从这一条日志流派生。官方的运行时不变式会断言它。这意味着:当你排查一个 agent 为什么干了蠢事时,trace 不会被「没记」或「记不全」卡死——不满足这条约束,这套系统根本起不来。

13写在最后

把上面所有步骤走完,你已经有了一套能跑通 dsh 的手感。最后给你几条真实的边界,都是有出处的:

  1. 开发者预览。版本 0.1.2-alpha.1,官方明示「未来将出现破坏兼容性变更」。本文的命令与 API 都基于这个快照,投产前一定对照官方最新源码复核。
  2. 官方自标未安全审计。SAFETY 文档写得很直白:尚未接受安全审计,不得视为安全或可用于生产环境的软件;沙箱、审批与权限控制不保证隔离。负责任使用的最小操作清单是:最小权限、优先一次性 VM/容器/专用环境、重要文件先备份、跑之前先审插件与命令。
  3. 没有终端 TUI。交互式使用要开浏览器(或走 headless 跑一次性任务);习惯纯终端 TUI 的人会不适应。
  4. 要自管 key 和模型。dsh 不附送模型,你要自己配 key、自己选 provider;本地 runtime(Ollama/LM Studio 这类)不在默认开箱路径里,要走「自定义 provider」配 OpenAI 兼容端点。
  5. 安装重、版本迭代快。插件按包拆分,安装体量不小;官方仍是 alpha/rc 版本、处于快速迭代期,API 可能很快变,一切以官方最新为准。
  6. headless 一次一任务。不是多轮交互客户端代理,多段工作拆多次运行。
DeepSeek Harness 保姆级使用教程 配图 12

落到结论就是:装起来玩、读它的架构、在可回滚的环境里做实验,是对的;现在直接接生产、或对它跑不可逆批处理,时机还没到。 它并不打算替代你手里已经能用的编码工具,而是把「agent 框架应该长什么样」这件事往前推了一档——想按它这条路深挖,官方仓库的 docs/architecture.mddocs/cordis-primer.md 和 docs/cookbook/ 就是下一步最该翻的入口

立即咨询 JOTO

JOTO 提供覆盖企业智能体规划与搭建、AI 平台私有化部署、RAG 知识工程、AI 安全治理、FDE 驻场共创及持续运营优化的全周期 AI 落地服务,帮助企业把验证中的 AI 能力转化为安全、可控、可持续迭代的生产力。 联系 JOTO 获取 AI 落地咨询

想把这些做法用到你的业务里?

留下你的场景和痛点,我们帮你判断从哪一步开始。

联系我们
Contact Us

Start your enterprise AI rollout

Tell us your industry, team, and current pain points. We'll get back to you within one business day to help you decide what to tackle first, what data to prepare, and which platform fits.

WeChat
Scan to add us for a 1:1 chat
JOTO WeChat consultation QR code

Tell us what you need

Once we receive your details, we'll be in touch within one business day.