DeepSeek Harness 源码版:从下载到第一个插件开发完整指南

日期:2026-08-22
环境:macOS 15.7.9 (Intel x86-64)、Oh My Zsh、node@24
DSH 版本:0.1.0-rc.8(源码版)


前言

DeepSeek Harness(简称 DSH)是 DeepSeek 开源的 AI Agent 框架,支持插件扩展。本文记录从源码下载、构建、启动,到开发并验证第一个插件的完整过程,包括所有踩过的坑和解决方案。

适用人群:想基于 DSH 开发插件、或想深入了解 DSH 源码的开发者。


一、环境准备

1.1 系统要求

  • macOS / Linux / Windows
  • Node.js v22.13+(关键!v20 不够)
  • pnpm(通过 corepack 自动管理)
  • git

1.2 Node.js 版本管理(最容易踩的坑)

DSH 源码构建需要 Node.js v22.13+,因为:

  • pnpm 11 需要 node v22.13+
  • 代码中使用了 node:sqlite 等较新的内置模块

检查你的 node 版本

node --version

如果低于 v22.13,需要安装新版本。以 macOS Homebrew 为例:

# 安装 node@24
brew install node@24

# 验证安装
/usr/local/opt/node@24/bin/node --version
# 输出:v24.x.x

二、第一步:下载源码

2.1 克隆仓库

选择一个工作目录,克隆 DSH 源码:

# 创建工作目录
mkdir -p ~/workspace/DSH
cd ~/workspace/DSH

# 克隆源码
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness

2.2 目录结构概览

deepseek-harness/
├── apps/              # 应用入口
│   └── cli/           # CLI 命令行工具
├── packages/          # 核心包(200+ 个子包)
│   ├── boot/          # 启动引导
│   ├── core/          # 核心功能(agent、session、tools 等)
│   ├── client/        # 前端 UI 组件
│   ├── llm/           # LLM 提供商适配
│   ├── shell/         # Shell 工具
│   └── ...
├── vendor/            # 第三方依赖(cordis、loader 等)
├── docs/              # 文档
├── package.json       # 根 package.json(monorepo)
├── pnpm-workspace.yaml
└── tsconfig.json

DSH 是一个 monorepo 结构,包含 200+ 个子包,用 pnpm 管理。


三、第二步:安装依赖

cd ~/workspace/DSH/deepseek-harness

# 用 node@24 安装依赖
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm install

💡 corepack pnpm 会自动按 package.json 里的 packageManager 字段下载对应版本的 pnpm,不需要全局安装 pnpm。

安装完成后,目录大小约 1.7GB(含所有依赖)。


四、第三步:构建源码(重点,有坑)

4.1 为什么必须构建?

DSH 用 TypeScript 编写,运行时需要编译成 JavaScript。克隆下来的源码只有 .ts 文件,没有编译产物,直接启动会报错:

Error: Cannot find module '.../typert.host.js'
Error: client bundles not found; run `pnpm run build` before launch

4.2 构建命令

cd ~/workspace/DSH/deepseek-harness

# 用 node@24 构建(关键!用 v20 会失败)
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm run build

构建过程约 20-30 秒,会编译全部 200+ 个子包。

4.3 构建失败的常见原因

错误 1:node:sqlite 模块找不到
Error: Cannot find module 'node:sqlite'

原因:用了 node v20,node:sqlite 是 node v22+ 才有的内置模块。

解决:确保用 node@24 运行构建命令(加上 PATH 前缀)。

错误 2:pnpm 版本要求 node v22.13+
ERROR: This version of pnpm requires at least Node.js v22.13

原因:同上,node 版本太低。

解决:同上。

4.4 验证构建结果

构建完成后,检查之前缺失的文件是否生成:

# 检查 typert.host.js
ls -la packages/context/session-reference/lib/typert.host.js

# 检查 4 个 client 包
for pkg in ui-renderer ui-brand-official ui-attachment ui-reference; do
  ls -la packages/client/$pkg/lib/client.js
done

所有文件都存在,说明构建成功。


五、第四步:启动验证

5.1 查看版本

cd ~/workspace/DSH/deepseek-harness
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh --version
# 输出:0.1.0-rc.8

5.2 启动 Web 模式

cd ~/workspace/DSH/deepseek-harness
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web

启动成功后,日志会显示访问地址(通常是 http://127.0.0.1:3080/)。在浏览器中打开,确认 Web UI 正常加载。

Ctrl+C 停止服务。

六、第五步:开发第一个插件

6.1 插件目录结构

在工作目录下创建插件项目:

~/workspace/DSH/dsh-plugins/
└── hello-plugin/
    ├── package.json          # 包配置
    ├── cordis.patch.yml      # 插件注册配置(关键!)
    ├── README.md             # 说明文档
    └── src/
        └── index.ts          # 插件源码

创建目录:

mkdir -p ~/workspace/DSH/dsh-plugins/hello-plugin/src

6.2 package.json

{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "description": "DeepSeek Harness Hello World 示例插件",
  "type": "module",
  "main": "src/index.ts",
  "author": "your-name",
  "license": "MIT",
  "keywords": ["dsh", "deepseek-harness", "plugin"],
  "dsh": {
    "bundle": true
  },
  "peerDependencies": {
    "@deepseek-ai/cordis": "*",
    "@deepseek-ai/dsh-tools": "*",
    "@deepseek-ai/schemastery": "*"
  }
}

关键字段说明

  • "type": "module":ES Module 模式
  • "main": "src/index.ts":入口文件(源码版支持直接加载 .ts)
  • "dsh": { "bundle": true }:DSH 插件标记,告诉 DSH 这是一个插件包

6.3 src/index.ts(插件核心代码)

/**
 * Hello World 示例插件
 * 
 * 演示:
 * 1. 基本插件结构(name + apply)
 * 2. 注册自定义工具(Tool)
 * 3. 事件监听
 * 4. 配置项
 */

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

// 插件名称(唯一标识,建议用 kebab-case)
export const name = 'hello-plugin'

// 声明依赖:需要 tools 服务来注册工具
export const inject = ['tools']

// 插件配置接口
export interface Config {
  /** 问候语前缀 */
  greeting: string
  /** 是否启用调试日志 */
  debug: boolean
}

// 配置 Schema(用于校验和在 UI 中生成配置表单)
export const Config = Schema.object({
  greeting: Schema.string().default('你好').description('问候语前缀'),
  debug: Schema.boolean().default(false).description('是否启用调试日志'),
})

/**
 * 插件加载时调用
 * @param ctx 上下文对象,通过它注册各种能力
 * @param config 插件配置(从 settings.yaml 或 patch 读取)
 */
export function apply(ctx: Context, config: Config) {
  if (config.debug) {
    console.log(`[hello-plugin] 插件加载,配置:`, config)
  }

  // ========== 1. 注册自定义工具 ==========
  const greetTool = defineTool({
    name: 'greet',
    description: '向用户打招呼,返回个性化问候语',
    // 工具参数定义
    input: Schema.object({
      name: Schema.string().required().description('用户的名字'),
      excited: Schema.boolean().default(false).description('是否用激动的语气'),
    }),
    // 工具执行逻辑
    async execute({ name, excited }) {
      const punctuation = excited ? '!!!🎉' : '。'
      const message = `${config.greeting}${name}${punctuation}`
    
      if (config.debug) {
        console.log(`[hello-plugin] greet 工具被调用: ${message}`)
      }
    
      return { result: message }
    },
  })

  // 注册到工具注册表
  ctx.tools.register(greetTool)
  console.log('[hello-plugin] 工具 "greet" 已注册')

  // ========== 2. 事件监听 ==========
  // 监听 DSH 就绪事件
  ctx.on('ready', () => {
    console.log('[hello-plugin] DSH 已就绪')
  })

  // 监听会话创建事件
  ctx.on('session/create', (session) => {
    if (config.debug) {
      console.log(`[hello-plugin] 新会话创建: ${session.id}`)
    }
  })

  // ========== 3. 可撤销的副作用 ==========
  // 用 ctx.effect() 包裹的副作用,插件卸载时会自动清理
  ctx.effect(() => {
    console.log('[hello-plugin] 插件已激活')
  
    // 返回清理函数
    return () => {
      console.log('[hello-plugin] 插件已卸载,清理完成')
    }
  })
}

插件核心概念

  • name:插件唯一标识
  • inject:声明依赖的服务(如 tools
  • Config:配置 Schema,定义插件可配置项
  • apply(ctx, config):插件入口函数,加载时调用
    • ctx:上下文对象,通过它注册工具、监听事件、执行副作用
    • config:插件配置对象

6.4 cordis.patch.yml(插件注册配置)

这是加载插件的关键配置文件:

# cordis.patch.yml
# 插件注册配置文件
# 通过 dsh web --patch 此文件来加载插件

- insert:
  - # 插件 ID(唯一标识)
    id: hello-plugin
    # 插件入口文件的绝对路径
    # 注意:必须是绝对路径,指向插件的主文件
    name: '/Users/claw/workspace/DSH/dsh-plugins/hello-plugin/src/index.ts'
    # 插件配置(可选,会覆盖 settings.yaml 中的配置)
    config:
      greeting: '你好呀'
      debug: true

⚠️ 重要注意事项

  1. insert 必须是数组格式- insert: 下面跟 - id: ...),不能写单个对象,否则会报 Spread syntax requires ...iterable[Symbol.iterator] 错误
  2. name 必须是绝对路径,指向插件入口文件
  3. config 里的字段要和插件代码里的 Config Schema 对应

七、第六步:配置插件加载

DSH 有两种加载插件的方式:

方式 A:通过 --patch 参数临时加载(推荐,开发阶段用)

启动时指定 patch 文件:

cd ~/workspace/DSH/deepseek-harness
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web \
  --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml

优点:不需要修改全局配置,灵活切换,适合开发调试。

方式 B:通过 dsh plugin add 永久注册

# 添加插件到指定 profile
dsh plugin --profile web add /path/to/your-plugin

# 查看已安装插件
dsh plugin --profile web list

# 移除插件
dsh plugin --profile web remove <plugin-id>

⚠️ 注意:dsh plugin 命令必须带 --profile 参数。


八、第七步:启动并加载插件

8.1 用源码版启动(推荐,支持 .ts 插件)

cd ~/workspace/DSH/deepseek-harness
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web \
  --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml

九、第八步:验证插件

9.1 验证配置解析(不启动服务)

/usr/local/bin/dsh --profile web \
  --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml \
  --dump-config | grep -A 10 "hello-plugin"

预期输出

- id: hello-plugin
  name: /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/src/index.ts
  config:
    greeting: 你好呀
    debug: true

能看到这个输出,说明配置文件格式正确,dsh 能解析。

9.2 验证启动日志

启动 dsh web 后,观察终端日志,应该能看到:

[hello-plugin] 插件加载,配置: { greeting: '你好呀', debug: true }
[hello-plugin] 工具 "greet" 已注册
[hello-plugin] 插件已激活
[hello-plugin] DSH 已就绪

看到这些日志,说明:

  • ✅ 插件被正确加载
  • ✅ 配置被正确读取
  • greet 工具注册成功
  • ✅ 插件生命周期正常

9.3 验证 Web UI 工具调用

  1. 打开浏览器,访问 dsh web 地址(启动日志里会显示)
  2. 进入对话界面
  3. 在输入框里输入:“用 greet 工具向张三打招呼,要激动一点”
  4. AI 会调用 greet 工具,传入参数 name="张三", excited=true
  5. 返回结果应该是:“你好呀,张三!!!🎉”

验证点

  • 工具列表里能看到 greet 工具
  • AI 能正确调用工具并传入参数
  • 返回结果符合预期(问候语前缀 + 名字 + 标点)

9.4 验证配置生效

cordis.patch.yml 里修改配置:

config:
  greeting: 'Hello'  # 改成英文
  debug: false       # 关闭调试日志

重启 dsh web,再次调用 greet 工具,返回结果应该变成:

  • "Hello,张三。"(问候语变了,标点也变了因为 excited=false)

说明配置项生效。


十、常见问题与解决方案

Q1:构建时报 node:sqlite 找不到

A:用了 node v20。确保用 node@24 运行构建:

PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm run build

Q2:启动时报 client bundles not found

A:源码没构建。先运行 pnpm run build

Q3:npm 版 dsh 加载 .ts 插件报 Unknown file extension ".ts"

A:npm 版不支持直接加载 .ts。用源码版 dsh,或把插件编译成 .js。

Q4:cordis.patch.ymlSpread syntax requires ...iterable[Symbol.iterator]

Ainsert 格式错了。必须写成数组格式:

# ✅ 正确
- insert:
  - id: hello-plugin
    name: '/path/to/plugin'

# ❌ 错误(单个对象)
- insert:
    id: hello-plugin
    name: '/path/to/plugin'

Q5:改了插件代码后不生效

A:dsh 启动时加载插件,运行中修改不会热更新。重启 dsh web 即可。

Q6:启动后看不到 [hello-plugin] 日志

排查

  1. 确认 cordis.patch.yml 里的 name 是绝对路径
  2. 确认用的是源码版 dsh(npm 版不能加载 .ts)
  3. 确认 debug: true 开了
  4. 检查有没有报错信息

Q7:怎么关闭 dsh 服务?

A

  • 前台运行:按 Ctrl+C
  • 后台运行:pkill -f "dsh web",或 ps aux | grep "dsh web" 找到 PID 后 kill <PID>

十一、快速命令速查

# ========== 环境 ==========
# 用 node@24 运行命令
PATH="/usr/local/opt/node@24/bin:$PATH" <命令>

# ========== 源码操作 ==========
cd ~/workspace/DSH/deepseek-harness

# 安装依赖
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm install

# 构建源码
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm run build

# 查看版本
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh --version

# 启动 web(不带插件)
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web

# 启动 web(带插件)
PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web \
  --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml

# ========== 插件验证 ==========
# 验证配置解析
/usr/local/bin/dsh --profile web \
  --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml \
  --dump-config | grep -A 10 "hello-plugin"

# 插件管理(npm 版)
dsh plugin --profile web list
dsh plugin --profile web add <plugin-path>
dsh plugin --profile web remove <plugin-id>

# ========== 便捷别名(加到 ~/.zshrc)==========
# alias dsh-dev='cd ~/workspace/DSH/deepseek-harness && PATH="/usr/local/opt/node@24/bin:$PATH" corepack pnpm dsh web --patch /Users/claw/workspace/DSH/dsh-plugins/hello-plugin/cordis.patch.yml'

十二、关键路径总结

项目 路径
DSH 源码 ~/workspace/DSH/deepseek-harness/
DSH 工作区 ~/workspace/DSH/dshworkspace/
插件开发目录 ~/workspace/DSH/dsh-plugins/
示例插件 ~/workspace/DSH/dsh-plugins/hello-plugin/
DSH 配置目录 ~/.dsh/
DSH settings.yaml ~/.dsh/settings.yaml
DSH profiles ~/.dsh/profiles/
node@24 路径 /usr/local/opt/node@24/bin/node
npm 全局 dsh /usr/local/lib/node_modules/@deepseek-ai/dsh/

十三、总结

本文完整记录了 DSH 源码版从下载到第一个插件开发验证的全过程,核心要点:

  1. Node 版本是关键:必须用 v22.13+,推荐 node@24
  2. 源码必须构建:克隆后先跑 pnpm run build,否则启动报错
  3. 插件开发用源码版:npm 版不能直接加载 .ts 插件,源码版用 tsx 支持
  4. cordis.patch.yml 格式要对insert 必须是数组,name 必须是绝对路径
  5. 验证三步走:配置解析 → 启动日志 → Web UI 工具调用

掌握了这个流程,你就可以开始开发更复杂的 DSH 插件了。DSH 的插件体系基于 Cordis 框架,支持注册工具、事件监听、UI 扩展、子 Agent 等丰富能力,值得深入探索。


参考资源

  • DSH 官方仓库:https://github.com/deepseek-ai/deepseek-harness
  • DSH 插件开发文档:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/index.md
  • Cordis 框架文档:https://cordis.js.org/
  • 源码内中文文档:~/workspace/DSH/deepseek-harness/docs/cordis-primer.zh.md
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐