菜单
积墨AI

积墨AI

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 直接使用这些产物,不会重复构建。

首次配置

浏览器打开后,你需要完成以下初始配置:

  1. 打开 Settings → Models,填写 DeepSeek API Key 并保存
  2. 凭据会保存在 $DSH_HOME/.credentials.yaml,页面只显示脱敏后的描述
  3. 点击 Choose workspace,选择你的项目目录
  4. 确认 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 的执行契约

官方在工具编写参考中明确了五条规则,这是编写可靠工具的关键:

  1. 参数已校验:execute 拿到的参数一定已按 schema 校验过
  2. 返回规范 JSON 值:不是内容块,不要让调用方解析散文
  3. 错误处理:基础设施故障才 throw;非理想业务结果应放进返回值
  4. 尊重 exec.signal:用它取消进行中的工作
  5. 长任务走后台:使用 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 故意不读取 ~/.dsh
  • cwd 是 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 提供可替换能力。

后续深入学习的建议路径:

  1. 阅读官方仓库的 docs/architecture.md 理解整体架构
  2. 学习 docs/cordis-primer.md 掌握插件系统原理
  3. 参考 docs/cookbook/ 中的实战食谱

重要提醒:当前版本为 0.1.2-alpha.1(开发者预览),官方明确表示未来将有破坏兼容性变更。在生产环境使用前,请务必对照官方最新源码复核。

DeepSeek Harness 的定位不是替代现有编码工具,而是探索「Agent 框架应该是什么样」的可能性边界。想在这个方向深入探索,官方仓库的文档是最权威的参考资料。

#DeepSeek Harness#Cordis 框架#插件化架构#Tool Calling#defineTool#Python SDK
分享文章

相关文章推荐

试用咨询
企业微信二维码

扫码添加企业微信