
"Everything is a Plugin"
DeepSeek Harness 完全详解:一切皆插件的 AI-Agent 框架
版本说明:本文基于 DeepSeek Harness v0.1(开发者预览版,npm 包
@deepseek-ai/dshv0.1.0-rc.6)编写,所有命令、架构与插件清单均对照官方发布包源码与官方文档核实。一句话定位:DeepSeek Harness(简称 dsh)不是"开箱即用的成品 Agent",而是用来组装 Agent 的底层运行时框架。官方核心理念只有一句话——"一切皆插件"(Everything is a Plugin)。
一、基本介绍
1.1 它是什么?
DeepSeek Harness 是 DeepSeek 于 2026 年 8 月开源的首款 Agent 框架(v0.1 开发者预览版),代码托管在 GitHub 的 deepseek-ai/deepseek-harness 仓库,采用 MIT 许可证,npm 上以 @deepseek-ai/dsh 发布,核心构建在 Cordis v4 插件框架之上。
传统 Agent 框架通常把"模型调用、工具执行、循环控制、记忆管理、执行环境"等环节焊死在一个整体里;而 Harness 的做法是把这些环节全部拆成可插拔的插件:
- 模型(LLM)是插件 —— 通过适配器(Adapter)机制,可接 DeepSeek、OpenAI 兼容接口、Anthropic Claude、Codex 等多种 provider,甚至支持运行中动态切换;
- 工具(Tool)是插件 —— 文件系统、终端、网页、子代理、任务清单等全部以
dsh-tool-*插件形式存在,按需挂载; - Agent 循环(Loop)是插件 —— 官方文档明确"它不依赖循环,因此循环可以替换",你可以替换思考-行动循环策略;
- 执行环境是插件 —— Bash / PowerShell / 沙箱 / 本地文件系统 / MCP 客户端,各自独立成包;
- 甚至连 Agent 本身、会话、提示词、人设(Persona)、技能(Skill)都是插件。
1.2 为什么说它是"Agent 界的 Android"?
这个比喻来自社区(发布后 GitHub 星标一度冲到 5 万+):就像 Android 提供内核 + 可定制 ROM,Harness 提供可拼装的 Agent 运行时,而"ROM"就是它的 Profile(配置档案) —— 通过组合不同的插件包(bundle)与配置补丁(patch),可以拼出完全不同的 Agent 形态:
Profile 形态组成典型用途webdsh-base + dsh-web-app浏览器 GUI 交互式编码 Agentheadlessdsh-base + dsh-headless一次性任务:跑完打印结果退出自定义dsh-base + 任意插件组合特定场景的专属 Agent
1.3 与主流方案的区别
方案定位与 Harness 的差异LangChain / LlamaIndex高层编排库Harness 是底层运行时,不绑架你的编排方式Codex / Claude Code成品编码 AgentHarness 不做特定领域的成品应用,而是给你"可编程工具台"MCP工具互通协议Harness 内置 MCP 客户端插件(dsh-mcp-client),两者是互补关系
二、AI-Agent 架构详解
2.1 总体架构图
graph TB
subgraph CLI["dsh 命令行(@deepseek-ai/dsh)"]
A1["dsh --profile <name>"]
A2["dsh web(= --profile web)"]
A3["dsh --profile headless \"task\""]
A4["dsh plugin(pnpm 插件管理)"]
end
subgraph BOOT["启动器(Launcher)"]
B1["解析自有 flag(--profile / --patch / --dump-config)"]
B2["加载 profile 组合包(bundle)"]
B3["叠加配置层(patch)"]
end
subgraph CORE["Cordis 内核(cordis v4)"]
C1["插件加载器 cordis-plugin-loader"]
C2["热更新 cordis-plugin-hmr"]
C3["include / timer 等基础插件"]
end
subgraph AGENT["Agent 核心服务(dsh-agent / dsh-session / dsh-llm)"]
D1["Agent 注册表 ctx.agents<br/>(创建 / 恢复 / 事件 / 发起方作用域)"]
D2["会话存储 ctx.sessions<br/>(事件溯源 + surface 压缩层)"]
D3["LLM 运行时 ctx.llm<br/>(适配器注册 / 模型发现 / 流式调用)"]
end
subgraph TOOLS["工具插件 dsh-tool-*"]
E1["fs / fs-search 文件系统"]
E2["bash / pwsh / terminal 终端"]
E3["web 网页工具"]
E4["subagent 子代理"]
E5["goal / todo / jobs 任务管理"]
E6["skill / ask-user / ralph 等"]
end
subgraph ENV["执行环境"]
F1["dsh-fs-local 本地文件"]
F2["dsh-terminal-bash / dsh-pwsh-local"]
F3["沙箱:bash-sandbox / pwsh-sandbox<br/>(Windows ACL 权限控制)"]
F4["dsh-mcp-client MCP 客户端"]
end
subgraph SURFACE["表现层组合包"]
G1["dsh-web-app(浏览器 GUI)"]
G2["dsh-headless(一次性任务)"]
end
CLI --> BOOT
BOOT --> CORE
CORE --> AGENT
AGENT --> TOOLS
TOOLS --> ENV
CORE --> SURFACE
2.2 分层模型:base → 表现层组合包
Harness 采用"基础层 + 表现层"的组合包设计,全部通过 cordis.patch.yml 补丁文件叠加:
@deepseek-ai/dsh-base(基础组合包) 每个 profile 的dsh.profile.bundles列表中的第一层。它在一个空的 profile 根之上插入全部基础插件行:
- 模型适配器与共享的
agent-default-model(默认模型)选择 - 工具集合、持久化、策略(重试等)、settings、credentials(凭据)、遥测
- 子代理(subagent)provider
- Codex 与 Claude Code 的 provider 以休眠(dormant)状态加载,需要时再激活
- 表现层组合包
dsh-web-app:叠加在 base 之上,设置 coding persona,插入 Web 宿主行(webserver、API 网关、workspace、投影缓存、存储)、浏览器插件注册表、客户端插件热重载链,以及web-runtime组合插件(printUrl、surfaceContext、trustedHosts等配置项)。dsh-headless:同样叠加在 base 之上,但不挂载任何 Host、HTTP server、Web runtime 或浏览器插件,禁用 HMR,把 Code Mode 的 worker 作为核心执行能力,并插入headless-runner插件用于一次性任务。
- 用户 Profile:在组合包之上再叠加你自己的
cordis.patch.yml,按 id 覆盖任意一行配置。
⚠️ 工程细节:patch 会替换整行的
config,不存在深度合并层。也就是说 profile 覆盖某一行时,必须把需要保留的每个字段都重写一遍。
2.3 六大核心子系统(对照源码)
以下均来自官方包的真实插件清单(@deepseek-ai/dsh 的依赖)与各包 README:
(1)Agent 运行时 —— dsh-agent
Agent 接口、注册表与进程内发起方(initiator)作用域,定义 agent/* 事件词汇。
- 注册表服务键:
ctx.agents - 核心 API:
ctx.agents.register(agent)、create(options)、resume(options)、list()、roots() - 工厂机制:
ctx.agents.setFactory(factory)注册AgentFactory—— 创建功能留在接口上,消费方(UI、ACP 桥接层)面向ctx.agents编程,不依赖具体循环包,这是"循环可替换"的架构基础 - 发起方作用域:
withInitiator(agent, op)/requireInitiator()/withoutInitiator(op),用于父子 Agent 关系的追踪 - Agent 生命周期:
enter(强制agent.id === session.id、ID 冲突检查)→announce(发出agent/created)→ dispose
(2)会话存储 —— dsh-session
事件溯源(event sourcing) 的会话日志与内存存储。这是 Harness 记忆系统的根基:
Session是 Agent 全部交互历史的唯一追加写入(append-only)真源;LLM 消息历史是"派生"出来的,而不是直接存储的- 在原始日志之上维护一个 surface 层(产生消息事件的有序投影),用于高效派生消息与压缩(compaction)
- 核心 API:
ctx.sessions.create(id, {seed, meta})、fork(source, boundary)(子会话分叉)、flush(session)(持久化检查点)、get(id)、list() - 会话头(
SessionHeader)携带版本、id、创建时间、cwd、父会话、seedLength、delegationDepth(委托深度)等元数据 - 配套压缩插件:
dsh-compaction-basic(基础压缩)、dsh-compaction-tool-result-pruner(工具结果裁剪——把冗长的工具输出修剪掉,这是省 token 的关键机制)
(3)LLM 运行时 —— dsh-llm
Provider 无关的大模型调用词汇与抽象服务,服务键 ctx.llm:
ctx.llm.registerAdapter(providers, adapter)—— 为一条或多条 provider 路由注册适配器ctx.llm.stream(options)—— 把一次模型调用流式输出为原始分片(token 级增量)ctx.llm.resolveModelInfo(provider, model)—— 精确模型身份解析(上下文长度、输出上限、reasoning 元数据)- 模型发现:
registerModelDiscovery(settingsNs, discover)+discoverModels(),让 UI 能查询端点发布了哪些模型 - 事件:
llm/stream(waterfall 模式),可被中间件拦截/包装,用于缓存、日志或路由 - 重试策略:适配器注册时携带 provider 自有的
providerRetryPolicy,随产品交付的 agent 重试走agent/request-error事件
(4)工具插件体系 —— dsh-tools + dsh-tool-*
工具不是硬编码的,而是一包一个工具的插件体系(详见第六章)。工具通过 ctx.agents 的作用域上下文注册,只对注册它的 Agent 生效,dispose 时全部撤销。
(5)执行环境 —— 终端 / 沙箱 / 文件系统
dsh-terminal+dsh-terminal-bash:终端抽象与 Bash 终端实现dsh-pwsh-local/dsh-pwsh-sandbox:PowerShell 本地执行器与沙箱执行器dsh-fs-local:本地文件系统服务(挂载ctx.fs)dsh-tmux-context:tmux 上下文(多会话复用)
(6)Agent 配置预设 —— Agent Preset
官方包自带 4 个预设目录(config/agent-presets/):code、cordis、minimal、standard。每个预设决定自己的 Agent 是否向模型贡献面向模型的工具,即"这个 Agent 长什么样、能用哪些工具"由 preset 决定。
2.4 子代理、Goal 与技能
- 子代理(Subagent):
dsh-subagent+dsh-tool-subagent(创建子代理)+dsh-tool-subagent-control(控制),支持多 Agent 并发执行与结果回收;dsh-workflow-worker-thread提供工作流的工作线程实现 - Goal 系统:
dsh-goal+dsh-goal-round-driver(目标轮次驱动,支持多轮自动续跑)+dsh-tool-goal+dsh-command-goal,用于"长跑型"任务目标管理 - 技能(Skill):
dsh-skill+dsh-skill-filesystem+dsh-tool-skill,把可复用的操作指令打包成技能,按需加载 - Persona:
dsh-persona提供人设提示词基础;dsh-agent-instructions/dsh-agent-tool-presentation负责指令与工具对模型的呈现方式
2.5 记忆与上下文管理
Harness 对上下文的处理非常有特色:
- 事件溯源 + surface 投影:原始事件永不丢失,模型看到的只是按需投影出来的消息序列;
- 增量投影:
deriveMessages()只对每个新 surface 条目做一次增量投影,避免全量重算; - 分层压缩:
dsh-compaction-basic负责常规压缩,dsh-compaction-tool-result-pruner专门裁剪工具结果——工具输出往往占据上下文大头,裁剪后 token 显著下降; - 会话分叉:
session.fork(boundary)从某个事件序号切出子会话,适合分支探索; - KV Cache 友好:官方包在提示词设计上刻意保证"提示词段落在进程生命周期内稳定",避免跨轮次缓存失效。
三、安装与快速开始
3.1 环境要求
- Node.js(建议 ≥ 18,包本身是 ESM 模块)
- pnpm(用于插件管理与 monorepo 开发)
- 一个 DeepSeek API Key(或其他兼容 provider 的凭据)
3.2 方式一:npm 全局安装(推荐,最快)
# 1. 全局安装 dsh CLI
npm install -g @deepseek-ai/dsh
# 2. 启动浏览器版(web profile 首次使用会自动从随附模板初始化)
dsh web
# 3. 启动后终端会打印形如 "dsh web: http://127.0.0.1:<port>" 的 URL
# 用浏览器打开即可开始对话
web 与 headless 两个 profile 在首次使用时会从随附模板自动初始化,其余任何 profile 都必须通过 dsh plugin 创建。
3.3 方式二:一次性运行(不安装)
npx @deepseek-ai/dsh web
3.4 方式三:从源码运行(开发模式)
# 克隆仓库
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
# 安装依赖
pnpm install
# 构建所有包与前端产物(生产运行需要已构建的包)
pnpm run build
# 使用 TypeScript 入口运行,转发所有参数
pnpm dsh <args...>
3.5 Headless(无头一次性任务)
# 运行一个全新的持久化会话,打印最终答案并退出
dsh --profile headless "帮我总结这个项目的架构"
# 退出码:turn/end 完成 → 0;失败 → 1
# 成功时 stderr 保持为空;失败时把 code 与 message 写入 stderr
适合做自动化:脚本调用 → 拿 stdout 结果 → 按退出码判断成败。
3.6 配置模型与凭据
Harness 通过 settings 与 credentials 两套机制管理配置(均由 dsh-base 提供):
- settings:profile 内的结构化配置(模型路由、默认模型
agent-default-model、预设等),按 settings namespace 组织; - credentials:API Key 等敏感凭据,独立存储;
- 模型发现:UI 的模型设置页会通过
ctx.llm.discoverModels()查询端点实际发布了哪些模型,选定后写入 settings; - Codex 与 Claude Code 的 provider 以休眠状态随 base 包加载,在 profile 或 home 的
cordis.patch.yml中按需激活。
四、Profile 与配置体系
4.1 Profile 目录结构
Profile 位于 $DSH_HOME/profiles/<name>($DSH_HOME 是 Harness 的配置根目录),包含:
profiles/<name>/
├── package.json # 记录树外(out-of-tree)插件依赖
├── dsh.profile # profile manifest(元数据清单):按顺序列出 bundles
└── cordis.patch.yml # 用户自己的补丁层
4.2 配置分层(自底向上)
配置树以空根为起点,依次叠加:
dsh.profile.bundles中各组合包的 patch(bundle 先从 dsh 安装目录解析:dsh-base、dsh-web-app、dsh-headless,再从 profile 自己的node_modules解析;pnpm 会把树外插件安装到该目录)- profile 自身的
cordis.patch.yml - home 级的
$DSH_HOME/cordis.patch.yml --patch指定的覆盖层(可重复:--patch a.yml --patch b.yml)
4.3 检查合并后的配置
# 查看默认配置树(不启动)
dsh --profile web --dump-default-config
# 查看叠加全部补丁后的最终配置树(不启动)
dsh --profile web --dump-config
4.4 创建自定义 Profile
# 通过转发给 pnpm 来管理某 profile 的插件依赖
dsh plugin --profile my-agent add @deepseek-ai/dsh-tool-web
# 之后启动
dsh --profile my-agent
⚠️ 注意:启动器(launcher)只解析自己的 flag,其后的所有内容会原样交给被启动的 profile 内的应用插件解析。所以启动器 flag 必须写在最前面,第一个无法识别的 token 标志着应用参数的开始:
dsh --profile web --port 8080 # --port 属于 web 应用
dsh --profile web --help # 打印 web 应用的帮助,不是启动器的
dsh --help # 打印启动器自己的帮助
五、常用命令速查
命令用途dsh --profile <name>启动位于 $DSH_HOME/profiles/<name> 的指定 profiledsh --profile headless "job"运行一个全新的持久化会话,打印最终答案并退出dsh web--profile web 的别名(浏览器 GUI)dsh plugin --profile <name> <pnpm args>通过转发给 pnpm 管理该 profile 的插件dsh --profile <name> --patch <file.yml>追加覆盖层(可重复)dsh --profile <name> --dump-default-config不启动,输出默认配置树dsh --profile <name> --dump-config不启动,输出合并后的最终配置树dsh --help启动器帮助(每个应用有自己的 --help)
Web 应用自己的 flag:--host、--port、可重复的 --trusted-host。当前版本有意拒绝 --host 0.0.0.0(不支持绑定所有网卡接口)。
六、工具插件全景图
以下工具插件全部随 @deepseek-ai/dsh 官方包发布(v0.1.0-rc.6 实测依赖清单):
类别插件包说明文件系统dsh-tool-fs、dsh-tool-fs-search文件读写、搜索终端dsh-tool-bash、dsh-tool-bash-persistent、dsh-tool-pwshBash / 持久化 Bash / PowerShell 执行网页dsh-tool-web网页抓取/搜索类工具子代理dsh-tool-subagent、dsh-tool-subagent-control创建与控制子代理任务管理dsh-tool-todo、dsh-tool-jobs、dsh-tool-goal待办清单、后台任务、目标交互dsh-tool-ask-user向用户提问确认技能dsh-tool-skill加载技能文本编辑dsh-tool-str-replace-editor字符串替换式编辑器(精确小改动)系统dsh-tool-cordis、dsh-tool-ralph、dsh-tool-workflow框架内省、Ralph 循环、工作流编排
配套基础设施插件:dsh-token-meter(token 计量)、dsh-schedule(定时任务)、dsh-time-context(时间上下文)、dsh-plan-mode(计划模式)、dsh-jobs-local(本地任务)、dsh-session-projection / dsh-session-reference(会话投影与引用)、dsh-command-compact / dsh-command-goal(命令)。
七、平台支持与安全沙箱
7.1 Windows / POSIX 差异
官方包对平台差异做了显式处理(来自 dsh-base 的 patch 设计):
- Bash 没有 Windows runner:
bash-sandbox/tool-bash携带disabled: !!js process.platform === 'win32';在 Windows 上由pwsh-sandbox/tool-pwsh以相反的表达式接替。同一份 patch 文件,每个宿主恰好挂载一个 shell 栈; - 反过来,POSIX 主机看到的是被禁用的 pwsh 行;
- 想在自己机器上用 Bash:必须在 profile 或 home 的
cordis.patch.yml中完整覆盖这两行(禁用 pwsh 栈、重新启用 bash 栈),因为两个执行器族注册同一个bash服务,配方不完整会在加载时直接报错。
7.2 沙箱权限面
- 权限面与 POSIX 完全对齐:
sandbox/sandbox-policy通过 Windows ACL 受限令牌 runner(dsh-sandbox-windows-acl)执行文件生效策略,权限切换器与 approval 服务原样运行; dsh-fs-local挂载ctx.fs,沙箱写操作由fs-sandbox围栏;- Windows 临时目录授权是按会话的私有子目录:
workspace-write把写入限制在工作区与会话自己的 temp 子目录(<temp>\dsh-<hash>,受限子进程的 TMP/TEMP 被改写);read-only不授予任何临时目录写入权。
八、生态、社区与二次开发
8.1 官方仓库结构
monorepo 主要目录(对应 npm 包组织):
apps/cli→@deepseek-ai/dsh(CLI 启动器)packages/core/*→dsh-agent、dsh-session、dsh-llm、dsh-tools等核心packages/boot/*→dsh-base、dsh-web-app、dsh-headless、dsh-cmdline等组合包packages/host/*→ webserver、apiproxy、frontend-static 等宿主packages/client/*→ 浏览器端 UI 与 HMRpackages/tools/*→ 各dsh-tool-*插件
8.2 社区资源
- Awesome 列表:
0xsline/awesome-deepseek-harness(中文) - 拆解教学:
onychen/learn-dsh(含简单教学版实现) - 深度手册:
Electricitysheep/dsh-handbook(安装/插件开发/性能调优/实测案例) - 桌面版封装:
LisiChen0/DeepSeek-Harness-Desktop
8.3 如何写一个自己的插件
插件本质是 Cordis 插件 + 一个 cordis.patch.yml 补丁。最小步骤:
- 继承你需要的服务接口(如
ctx.agents、ctx.llm、ctx.sessions); - 用
registerAdapter/register/on(event)等 API 挂载你的能力; - 把插件声明进 profile 的 bundles 或 patch 层;
- 用
dsh plugin --profile <name> add <你的包>安装; - 用
--dump-config验证合并结果。
九、已知限制与注意事项
- patch 是整行替换,不是深度合并:覆盖配置时必须重写需要保留的每个字段;
- 前端 dist 必须已构建:
dsh-web-app对 dist 的require.resolve在激活时明确报错并给出构建提示,没有从源码直接服务的回退路径; lanAddresses是启动期快照:启动后的网卡变化不会重新公告,打印的 LAN URL 始终与配置的信任栏一致;- headless 只提交一个任务:runner 没有用于交互式后续输入的 surface,它会等 Agent 返回 idle 前完成的所有工作,打印该区间内最后一条非空 assistant 消息;
ctx.appExit由启动器持有:在dsh启动器之外启动 headless profile 会在激活时明确报错;- Web 版当前拒绝
--host 0.0.0.0,CLI 有意不支持绑定所有网络接口; - 仍处于 v0.1 开发者预览版:API 与配置格式在正式版前可能调整。
十、参考资料
- 官方仓库:deepseek-ai/deepseek-harness
- 官方 npm 包:
@deepseek-ai/dsh(npm) - 官方中文 README:README.zh.md
- CLI 文档:apps/cli/README.zh.md
- 媒体报道:
本文架构描述基于 @deepseek-ai/dsh v0.1.0-rc.6 官方发布包源码逐项核实,引用命令与配置均可在该版本复现。
评论 (0)
还没有评论,来写第一条吧~