平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“认识 DeepSeek Harness(DSH):Agent、Harne……”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
摘要:本章从"模型只会输出 token"这一基本事实出发,厘清 Agent = Model + Harness 的本质,同时系统拆解 harness 承担的五类工程职责(工具安全执行、上下文管理、状态持久化、权限审批、多轮编排)。随后对比 2026 年主流 agent harness 格局,引出 DeepSeek Harness(
dsh)的四个差异点,深入解读其"一切皆插件"架构在源码层面的含义——不存在特权内核,模型适配器、工具注册表、会话日志乃至 agent loop 本身皆可设置替换,并由 capability seam 的三种角色(Service Definition / Provider / Consumer)承载。文章还导读支撑该设计的论文《A Programming Paradigm for Spatiotemporal Composability》,用 RAII、词法作用域与模块 import 类比解释 temporal / spatial composability,并介绍其可运行实现 Cordis 被 vendored 内嵌的工程决策。最后给出技术栈、版本生态现状、学习路线图、FAQ 与两个动手实验,帮助读者建立一张从概念到源码的准确认知地图。
本章导读:你大概已经用过不少 AI 编程工具,也听过"智能体(Agent)"这个词。但"agent harness(智能体框架)“到底是什么?为什么 DeepSeek 要开源一个,而且声称它"一切皆插件”?本章不写一行业务代码,只解决一个问题:让你建立一张准确的认知地图——模型、agent、harness 三者的边界,dsh 与同类工具的差异,以及支撑它的那篇设计论文到底在讲什么。
npx @deepseek-ai/dsh --help。deepseek-ch@t,它不会打开文件、不会执行命令、不会记住上一次的对话(除非你把历史又发一遍)。它是一个纯函数式的文本进、文本出的机器。// 示例代码:最小 agent 循环(伪代码)
while (true) {
reply = model(messages) // 1. 请求模型
tool_calls = parse(reply) // 2. 解析模型想调用的工具
if (tool_calls.length === 0) break
for (call of tool_calls) {
result = execute(call) // 3. 真正执行(读文件、跑命令……)
messages.push(result) // 4. 把结果拼回上下文
}
}
一、工具安全执行。 反例:你让 agent"清理一下项目里的临时文件",模型输出的命令是 rm -rf /tmp/build,但如果模型的参数序列化出了偏差,或者干脆幻觉出一个 rm -rf ~呢?玩具循环会直接 exec(),你的家目录就此消失。一个合格的 harness 必须在模型输出的命令和真实操作系统之间加一道闸:参数校验、工作目录限定、沙箱(sandbox,把进程关进一个受限的"笼子"里执行)、以及最坏情况的兜底。在这个场景下,dsh 里这条链路是工具注册表 → 执行流水线 → 沙箱/审批提供方,全部可替换。
二、上下文管理。 反例:任务做到第 40 轮,历史消息加工具结果早超过 128K 上下文窗口,API 直接报错;或者更糟,不报错,模型悄悄"忘了"你第 2 轮立下的规矩,开始自作主张。harness 需决定每轮请求发什么:哪些历史保留、哪些压缩成摘要、哪些注入为隐形背景。在这个场景下,dsh 的做法是"模型可见即已记录"——凡是发给模型的内容都必须能从会话日志重建(架构文档原话),这让上下文管理变得可审计、可回放。
三、状态持久化。 反例:进程崩溃或者你手一抖关了终端,刚才让 agent 跑了半小时的重构任务,没了,日志都没处找。harness 必须把每一轮对话、每次工具调用持久化成事件日志,重启后能原样恢复现场。理解这一步时,dsh 的会话是一份仅追加(append-only)的 JSONL 事件日志,fork、回放、transcript(文本记录)导出都从这同一份日志派生。
四、权限审批。 反例:agent 在无人值守时决定"为了修好这个测试,我要改一下 CI 设置同时且 curl 一个外部脚本下来执行"。谁批准的?没有人。在这个场景下,harness 需一个审批(approval)机制:敏感操作先弹给人类,人类点了允许才放行,同时且每一次决定本身也要留痕。dsh 的审批记录是持久会话事件,事后可回溯谁在何时批准了什么。
五、多轮编排。 反例:一个"调研 → 写码 → 跑测试 → 修复 → 汇报"的长任务,中途用户插了一句"等等,别用那个库",玩具循环要么忽略插话,要么把整个上下文搞乱。结合项目来看,harness 要处理输入排队(什么消息算新任务、什么算补充说明)、子任务委派(subagent,子智能体)、后台任务与定时续跑——这些在 dsh 里对应 inbox(收件箱)、turn(轮次)/step(步骤)分层、jobs 与 goals 等一整套机制。
实际处理时,这五件事没有一件是"模型能力"问题,全是工程问题。这就是 harness 存在的理由:它把"模型能干活的假设"变成"模型被约束着干活的现实"。
常用误区:很多人以为"harness 越强,模型越自由"。恰恰相反——harness 的核心价值是约束:它让模型的每次越界企图都先经过一道可设置、可审计的闸门。
结合项目来看,harness 不是新概念,但 2025 年之后它才成为一类显性的软件品类。截至本章写作(2026-08),主流玩家大致是:
(以上定位概括以各家官方文档为准,一句话带过)重点是你该怎么选、dsh 凭什么不同。dsh 的差异点有四个:
dsh --profile web --dump-config 能够打印出你这台机器上实际组装出的整棵设置树,其中每个条目都能被你自己的 patch 替换。一句话总结:别家是"一个带扩展槽的产品",dsh 是"一堆插件的预装组合"——后者在工程上更激进,代价是概念更多。
在这个场景下,这对你的实际选择意味着什么,能够再说得直白些。如果你只是想要"开箱即用的终端助手",Claude Code、Codex CLI 这类产品到今天依然更省心——少设置、少概念、官方体验打磨得细。但当你出现以下任一需求时,dsh 的差异点就会开始变现:想把执行底座换成自己的沙箱或远程环境(换 provider);想接一家没有官方兼容的内网模型网关(写一个模型适配器插件);想基于同一套能力做自己的产品形态(复用 dsh-base 组合包组装新 profile);或者就是想读懂一个现代 agent 的全部内部构造(整棵树都在仓库里,没有黑盒)。
实际处理时,DeepSeek Harness(命令名 dsh,npm 包 @deepseek-ai/dsh)是 DeepSeek AI 官方开发的开源 agent harness。 它构建于"一切皆插件"的架构之上,由 Cordis 框架驱动,设计思想来自论文《A Programming Paradigm for Spatiotemporal Composability》(arXiv:2608.25512),MIT许可。本章写作时的版本基准是 0.1.2-alpha.1(根package.json 的 version 字段)。
# 来自 README.zh.md「运行」一节
npx @deepseek-ai/dsh web
(链接已移除) 启动 Web UI,本机启动时会用默认浏览器打开页面;借助 SSH 启动时只打印宿主机 URL(本地转发由 SSH 客户端持有),--no-open 可仅运行服务器不开浏览器。深一层看,"形态"在 dsh 里不是硬编码的产品分支,而是五个随发行版交付的 profile 模板:| profile | 形态 | 面向 |
|---|---|---|
web | Web UI + HTTP 服务器(dsh web) | 日常交互采用 |
headless | 不挂服务器的一次性运行器 | 脚本与流水线,如 dsh --profile headless "跑一遍测试" |
sdk / sdk-minimal | stdio 上的 JSON-RPC 服务器 | TypeScript / Python SDK 程序化驱动 |
acp | Agent Client Protocol 服务器 | 与编辑器等外部 agent 客户端对接 |
dsh-base 是所有 profile 的共享第一层,架构文档对此有明确说明)。预览期警告——这不是套话,必须原样转述。README 中文版写着:
在这个场景下,DeepSeek Harness 处于 开发者预览 阶段,正在更快迭代。未来将出现破坏兼容性的变更。 在这个场景下,运行本项目前,请阅读安全说明 SAFETY.zh.md(仓库根目录,本章末尾参考资料有路径)。
SAFETY.zh.md 说得更直接:
理解这一步时,DeepSeek Harness 是实验性的开发者预览软件。它尚未接受安全审计,不得视为安全或可用来生产环境的软件。不要把 DeepSeek Harness 当作不可信工作负载唯一的安全控制措施。
现在拆解本章标题里的第三个词。先看两个原文引用:
README.zh.mddocs/architecture.zh.md「Cordis」
两段话里有三个关键词,值得逐个落到源码。
第一,"特权内核"的不存在。 实际处理时,传统软件的扩展是"内核 + 插槽":内核里有硬编码的主循环、硬编码的工具清单,扩展点之外的一切都改不了,想深度定制就得给内核打补丁(fork 后改源码,从此走上维护地狱)。dsh 的主张是反过来的:没有一个"dsh 核心 + 若干可选插件",只有插件。你运行 dsh 时看到的一切能力,都是启动时一棵插件树组合出来的结果;组合方式暴露为设置,所以"改造产品"不需改产品代码,改设置树就行。
第二,“从设置替换”。 理解这一步时,承接这个主张的机制叫 capability seam(能力接缝,下文简称 seam)。seam 是一种包含三种角色的可替换能力(术语表 docs/glossary.zh.md 原文):
ctx.(如 ctx.shell),注意它是一个 Cordis Service 类,而不是 TypeScript interface;packages/shell 是官方术语表点名的规范范例,目录结构如下所示:// 真实目录结构:packages/shell/
packages/shell/
├── shell/ # dsh-shell:ctx.shell 服务定义(Service Definition)
├── bash-local/ # dsh-bash-local:本机 bash 提供方(Provider)
├── bash-sandbox/ # dsh-bash-sandbox:沙箱 bash 提供方(Provider)
├── pwsh-local/ # dsh-pwsh-local:Windows PowerShell 提供方
├── pwsh-sandbox/ # dsh-pwsh-sandbox
├── shell-env/ # dsh-shell-env:shell 环境信息
├── tool-bash/ # dsh-tool-bash:bash 工具(Consumer)
└── tool-bash-persistent/ ...
dsh-base 组合包——所有主流 profile 的共享第一层——原文清单是:“模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测”。也就是说,你 npx 下来的那个"产品",本质上是这一层之上再加一层界面(dsh-web-app 加浏览器应用、dsh-headless 加一次性运行器)。看懂了这一点,你就看懂了 dsh 产品哲学的全部:界面能够换、组合能够换,底座清单每层都明码标价。bash-local 换成 bash-sandbox 提供方——改动只是设置树里的一行——整个产品的执行行为就变了:所有 bash 工具调用从此被关进沙箱执行,而 tool-bash 这个消费方一行代码都不用动,它根本不知道(也不需知道)底下是谁在执行命令。架构文档对此有一句精辟总结:“seam 正是替换一个提供方就能改变整个产品的原因。” 更进一步:“文件系统与进程提供方共享同一个执行世界,因此把它们指向远程沙箱,也就把 Bash、PTY 和 LSP 一同时搬了过去”——换提供方,等于给整个产品搬家。 深挖:想亲眼看看你这台机器上组装出了什么?运行 dsh --profile web --dump-config,它会打印组合包各层叠加上你自己的 patch 之后的完整设置树,同时注释每一行来自哪个文件。架构文档原话:“它打印出的任何条目,都能够由你自己的 patch 替换。” 这条命令是本系列的核心调试手段。
第三,“挂载到其他插件旁边”。 没有内核,插件之间如何协作?答案是共享的上下文(Context)。每个插件向当前上下文贡献服务、事件、安装副作用;上下文既是服务容器(借助 inject 声明依赖,服务就绪后插件才启动),又是事件总线从实现思路看,(emit / waterfall / parallel / serial / bail 五种分发模式),还是副作用的登记处理解这一步时,(登记的副作用在插件卸载时自动撤销)。这套机制的学名就是 Cordis——它从哪来、为什么可信,正是下一节的话题。
import:你声明"我依赖 lodash",模块加载器负责解析、去重、按序加载——你从不手动编排"先加载 A 再加载 B"。effect/coeffect的预备概念摆正,第 3 章分别给出"可逆 effect"与"响应式 coeffect"的设计,第 4 章把规则形式化为一个动态组合演算,同时证明了保持性(preservation)、时间可组合性、空间可组合性、进展(progress)、合流(confluence)等定理。vendor/cordis 目录,更名为 @deepseek-ai/cordis(上游版本在 vendor/README.md 清单中记录为 4.0.0-rc.7;本地 package.json 的 version 字段随同步演进可能更高,以你检出的源码为准)。vendor/README.md 给了两个理由,值得原文转述:一是让 harness 完全拥有框架层落到代码里,(可审计、可打补丁、版本钉死),二是避免以上游名字发布导致 npm 注册表上的抢注(squatting)风险。内嵌不是原样照抄:vendor/README.md 逐条记录了 18 处本地加固改动理解这一步时,——比如 fiber 生命周期加固(堵住重入卸载的三个缺口)、事务化的 Loader 设置变更(应用失败的候选设置自动回滚)等。这本身就是"一切皆插件"精神的延伸:连框架层也是一个能够整体替换的组件。ctx.on() / ctx.effect() 把副作用登记到当前 fiber(纤维,Cordis 的执行与生命周期单位)上;"拔掉"是 fiber 的 dispose(资源释放)过程,按登记信息把每一条副作用撤销。论文证明的就是:只要大家遵守插座协议,无论多少电器插上拔下多少次,电路都不会出问题。 深挖:论文第 5 章实现的另一半是"声明式 loader 与 HMR"(Hot Module Replacement,热模块替换)。dsh 里它对应 cordis.yml / cordis.patch.yml 设置树、dsh plugin 安装、以及自定义 profile 的 patch 热重载——改一行 patch 文件,运行中的插件树即时重组。换句话说,dsh 的"可设置"不是产品特性,而是论文理论的直接产物。Cordis 概念的入门读物就在仓库里:docs/cordis-primer.zh.md。
packages/ 下有 56 个一级分组、247 个包目录(packages/*/*/package.json 实数),另有 apps/(CLI 与 Web 应用)、vendor/(内嵌框架层)、native/(原生组件)、python/(Python SDK 与运行时 wheel)、website/(文档站)。package.json 的 engines 字段原文——"node": "^22.19.0 || >=24.0.0",包管理器钉死 [email protected]。apps/web + client 模块)。python/sdk,文档在 docs/user/guide/python-sdk.zh.md),借助打包 dsh --profile sdk 的运行时 wheel 驱动同一棵插件树。docs/testing.zh.md 描述了六层测试——单元测试、覆盖率门禁、真实 API e2e、预期输出测试、快照测试、Web 浏览器快照。其中覆盖率门禁的原文值得一看:“对 packages/*/*/src 按文件 100% 覆盖”——全仓库 src 达到按文件 100% 行覆盖,是 CI 的硬性门禁,未覆盖的行会被当作应删除的死代码。仓库还带几十个 verify-* / gen-* 脚本,把"文档与代码一致"也做成了门禁。从实现思路看,这套工程设置想说明一件事:dsh 虽然是 0.1.x 的预览版,但它不是玩具——它的工程纪律(覆盖率、文档门禁、事故复盘 docs/postmortem/)达到甚至超过很多 1.0 产品。
常用误区:版本号小 ≠ 质量差,但 ≠ 稳定。工程门禁防的是"代码写错",防不了"预览期 API 设计变更"。破坏性变更(如 rc.8 的存储格式)在门禁全绿的情况下照发不误——这是有意为之的更快迭代,不是事故。
dsh 于 2026-08-13 落到代码里,发布开发者预览,随后以罕见的节奏迭代(以下节点信息来自各版本 release notes):
| 时间 | 版本 | 要点 |
|---|---|---|
| 2026-08-13 | 开发者预览 | 首次公开发布 |
| 08-17 | v0.1.0-rc.7 | 实际处理时,插件设置卡片;Claude Code / Codex 子代理接入 Job Panel |
| 08-19 | v0.1.0-rc.8 | 实际处理时,子代理改为以 Profile Bundle 安装(dsh plugin add @deepseek-ai/dsh-subagent-codex 等,命令见 apps/cli/reference/README.zh.md);SQLite 存储格式不兼容变更 |
| 08-21 | v0.1.1-rc.1 / rc.2 | 结合项目来看,视觉模型 DeepSeek-V4-Flash-Vision-Exp;修复 Bubblewrap /proc 逃逸;Files API 上传图像 |
| 08-27 | v0.1.2-alpha.1(本系列基准) | 在这个场景下,会话流折叠;@Remote 网关统一;Web UI 一次性 token 认证;Code Mode 更名 PTC mode;SSRF 防护 |
SessionFormatUnsupportedError)——这是"预览期破坏性变更"的活例子。pnpm run demo:ptc 即其演示脚本)。dsh-plugin 下已有 700+ 仓库;社区维护的 awesome 清单(libukai/awesome-deepseek-harness)聚合插件与教程;官方渠道包括 GitHub Discussions、Discord、企业微信群(README 里有入群二维码)与微信公众号。判断一个开源项目的"可持续性",提交节奏与第三方插件数量比 star 数更有说服力——这两项 dsh 目前都很健康。本系列《DeepSeek Harness(dsh)从零到全栈》共 32 章,分四个阶段:
采用方法有三条约定:第一,源码对照。每章给出的仓库路径都真实存在。第二,版本基准 0.1.2-alpha.1理解这一步时,。dsh 迭代很快,凡涉及行为细节,以你检出的源码为准;教程会在易变处显式标注。第三,术语回查。遇到陌生名词先翻 03-核心概念地图.md,那里按七层组织了全部术语。
Q1:dsh 是一个大模型吗?和 DeepSeek API 什么关系?
Q2:dsh 能接 Claude、OpenAI、本地模型吗?
ctx.llm seam 上的插件,任何 OpenAI 兼容端点(含 Ollama、vLLM)都可接入,设置层面的兼容性开关(compat 字段)也都有——完整步骤与坑位在 05-模型配置深入.md。Q3:dsh 和 LangChain 这类框架是什么区别?
Q4:要付费吗?
Q5:能用来生产吗?
Q6:Windows 兼容吗?
package.json 里的 check:ci:windows-* 系列),packages/shell 同时内置 bash 与 PowerShell(pwsh)双套本地/沙箱提供方,本系列教程的主环境就是 Windows。Q7:为什么不直接用 npm 上的 Cordis,要自己 vendor 一份?
Q8:dsh 和 MCP(Model Context Protocol)什么关系?
packages/mcp,采用场景见 docs/user/guide/mcp-memory.zh.md)。但需留意方向:MCP 只解决外部工具接入这一件事;dsh 的 seam 体系覆盖面大得多,模型、文件系统、进程、沙箱、审批、持久化都是可替换的 seam。能够粗略地说:落到代码里,MCP 是 dsh 工具体系的一条"对外接口",而不是它的扩展机制本身。# 来自 README.zh.md「从源码运行」一节(本实验只需 clone,无需 build)
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
ls,对照确认顶层布局(节选):// 真实输出(节选):仓库根目录
apps/ docs/ native/ packages/ patches/ python/ scripts/
snapshots/ vendor/ website/ README.zh.md SAFETY.zh.md AGENTS.md LICENSE package.json
随后打开 docs/architecture.zh.md,通读第 1 节「Cordis」。
packages/shell/ 下哪三个包分别扮演 seam 的三种角色。npx @deepseek-ai/dsh --help
apps/cli/reference/README.zh.md,具体文案以你拉到的版本为准):dsh --help 没有可供交付参数的 profile,所以打印启动器自身的帮助信息同时以 0 退出;npx @deepseek-ai/dsh -V 打印启动器版本。再试 npx @deepseek-ai/dsh web --help——第一个参数 web 会选中 web 子命令,这次打印的是web 应用的帮助(其参数表:--host、--port、可重复的 --trusted-host、--no-open),同样不启动服务器。| 症状 | 原因 | 解法 |
|---|---|---|
| 启动 dsh 后无法对话,以为是软件坏了 | dsh 是 harness 不是模型,未设置任何模型提供方 | 属预期行为;按第 02 章设置 API key |
| Node 18/20 上安装或启动出现莫名报错(往往不直说版本问题) | engines 要求 ^22.19.0 || >=24.0.0 | 升级 Node 或用 nvm 切换;细节见第 02、06 章 |
| 从 npm 搜索 “cordis” 同时安装,得到的是别人的框架 | dsh 内嵌的是改名后的 @deepseek-ai/cordis,上游 cordis 是独立项目 | 只借助 @deepseek-ai/* 作用域采用 dsh 生态 |
| 升级版本后旧会话打不开 | 预览期存储格式不兼容变更(如 rc.8 的 SQLite 格式) | 升级前备份 $DSH_HOME;处置见第 06 章 |
| 在重要机器上放开权限长跑任务 | 忽视 SAFETY.zh.md 警告:沙箱/审批降低风险但不保证隔离 | 最小权限;一次性虚拟机/容器;备份可访问文件 |
token; a g e n t = m o d e l + h a r n e s s, h a r n e s s agent = model + harness,harness agent=model+harness,harness把"能干活"变成"被约束地干活"。dsh / @deepseek-ai/dsh),MIT,五种 profile(web / headless / sdk / sdk-minimal / acp)对应四种采用形态。ctx.)、Service Provider(可替换实现)、Consumer(通常是面向模型的工具);换提供方即换产品行为。@deepseek-ai/cordis。^22.19.0 || >=24、React Web UI、Python SDK、六层测试与按文件 100% 行覆盖门禁。02-环境搭建与对话.md 将带你用 npx @deepseek-ai/dsh web 一步起服务,配好第一个模型 key,越过新手第一大卡点,“选择工作区”,完成第一次带权限审批的对话,同时顺便弄清 Web UI 每个面板是干什么的。README.zh.md(运行方式、社区渠道、预览期警告)SAFETY.zh.md(安全说明全文,本章多处引用)docs/architecture.zh.md("一切皆插件"与微内核声明、profile/bundle、能力 seam)docs/glossary.zh.md(seam 三角色规范定义)docs/cordis-primer.zh.md(Cordis 五个核心概念)docs/testing.zh.md(六层测试与 100% 行覆盖门禁)vendor/README.md(vendored 清单、@deepseek-ai/cordis 更名缘由、18 处本地改动日志)apps/cli/reference/README.zh.md(CLI 命令与 --help 行为参考)package.json(版本 0.1.2-alpha.1、engines、scripts)packages/shell/(seam 规范范例:shell/、bash-local/、bash-sandbox/、tool-bash/)vendor/cordis/(内嵌 Cordis 源码)从实现思路看,总的来说,DSH适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。