版本: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)
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 Code | DeepSeek 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(升级会覆盖,改坏cordispreset 会瘫痪创造模式本身)——要改就复制一份再改。
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.tools、ctx.llm、ctx.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.yml。web和headless是官方模板,首次使用自动初始化。
层级从空的入口列表开始,按此顺序叠加:
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 当前会话",也可以是"把一轮对话委派给另一个产品"(官方组合文件里就预置了 codex 和 claude-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-step、agent/request、llm/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
内部发生什么:
- npx 命中本地缓存(
%LOCALAPPDATA%\npm-cache_npx...),启动dsh启动器 - 启动器解析
web=--profile web,首次使用从模板自动初始化$DSH_HOME/profiles/web - boot 按层级组合插件树:bundle patch → profile patch → home patch
- webserver 插件(
@deepseek-ai/dsh-host-webserver)尝试监听127.0.0.1:3080
你看到什么(踩坑): 如果已有实例在跑,直接报 EADDRINUSE 退出——这不是 bug,去浏览器打开 http://127.0.0.1:3080 即可;或按 3.4 节换端口/杀进程。
跑通后的操作路径:
- 浏览器打开
http://127.0.0.1:3080 - Settings → Models:填入 DeepSeek API key,保存(立即生效)
- Choose workspace:添加并选中启动
dsh时的项目目录(不选 workspace 无法创建会话) - 新建会话时选择 Agent 模式:日常用标准模式;多步组合任务试 PTC 模式;想自己造模式用创造模式(见第 4 节)
- 发送第一个任务,例如:
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 帮你写。