DeepSeek Harness 架构研究与上手指南

2,888 阅读13分钟

版本:2026-08-13 依据:deepseek-harness 仓库源码(master,提交 47f9438)+ 官方架构与用户文档 + 本机实测(npm 包 0.1.0-rc.6,Node v24.14.0,Windows) 仓库地址:github.com/deepseek-ai…


目录

1. 什么是 DeepSeek Harness(dsh)
2. 与 Kimi Code / Qwen Code 的区别
3. 安装与启动(本机实战)
4. 四大 Agent 模式(Preset)
5. dsh 的插件体系
6. Cordis:一切皆插件的底层框架
7. Profile 与 Bundle:启动时的分层组合
8. 能力接缝(Capability Seam)
9. Turn 流程与 Session Log
10. 模型配置与自定义 Provider
11. 第一次跑通:完整实战记录
12. 常见问题(FAQ)


deepseek-ai.png

1. 什么是 DeepSeek Harness(dsh)

DeepSeek Harness(命令行名 dsh)是 DeepSeek AI 开源的 agent harness(智能体框架/底座) ,采用 MIT 许可证。它的核心特征是:

  • 一切皆插件:整个产品由 Cordis 插件框架驱动——模型适配器、工具注册表、会话日志、甚至 agent 循环本身都是插件,没有"特权核心",每一部分都可以从配置层替换。
  • Web UI 形态:默认产品是浏览器应用(http://127.0.0.1:3080),不是终端 TUI;也提供无服务器的 headless 一次性运行模式和自动化用的 ACP(Agent Client Protocol)服务。
  • 多 Agent 模式:内置四种官方 Agent 模式(标准 / PTC / 极简 / 创造),还可以让 agent 自己创作新模式(见第 4 节)。
  • 开发者预览阶段:官方明确警告"未来将出现破坏兼容性的变更",仓库的发布前立场是"宁要正确的地基,不要兼容包袱"——SQLite 用单调递增的 SCHEMA_VERSION,会话格式 SESSION_FORMAT_VERSION 保持在 0,不做兼容承诺。
  • 多模型:虽然出身 DeepSeek,但模型层是能力接缝,支持 Anthropic、OpenAI 等目录 provider 和任意 OpenAI 兼容的自定义端点。

它适合两类人:想用一个可自由改造的 agent 产品的用户,以及想研究/二次开发 agent 框架的开发者(仓库本身就是高质量的架构范本,自带详尽的 docs/architecture.md 和 AGENTS.md 工程规范)。

2. 与 Kimi Code / Qwen Code 的区别

日常用的 Kimi Code、Qwen Code 是"成品 CLI",dsh 是"框架 + Web 产品",差异如下:

维度Kimi Code / Qwen CodeDeepSeek Harness
定位面向终端用户的 CLI 产品插件化 agent harness(框架即产品)
界面终端交互(TUI)浏览器 Web UI(默认 127.0.0.1:3080
模型/鉴权登录自家账号,或配 [models]自备 API key,Web UI 里配置,支持多家 provider
Agent 形态单一主 agent + 子代理派生四种可切换的 Agent 模式 + 用户自创 preset
架构单体应用,扩展靠配置/插件目录一切皆 Cordis 插件,agent 循环本身也可替换
扩展方式agent 文件、config.toml、MCP挂载 Cordis 插件、patch 配置树、写 provider
自我修改不支持创造模式:agent 可检查并改写自己运行的运行时
成熟度稳定发布开发者预览,API 随时可能破坏变更
安装单二进制 / npm 包,开箱即用npx @deepseek-ai/dsh web 或源码构建

一句话:Kimi Code 是"拿来用的工具",dsh 更像"可以自己组装的发动机"——官方把会话、工具、循环都做成可替换的接缝,连 agent 的人格和工具集都做成可切换、可创作的 preset。

3. 安装与启动(本机实战)

3.1 两种方式

方式一:直接用(推荐,类似 kimi code 的体验)

npx @deepseek-ai/dsh web

只要有 Node.js(仓库要求 ^22.19 || >=24,本机 v24.14.0)。首次运行 npx 会把包下载到缓存:

C:\Users\姜子牙\AppData\Local\npm-cache_npx<hash>\node_modules@deepseek-ai\dsh

方式二:从源码跑(研究/二次开发用)

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

⚠️ pnpm run test 等命令是纯开发流程,普通使用完全不需要。源码树约 188 MB,含 40+ 个 workspace 包。

3.2 npx 不会自动更新

npx 首次解析 latest 后就复用本地缓存,之后启动不再检查新版本(本机实测:缓存与 npm 最新同为 0.1.0-rc.6)。要确保最新:

npx @deepseek-ai/dsh@latest web        # 强制重新解析版本
# 或全局安装,便于版本管理
npm install -g @deepseek-ai/dsh
npm update -g @deepseek-ai/dsh

3.3 数据目录(DSH_HOME)

首次启动会在用户目录创建 C:\Users\姜子牙.dsh

.dsh\
├── profiles\          # 各 profile 的组合配置与插件 node_modules
│   └── web\
├── settings.yaml      # 用户设置(主题、默认 Agent 模式、provider 配置)
├── .credentials.yaml  # API key 实际存放处(保存后界面只显示脱敏描述符)
├── .agent-presets\    # 用户自创的 Agent 模式(首次创作时生成)
└── storages\

3.4 端口占用排查

第二次启动如果报:

Error: ... listen EADDRINUSE: address already in use 127.0.0.1:3080

说明 3080 已被占用(通常是上一个 dsh 实例没关)。排查:

netstat -ano | findstr ":3080" | findstr LISTENING   # 查到 PID,如 15812
Stop-Process -Id 15812                                # 杀掉
# 或者换个端口启动(--port 属于 web app 的参数)
npx @deepseek-ai/dsh web --port 8080

其实多数情况下不用杀——直接打开 http://127.0.0.1:3080,旧实例还在跑。

4. 四大 Agent 模式(Preset)

dsh 官方随产品发货 四种 Agent 模式(agent preset),在 Web UI 创建会话时选择。每个模式本质是一个目录 + 一份 agent.cordis.yml 组合文件,定义这个 agent 的人格(persona)、工具集和提示词段。

4.1 四个模式一览

模式id能力构成适用场景
标准模式standard功能完整的编码 Agent:文件编辑、Shell、文件与网页检索、Skills、计划(Plan)、目标(Goal)、子代理、工作流默认选择,日常开发
PTC 模式code标准模式全部能力 + Code Mode:工具不以单次调用呈现,而是生成一套 TypeScript SDK,模型写一个程序由 run_code 一次执行多步组合操作——原本五次请求往返的任务一次完成
极简模式minimal持久 bash + str_replace_editor 两个工具;persona 固定为完整提示词,无运行时上下文快照,无上下文压缩基准测试、最小可复现环境、回归传统双工具 coding agent
创造模式cordis标准模式全部能力 + 自引用 Cordis 工具集(检查活体运行时、挂载/卸载模型写的插件)+ 组合创作 Skill让 agent 为你创作新的 Agent 模式

本机 settings.yaml 中的默认值:

agent-presets:
  default: standard      # 新会话默认用标准模式

4.2 PTC 模式的机制

PTC 模式与标准模式的组合文件几乎逐字相同,只多一行 tool-presentation@deepseek-ai/dsh-agent-tool-presentation):它把该 agent 的工具注册表呈现方式换成 Code Mode——模型面对的不是一堆孤立工具,而是一份生成的 TypeScript SDK;模型写一个程序,run_code 在 worker 线程里执行,程序内部可以连续调用多个工具。一个要五次模型往返的操作序列变成一次。注册表本身留在宿主层,preset 拥有的只是"呈现",所以同进程里原生会话和 PTC 会话各自看到自己的目录,互不干扰。

4.3 创造模式:agent 改写自己

创造模式在标准模式之上挂载 @deepseek-ai/dsh-tool-cordis(读取活体运行时、挂载临时插件、卸载)和 editing-cordis-compositions Skill,persona 里写明了"两个平面"的编辑纪律:

  • 宿主组合(HOST) :注册表和跨会话共享的东西——持久化、沙箱与审批栈、模型路由、子代理注册表;
  • Agent preset:单个会话贡献给注册表的东西——工具、persona、提示词段。

⚠️ 信任警告:创造模式的 cordis_mount 会对活体运行时执行模型写的 JavaScript,且它创作出的组合会成为其他会话挂载的 preset。官方原话:把跑这个模式的会话当作 shell 权限对待。创作的 preset 放在 $DSH_HOME/.agent-presets/<id>/永远不要直接改 shipped preset(升级会覆盖,改坏 cordis preset 会瘫痪创造模式本身)——要改就复制一份再改。

4.4 Preset 机制要点

  • 每进程挂载一次:roster 把每个 preset 组合挂载为 standing mount,命名它的会话通过 scope 父链"加入"——工具解析顺序 agent → preset → global(就近遮蔽),多个会话共享一个组合实例但状态按 Session/Agent 隔离。
  • 只有空会话能切模式:会话一旦产出内容就锁定(切了会让日志里已记录的工具调用在新工具集下无法解释);切换动作本身记为 session 事件 agent-preset/selected,满足"model-visible ⟺ logged"铁律。
  • 创作是 copy-only:新 preset = 完整复制一个现有 preset 的目录(组合、元数据、skill、资源)再改文件,任何调用方都不能直接提交组合文本。
  • 组合文件可以用 !!js 表达式:例如官方 preset 里 tool-bash 在 Windows 上自动禁用、换成 tool-pwsh
- id: tool-bash
  name: '@deepseek-ai/dsh-tool-bash'
  disabled: !!js process.platform === 'win32'

- id: tool-pwsh
  name: '@deepseek-ai/dsh-tool-pwsh'
  disabled: !!js process.platform !== 'win32'

5. dsh 的插件体系

5.1 插件是什么

在 Harness 中,插件就是一个导出 apply 函数的 TypeScript 模块。框架加载时调用 apply 并传入 ctx,你通过 ctx 注册能力:

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

export const name = 'hello-plugin'
export const inject = ['tools']        // 声明依赖:等 tools 服务就绪才加载

export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)        // 注册的东西在插件卸载时自动清理
}

插件有三种形态:函数形式(如上,最常用)、对象形式export default { name, inject, apply })、类形式(继承 Service,用于向其他插件提供服务)。需要手动清理的资源(如网络连接)用 ctx.effect() 登记清理函数。

5.2 往哪里挂插件

方式做法场景
--patch 覆盖层dsh web --patch ./my/cordis.yml,yaml 里 insert 插件行(绝对路径临时实验、开发调试
profile 的 cordis.patch.yml写进 $DSH_HOME/profiles/<name>/对某个 profile 长期生效
home 级 cordis.patch.yml写进 $DSH_HOME/对所有 profile 生效
dsh plugin 命令dsh plugin --profile web add <pkg>(转发给 pnpm)安装 npm 发布的第三方插件
Bundle打包成 dsh.bundle 分发,进 profile 的 bundles 列表正式分发一整套能力

5.3 社区生态与开发路径

  • 为你的插件仓库添加 GitHub topic dsh-plugin 便于被发现;官方有企微群和 GitHub Discussions。
  • 官方开发教程递进:docs/user/develop/basic(第一个插件 → 工具 DSL → 插件配置 → 发布)→ framework(服务与依赖、事件)→ practice(LLM 适配器等实战)。
  • 不会写代码也有路:用创造模式让 agent 帮你写 preset 和插件(见 4.3)——这是 dsh 区别于其他 agent 产品的标志性能力。

6. Cordis:一切皆插件的底层框架

dsh 的底座是 vendored 进仓库的 Cordis 插件框架(设计见论文 A Programming Paradigm for Spatiotemporal Composability)。理解五个概念就够读源码了:

概念说明
插件实现 Service 的对象(函数 + apply(ctx),或 Service 子类),生命周期由 Cordis 托管
上下文(context)服务仓库。服务占据稳定的 ctx.<key>(如 ctx.toolsctx.llmctx.sessions),其他插件按键找服务,不 import 具体实现
inject 依赖声明插件声明依赖的服务,等服务就绪才加载——加载顺序由依赖关系表达,而不是手写启动编排
类型化事件通过 TypeScript declaration merging 声明事件名,按四种模式派发
可逆注册(effects)提示词段、工具 schema、适配器、监听器都通过 ctx.effect() / ctx.on() 安装,插件卸载时自动回滚

四种事件派发模式:

模式是否等待顺序有返回值
emit按注册顺序观察
waterfall按注册顺序包裹(around-middleware,必须调 next() 委托,否则短路)
parallel全部并行
serial按注册顺序

关键推论:没有特权核心可以打补丁。想扩展 dsh,就把一个插件挂到别的插件旁边;它的注册是 effect,卸载即回滚。这与 Kimi Code"改配置/加 agent 文件"的扩展思路完全不同——dsh 里你替换的是组成产品的积木本身。

7. Profile 与 Bundle:启动时的分层组合

一个运行中的 dsh启动时按有序层级组合出来的插件树

  • Bundle(能力包) :可安装的分发格式,内含 Cordis 配置行 + 对应代码。dsh-base 是每个 profile 的第一层(模型适配器、工具、持久化、沙箱、审批策略、设置、凭据、遥测);dsh-web-app 叠加浏览器应用;dsh-headless 叠加无服务器的一次性运行器。
  • Profile(档案) :Harness home 下的一个命名组合($DSH_HOME/profiles/<name>),列出它堆叠哪些 bundle、装了哪些树外插件,并保存用户自己的 cordis.patch.ymlwebheadless 是官方模板,首次使用自动初始化。

层级从空的入口列表开始,按此顺序叠加:

profile 列出的各 bundle patch(按序)
→ profile 自己的 cordis.patch.yml
→ home 级 $DSH_HOME/cordis.patch.yml
→ 命令行 --patch 覆盖层

patch 按 id 定位某一行并整体替换其 config,或插入新行。查看本机实际启动的树:

dsh --profile web --dump-config

输出的任何一行都可以用你自己的 patch 替换。CLI 入口模式:

命令用途
dsh --profile <name>启动 $DSH_HOME/profiles/<name> 下的指定 profile
dsh --profile headless "任务"跑一个全新的持久化会话,打印最终答案后退出
dsh web--profile web 的别名
dsh plugin --profile <name> <pnpm args>管理 profile 的插件(转发给 pnpm)

8. 能力接缝(Capability Seam)

这是 dsh 架构里最重要的设计概念。一个接缝(seam)= 可替换能力,固定由三个角色组成:

角色职责shell 接缝的实例
Service Definition声明接口、拥有 ctx.<key> 和词汇类型(抽象类或具体注册表,不是 TS interface)dsh-shell
Service Provider实现接口,可以有多个dsh-bash-local / dsh-bash-sandbox
Consumer使用接口的一方,通常是面向模型的工具dsh-tool-bash

规则:只有三个角色齐全才是一个完整能力;一个角色单独存在不构成 seam。演进节奏不同的角色拆到不同包。

接缝的威力在于"换一个 provider,整个产品跟着换":filesystem 和 subprocess provider 共享一个执行世界,把它们指向远程沙箱,Bash、PTY、LSP 全部随之迁移,不需要 fork 任何 provider。子代理 provider 也一样——同一个接口背后,可以是"新建一个子 agent"(spawn)、"fork 当前会话",也可以是"把一轮对话委派给另一个产品"(官方组合文件里就预置了 codexclaude-code 两个默认禁用的委派 provider)。

仓库 packages/ 下 40+ 个包大多按这个模式组织:shell/fs/lsp/subagent/web/compaction/skill/ 等都是能力家族。

9. Turn 流程与 Session Log

9.1 概念层级

  • step(步) :一次模型请求 + 它引发的工具调用。
  • turn(轮) :零个或多个 step——在认领第一条输入前开启,不再欠任何工作时关闭。
  • round(回合) :更外层的策略迭代,如一个 goal round 或一次 Ralph 尝试。

9.2 Turn 内部流程(简化)

turn/start
  认领下一步输入 + 一条排队消息
  组装提示词段 + 工具 schema
  -> agent/pre-step            拒绝 | 改写后进入
     step/start
     追加 user/message
     从日志推导模型历史
     agent/request -> llm/stream -> assistant/chunk* -> assistant/message
     tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result*
     step/end
     工具欠着下一次请求,或有新输入 -> 认领 -> 下一步
  -> agent/turn-stopping
turn/end

其中 agent/pre-stepagent/requestllm/stream 和三个 tools/* 是 waterfall 事件——监听器必须调 next() 委托,直接 return 会短路整条链。

9.3 铁律:Model-visible ⟺ logged

Session log 是只追加的 SessionEvent 流,是模型所见上下文的唯一来源deriveMessages() 从日志投影出模型历史,fork、resume、transcript、遥测、持久化全部从这条流推导。

凡到达模型请求的内容,必须能从日志重建,且有运行时不变量在断言这一点。所以新增一种"模型可见输入"= 新增一个 session 事件(扩展 SessionEventMap),而不是绕过日志直接塞给模型。

这条铁律是 dsh 会话可 fork、可回放、可审计的基础,也是它和各种"上下文黑盒"agent 实现的分水岭——第 4 节里"切模式要记 session 事件"就是它的直接推论。

10. 模型配置与自定义 Provider

10.1 基本配置

Web UI 里 Settings → Models:DeepSeek 卡片只有一个 API key 字段,填入保存即生效,不用重启服务器。key 是只写的——保存后界面只收到脱敏描述符,真实密钥存在 $DSH_HOME/.credentials.yaml,settings 里只保留凭据引用。

Add provider 可选 Anthropic、OpenAI 等目录 provider(目录自带 endpoint、协议和模型列表);Add a custom provider 可接公司网关、自建服务或任何 OpenAI 兼容端点。

10.2 自定义 Provider 注意点

  • Provider ID 是永久的:请求、已存会话、模型默认、凭据引用都引用它。要改名只能新建再删旧。
  • 手输的模型默认按纯文本处理;视觉模型要在 $DSH_HOME/settings.yaml 里补一行 input: [text, image]
llm-pi-ai:
  providers:
    my-gateway:
      apiKeyEnv: GATEWAY_API_KEY
      api: openai-completions
      baseURL: https://gateway.example/v1
      models:
        - id: legacy-chat
        - id: vision-preview
          input: [text, image]
  • 常见错误:MISSING_CREDENTIAL(没存 key 或缺环境变量)、UNKNOWN_MODEL(模型未配置)、拉取模型列表 401(key 错误;不支持 GET /models 的端点改手输)。

11. 第一次跑通:完整实战记录

你输入什么:

npx @deepseek-ai/dsh web

内部发生什么:

  1. npx 命中本地缓存(%LOCALAPPDATA%\npm-cache_npx...),启动 dsh 启动器
  2. 启动器解析 web = --profile web,首次使用从模板自动初始化 $DSH_HOME/profiles/web
  3. boot 按层级组合插件树:bundle patch → profile patch → home patch
  4. webserver 插件(@deepseek-ai/dsh-host-webserver)尝试监听 127.0.0.1:3080

你看到什么(踩坑): 如果已有实例在跑,直接报 EADDRINUSE 退出——这不是 bug,去浏览器打开 http://127.0.0.1:3080 即可;或按 3.4 节换端口/杀进程。

跑通后的操作路径:

  1. 浏览器打开 http://127.0.0.1:3080
  2. Settings → Models:填入 DeepSeek API key,保存(立即生效)
  3. Choose workspace:添加并选中启动 dsh 时的项目目录(不选 workspace 无法创建会话)
  4. 新建会话时选择 Agent 模式:日常用标准模式;多步组合任务试 PTC 模式;想自己造模式用创造模式(见第 4 节)
  5. 发送第一个任务,例如:
Summarize this repository and identify its main packages.

agent 即可读写 workspace 文件、执行命令、委派子任务、维护 plan;触及审批策略的操作会在 Web UI 里先问你。

12. 常见问题(FAQ)

Q:npx @deepseek-ai/dsh web 会自动更新到最新版吗? A:不会。npx 首次下载后复用 _npx 缓存,不再检查 registry。用 npx @deepseek-ai/dsh@latest web 强制解析最新版,或全局安装后用 npm update -g @deepseek-ai/dsh 管理。

Q:启动报 EADDRINUSE: address already in use 127.0.0.1:3080 A:3080 被占用,多半是旧实例还活着——直接访问 http://127.0.0.1:3080 即可。要换端口用 dsh web --port 8080--port 是 web app 的参数,要放在 web 之后);要杀进程用 netstat -ano | findstr :3080 查 PID 再 Stop-Process

Q:四个 Agent 模式怎么选? A:默认标准模式即可,功能最全;任务需要把多步工具调用压缩成一次模型往返时用 PTC 模式;做基准对比或想要最小环境用极简模式;想让 agent 帮你定制新模式/插件用创造模式(注意它等同 shell 权限)。

Q:怎么创建自己的 Agent 模式? A:两条路:①在 Web UI 里复制一个现有 preset(创作是 copy-only 的),改 $DSH_HOME/.agent-presets/<id>/ 下的文件;②直接用创造模式会话让 agent 帮你创作。不要改 shipped preset——升级会覆盖,且改坏 cordis preset 会瘫痪创造模式。

Q:为什么有的会话不能切换模式? A:只有"空会话"(尚未产出任何内容)能切。会话一旦跑过,日志里已有按旧工具集记录的工具调用,换新组合会让历史无法解释——这是"model-visible ⟺ logged"铁律的产品化结果。切换会记为 agent-preset/selected session 事件。

Q:必须设置 DEEPSEEK_API_KEY 环境变量吗? A:用 Web UI 不需要——在 Settings → Models 页面填 key 即可(存入 .credentials.yaml)。环境变量方式主要面向源码仓库的 e2e 测试和 demo(读根目录 .env),以及自定义 provider 的 apiKeyEnv 引用。

Q:dsh 只能用 DeepSeek 的模型吗? A:不是。模型层是能力接缝:内置 DeepSeek 适配器,目录里还有 Anthropic、OpenAI 等,也可以加任意 OpenAI 兼容的自定义端点(公司网关、自建服务)。

Q:Windows 上 Shell 工具是什么? A:官方 preset 用 !!js 表达式按平台切换:Windows 上禁用 tool-bash,改用 tool-pwsh(PowerShell),无需手动配置。

Q:和直接从源码跑有什么区别? A:npx @deepseek-ai/dsh web 用的是 npm 发布的预构建产物,适合使用;源码路径(pnpm install && pnpm run build && pnpm dsh web)适合读架构、改插件、提 PR。pnpm run test / pnpm run hygiene 等是纯开发门禁,使用者无需关心。

Q:会话数据存在哪?能 fork / resume 吗? A:会话是只追加的 SessionEvent 日志,持久化在 $DSH_HOME 下(JSONL/SQLite 后端)。fork、resume、transcript 都从日志流推导,ctx.sessions.fork() 可 fork 一个活会话。注意发布前版本不做旧格式兼容——升级后旧会话可能无法加载。

Q:想给它写插件从哪入手? A:先读仓库 docs/cordis-primer.md(五个核心概念)和 docs/user/develop/basic/(第一个插件教程),再按 cookbook 深入。插件仓库打上 dsh-plugin topic 便于被发现;也可以直接用创造模式让 agent 帮你写。


参考链接