DeepSeek Harness 快速上手:从安装到自定义插件开发全流程指南
前言
在 AI Agent 开发领域,框架的选择直接影响项目的开发效率和可扩展性。DeepSeek Harness(以下简称 dsh)是 DeepSeek 开源的一款智能体开发框架,其核心理念是「一切皆插件」,通过模块化设计让开发者能够灵活组合不同的能力组件。
本文将基于 0.1.2-alpha.1 版本,手把手带你走通从环境安装、Web UI 启动、插件开发到 Python SDK 集成的完整流程。无论你是想快速体验 Agent 能力,还是计划基于 Harness 构建自己的智能体应用,这份指南都能帮你节省大量摸索时间。
一、DeepSeek Harness 是什么
在深入技术细节之前,我们先来理解 Harness 的设计哲学。官方给出了一个简洁的公式:
Agent = Model + Harness
- Model(模型):负责推理和决策,是可替换的部件
- Harness(框架):负责模型之外的所有工作,包括工具注册、任务规划、沙箱隔离、会话存储、Agent 循环控制
Harness 构建在 Cordis 元框架之上,这一设计让它天然支持插件化扩展。框架的核心特性包括:
- 热插拔插件:模型适配器、会话存储、工具集、沙箱、执行循环等都可以独立替换
- Profile 机制:通过具名组合(Profile)管理不同的能力集合
- Patch 配置:支持通过 YAML 文件精细化调整插件行为
- 会话日志:架构级约束,确保所有模型可见内容均可回溯
理解这些概念后,我们的环境配置就会变得清晰明了。
二、环境准备与依赖要求
在开始安装之前,请确保你的开发环境满足以下要求:
Node.js 版本:官方要求 Node.js ^22.19.0 或 >=24.0.0,可通过 node -v 命令检查当前版本。
pnpm 包管理器:Harness 使用 pnpm 11 作为官方包管理器。如果尚未安装,可以通过 npm install -g pnpm 全局安装。
DeepSeek API Key:需要在 DeepSeek 官方平台申请。这个 Key 同时覆盖模型调用和内置联网搜索两个功能。
关于 DSH_HOME:dsh 会将 Profile、凭据、会话等持久化内容存放在 Harness Home 目录。默认情况下,手动安装使用 ~/.dsh 目录。可以通过环境变量 DSH_HOME 显式指定。特别提醒:如果使用 Python SDK,官方故意不读取 ~/.dsh,需要你在代码中显式传入 dsh_home 参数。
安装体积说明:由于「一切皆插件」的设计理念是真实按包拆分的,@deepseek-ai/dsh 及其插件包的依赖树相对较大。在受限环境(无 root 权限或沙箱)下,npm install 可能会明显变慢,这是正常现象,不是安装出错。
三、安装与启动:两种路径对比
路径一:npm 快速入门
这是最简单的入门方式,适合想快速体验框架能力的开发者。执行以下命令即可启动 Web UI:
npx @deepseek-ai/dsh web
服务默认在 http://127.0.0.1:3080 启动,并会自动打开默认浏览器。如果只想启动服务而不打开浏览器,可以添加参数:
npx @deepseek-ai/dsh web --no-open
路径二:从源码运行
如果你是开发者,想深入研究框架源码或开发自己的插件,建议从源码运行:
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web
重要说明:pnpm run build 负责准备构建产物,pnpm dsh web 直接使用这些产物,不会重复构建。
首次配置
浏览器打开后,你需要完成以下初始配置:
- 打开 Settings → Models,填写 DeepSeek API Key 并保存
- 凭据会保存在
$DSH_HOME/.credentials.yaml,页面只显示脱敏后的描述 - 点击 Choose workspace,选择你的项目目录
- 确认 workspace 后,会话输入框即可使用
现在你可以发送第一个任务试试,比如:「Summarize this repository and identify its main packages.」框架会自动分析代码结构、读写文件、执行命令。
四、理解 Profile、Bundle 与 Patch
Harness 的灵活性很大程度上来自于这三个核心概念的协作。理解它们,你才能真正掌握框架的配置艺术。
Profile:具名能力组合
Profile 躺在 Harness Home 里,定义了堆叠哪些 Bundle、装了哪些外部插件、以及自定义的 cordis.patch.yml。内置模板包括:
- web:带浏览器界面的交互式环境
- headless:无 GUI 的一次性任务执行
- sdk:提供 JSON-RPC stdio 服务的 SDK 客户端
- sdk-minimal:极简独立 Agent 树
- acp:通过 ACP stdio 服务的自动化客户端
Bundle:分发包
Bundle 是一组 Cordis 配置行及其挂载代码的集合,是标准的「分发包」格式。例如:
@deepseek-ai/dsh-base:提供模型接入、完整工具集、持久化会话、沙箱与权限策略@deepseek-ai/dsh-web-app:追加浏览器应用@deepseek-ai/dsh-headless:追加无 Server 的一次性 Runner
Patch:按行配置
Patch 是一个 YAML 配置文件,用于「按 ID 改一行或插一行」。规则是:插件路径必须使用绝对路径;对于同一配置,后应用的层优先级更高。
查看当前配置树的有效方式是:
dsh --profile web --dump-config
这条命令会打印出你机器上实际装配的插件树,每一行都是「ID + 包名 + 配置」。如果想看默认配置树(不启动服务),用 --dump-default-config。
五、编写你的第一个插件
插件是 Harness 的基本扩展单元。一个插件就是一个 TypeScript 模块,需要导出一个 apply(ctx) 函数。以下是最小插件示例:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded!')
}
三种插件写法
函数形式(最常用):
export default {
name: 'my-plugin',
inject: ['tools'],
apply(ctx: Context) {
// 插件逻辑
},
}
类形式(用于提供 Service):
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MyService extends Service {
static inject = ['tools']
constructor(ctx: Context) {
super(ctx, 'myService')
}
}
声明依赖: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 中声明的依赖全部就绪后再加载你的插件。
自动清理:ctx.effect
经 ctx 注册的一切(事件监听、工具、定时器)在插件卸载时都会自动清理。如果需要显式释放资源(如网络连接),返回 disposable 函数:
export function apply(ctx: Context) {
ctx.effect(() => {
const timer = setInterval(() => {
console.log('heartbeat')
}, 5000)
// 插件卸载时执行清理
return () => clearInterval(timer)
})
}
六、使用 defineTool 开发工具插件
工具是「模型能看到的插件」,通过 defineTool 定义。以下是一个完整的 Greeter 工具示例:
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}!`
}
}))
}
execute 的执行契约
官方在工具编写参考中明确了五条规则,这是编写可靠工具的关键:
- 参数已校验:execute 拿到的参数一定已按 schema 校验过
- 返回规范 JSON 值:不是内容块,不要让调用方解析散文
- 错误处理:基础设施故障才 throw;非理想业务结果应放进返回值
- 尊重 exec.signal:用它取消进行中的工作
- 长任务走后台:使用
ctx.jobs.start(...)而非前台 execute
文件读取示例
带异步 I/O 的经典例子是文件读取,注意 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 })
}
}))
}
七、插件加载的三步闭环
光有 apply(ctx) 还不够,dsh 需要知道插件文件的位置和加载时机。官方教程的最小闭环是三步:
第一步:保存插件文件到 scratch-plugin/src/my-plugin.ts
第二步:创建挂载点配置 scratch-plugin/cordis.yml:
- insert:
- id: hello
name: '/绝对路径/to/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!。验证插件树:
dsh --profile web --dump-config
拉到输出末尾,你会看到新注册的插件行。
卸载同样干净:去掉 --patch 重启,或从 cordis.yml 删除对应行,插件会自动 unwind,不留任何孤儿状态。
八、Python SDK 集成
Harness 本体是 TypeScript/Node 栈,但官方提供了 Python SDK 作为批处理入口。注意:Python SDK 是入口,不是 Harness 本体。
安装:
python -m pip install deepseek-harness-sdk
SDK 会自动带上同版本的原生 runtime wheel 和 dsh 命令,正常运行不需要系统安装 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必须显式传递,SDK 故意不读取~/.dshcwd是 Agent 的 workspace 目录provider/model在初始化时发送DeepSeekHarness是懒启动的,复用一个 runtime 直到close()或退出 with 块- profile 默认为
sdk,极简场景用profile="sdk-minimal"
九、会话日志与安全边界
会话日志架构
「Model-visible means logged」是 Harness 的架构级硬约束:模型看到的一切,必须能从会话日志重建。每一条 prompt、每一次工具调用的输入输出、原始响应都完整记录。
这意味着当你排查 Agent 行为异常时,不会遇到「trace 没记」或「记不全」的问题。
安全边界警示
官方明确标注 Harness 尚未通过安全审计,不得视为安全或可用于生产环境的软件。沙箱、审批与权限控制不保证隔离。负责任使用的最小操作清单:
- 最小权限原则:只用完成任务所需的最小能力集
- 隔离环境优先:优先在一次性 VM、容器或专用环境运行
- 重要文件先备份:操作前做好数据保护
- 审慎审查插件:跑之前先审查插件源码和命令逻辑
十、总结与后续路径
走完以上步骤,你已经具备了 Harness 的基本使用能力。框架的核心理念——「一切皆插件」——体现在每一个设计细节中:Profile 管理能力组合、Bundle 分发功能模块、Patch 精细化配置、Seam 提供可替换能力。
后续深入学习的建议路径:
- 阅读官方仓库的
docs/architecture.md理解整体架构 - 学习
docs/cordis-primer.md掌握插件系统原理 - 参考
docs/cookbook/中的实战食谱
重要提醒:当前版本为 0.1.2-alpha.1(开发者预览),官方明确表示未来将有破坏兼容性变更。在生产环境使用前,请务必对照官方最新源码复核。
DeepSeek Harness 的定位不是替代现有编码工具,而是探索「Agent 框架应该是什么样」的可能性边界。想在这个方向深入探索,官方仓库的文档是最权威的参考资料。
