本章不涉及源码细节,回答三个更根本的问题:dsh 是什么?它和你已经知道的那些 agent 工具有什么本质不同?为什么值得花时间读它的架构?读完这章,你会知道后面 12 章要拆的到底是个什么东西。
先看一组对比。同样是「agent harness(智能体运行外壳)」这个品类:
| 项目 | 核心包数量 | 设计主张 |
|---|---|---|
| pi-agent | 4 个 | 核心极简,刻意不做 MCP / 子 Agent / 权限弹窗 |
| DeepSeek Harness | 185 个 | 每一寸能力都是可替换插件 |
185 比 4。如果你刚读完 Pi 教程第 1 章那套"做减法是一种竞争力"的论证,这个数字看起来像是走了完全相反的弯路。
但事情没那么简单。这 185 个包里,真正跑 agent 循环的只有 1 个,其余全是抽象接口、可换实现和插件。dsh 官方 README 里有一句话点破了这个设计:
这是 harness 中唯一包含具体循环逻辑的包。其他所有内容要么是抽象服务,要么是针对扩展点的插件:新行为应放入插件,而不是这里。 —— dsh-agent-loop/README.zh.md
换句话说,Pi 数的是"我做了多少功能",dsh 数的是"我拆出了多少个可替换的位置"。两个数字不在同一个坐标系里。
这就是本教程要拆的东西:当你把 agent 运行时的每一个决策点都做成插件,会得到什么,又会付出什么。
DeepSeek Harness(简称 dsh)是 DeepSeek 开源的 agent 运行外壳,全部用 TypeScript 编写,架构上把 agent 运行时的每一项能力都拆成"抽象服务接缝 + 可替换实现",并用一个叫 cordis 的依赖注入框架把它们组装起来。
拆开看:
| 指标 | 数值 | 含义 |
|---|---|---|
| 官方包总数 | 195 个 | 185 个 dsh-* 包 + 7 个 cordis 框架包 + 3 个工具库 |
| 含具体循环逻辑的包 | 1 个 | 只有 dsh-agent-loop,1295 行 |
| 抽象能力 seam | 20+ 个 | fs / shell / subprocess / sandbox / jobs / web / spill / storage / … |
| 配置 patch 层 | 4 层 | bundle patch → profile patch → home patch → --patch 覆盖 |
| 本机会话实际装载 | 78+78+8+33 行 | base 78 → web-app 78(含 24 行禁用)→ toolbelt 8 → preset 33 |
| 模型可见工具 | 27 个 | 由 agent preset 决定,可增可减 |
| 会话事件类型 | 21 种 | 单次会话实测,非全集 |
| 装配后系统提示词 | 9927 字符 | 由多个插件各贡献一段拼成 |
| 官方文档 | 385 篇 / 2.54 MB | 每包一份 README,186 篇有中文版 |
| 版本 | 0.1.0-rc.6 | developer preview,官方明示 rc 间有破坏性变更 |
关于"185 个包"这个数字的诚实说明 这个数字容易造成误导,必须讲清楚三件事:
- 它统计的是本机 profile 实际安装的 @deepseek-ai/* 包,不等于官方仓库的包总数(可能更多,也可能含未安装的)
- 其中约 34 个是 Web 前端 UI 插件(dsh-client-ui-*),跟 agent 内核无关
- 很多包极小 —— dsh-brand 只导出一个类型、dsh-timeout 只有几个纯函数。包数量衡量的是拆分粒度,不是代码规模
后面每次用到"185",都是在讨论拆分粒度这件事,不是在夸功能多。

配图说明:dsh 的五层架构。自上而下:前端 UI 插件(约 34 个,一人一块)、Host 宿主层(进程级)、Agent 平面(唯一循环实现 + 模型可见工具,由 preset 决定)、能力 Seam 层(20+ 组抽象+实现)、cordis 内核。关键在每一层内部的东西都是可插拔的——把 dsh-tool-pwsh 从配置里删掉一行,模型就没有 shell 了,不需要改任何代码。
这张图的关键不在层数,而在每一层内部的东西都是可插拔的。第 3 章会展示:把 dsh-tool-pwsh 从配置里删掉一行,模型就没有 shell 了;换成 dsh-bash-local,它就跑在 bash 上。不需要改一行代码。
和 Pi 一样,dsh 也可以从三个视角来看,但内容完全不同。
dsh web 起一个本地 Web GUI,dsh --profile headless "跑测试" 做一次性任务。本机实测跑的就是 Web 形态,监听 127.0.0.1 的随机端口。
作为产品它的特点:
但产品成熟度不是它现在的卖点 —— 版本号还是 0.1.0-rc.6,官方 README 直说 rc 之间会破坏兼容。如果你只想找个顺手的编码 agent,Claude Code 或 Pi 都更稳。
这是本教程认为 dsh 最大的价值。
任何人做 agent 运行时都会面对同一批问题:文件怎么读写、命令怎么跑、结果太长怎么办、上下文满了怎么办、多个 agent 怎么协作、危险操作怎么拦。dsh 的做法是把每个问题都定义成一个抽象接缝,然后给出至少一个实现。
于是它变成了一份清单:如果你要做 agent 运行时,这 20 多个位置你迟早要做决定。清单本身比它的任何一个具体实现都有价值 —— 哪怕你一行 dsh 代码都不用。
第 4 章会把这份清单完整摊开。
dsh 的扩展方式不是"写扩展文件",而是"往插件树里加一行"。本机实测的用户配置里就有 8 行第三方插件(一个叫 dsh-toolbelt 的社区包),提供了跨 agent 记忆、Windows 编码守护、图像生成等能力。
更极端的是,它装了一个叫 dsh-tool-cordis 的包 —— 让模型自己检查运行时、挂载自己写的插件。这个包本机没启用,但它的存在说明了设计意图:插件系统是给模型也准备的。
理解一个 harness 最快的方式,是看它在什么地方和别人做了不同的选择。
| 维度 | Pi | dsh |
|---|---|---|
| 核心主张 | 不需要的就不构建 | 每个决策点都留一个可替换位置 |
| 内置工具 | 4 核心 + 3 辅助,固定 | 由 preset 决定,本机实测 27 个 |
| 系统提示词 | 静态模板约 90 词 | 多插件各贡献一段,实测装配后 9927 字符 |
| 子 Agent | 刻意不做,建议用 tmux | 四种委派机制(spawn / fork / workflow / ralph) |
| 权限弹窗 | 刻意不做,认为是"安全表演" | approval seam + 沙箱强制 + 权限预设三层 |
| 计划模式 | 刻意不做,建议写 plan.md | dsh-plan-mode,软引导 + 用户复核退出 |
| 扩展方式 | TypeScript 文件 + 热重载 | cordis 插件 + 四层配置 patch |
| 读完全部核心代码 | 可能(核心循环几百行) | 不可能(195 包),但可以只读你关心的那个 seam |
有意思的是:Pi 明确列为"不做"的三件事(子 Agent、权限弹窗、计划模式),dsh 全做了,而且都做成了可以整体拔掉的插件。这不是"dsh 比 Pi 功能多",而是两种应对同一矛盾的方式 —— Pi 说"我不做,你自己加",dsh 说"我做了,你不要就删配置"。
代价也不同:Pi 的代价是缺功能时要自己写;dsh 的代价是理解成本 —— 你得先懂 cordis、懂 patch 分层,才能改动任何东西。
Claude Code 是闭源产品,系统提示词不公开、工具集固定、扩展点由官方定义(hooks / skills / MCP)。
dsh 是开源运行时,每一段系统提示词都能追到是哪个插件贡献的(第 9 章会逐段拆解本机实测的 9927 字符),每个工具的完整 schema 都在会话日志里躺着。
这不是优劣 —— 产品化程度和可观测性通常是反比。但如果你的目标是学 agent 运行时怎么做,白箱是唯一选项。
LangChain / LangGraph 是库:你在自己的应用里 import 它,控制流在你手上。
dsh 是运行时:它启动进程、管生命周期、拥有配置树,你的代码作为插件被它加载。
这个区别决定了很多设计。比如 dsh 的每个插件都必须能被 dispose() 干净卸载(第 2 章会讲 cordis 的 fiber 机制),因为运行时要支持热重载和会话级作用域;而库不需要操心这个。
本教程写作时(2026 年 8 月),dsh 的状态是:
所以:
不要把本教程当作生产选型依据 本教程的价值在于拆解架构思路。如果你要在生产环境选一个 agent 运行时,dsh 现在的版本状态不适合。等它到 1.0 再说。
但架构思路不会因为版本号而失效 —— 第 13 章总结的十条设计判断,你可以直接用在自己的项目上。
另一个必须说清楚的:本教程有一处天然盲区。所有素材来自本机安装的包(打包后的 lib/*.js + README),不是官方仓库的原始 TypeScript 源码。这意味着:
凡是受这个盲区影响的结论,正文里会明确标注。
| 章节 | 一句话 |
|---|---|
| 第 2 章 cordis 底座 | 六个概念(Context / Service / Plugin / Fiber / inject / dispose)撑起整个 harness |
| 第 3 章 Profile 分层 | 一个会话的插件图是四层配置叠出来的,host 平面和 agent 平面是两套账 |
| 第 4 章 Seam 架构 | 20 多个能力接缝的完整清单,以及"换后端 = 改配置"的实现代价 |
| 第 5 章 Agent Loop | session / turn / step 三级生命周期,inbox 的三种投递语义 |
| 第 6 章 模型调用 | provider 中立的 LLM 抽象,以及每篇文档都有的「KV Cache 影响」视角 |
| 第 7 章 工具系统 | 五段执行流水线,原生 Function Calling 与 Code Mode 两种呈现 |
| 第 8 章 会话 | 事件日志是真源,消息历史是派生物 |
| 第 9 章 上下文工程 | 9927 字符系统提示词的逐段来源,以及压缩的三种手段 |
| 第 10 章 沙箱与权限 | 四种操作系统后端,fail-closed 的四层防线 |
| 第 11 章 委派与编排 | spawn / fork / workflow / ralph 各解决什么问题 |
| 第 12 章 技能与人机界面 | 技能发现、斜杠命令、提问、UI 插件的接入方式 |
| 第 13 章 设计精华 | 十条可迁移的判断,以及全插件化的真实代价 |
本章的关键数字,你可以这样验证(PowerShell):
第 3 章会给出读取会话事件日志的完整方法 —— 系统提示词、工具 schema、事件流都在那个文件里。
DeepSeek Harness 是一次把"可替换性"推到极致的架构实验:
它和 Pi 构成了同一道题的两个极端答案。Pi 问"最少需要什么",dsh 问"最多能拆成什么"。两个问题都值得问 —— 而只有把两个答案都看过,你才知道自己的项目该站在哪个位置。
下一章我们从地基开始:cordis 到底是什么,为什么一个 agent 运行时会选一个聊天机器人框架的 IoC 容器当底座。