DeepSeek Harness 上手笔记:dsh、workspace、patch 和 Cordis
DeepSeek Harness 发布后,我花了一轮把它跑起来。版本组合是 Node v22.19.0 和 @deepseek-ai/dsh@0.1.0-rc.6。我跑了四段:启动 dsh web,用 headless 做最小 smoke;让 Web UI 修一个带测试的小仓库;处理一次 workspace API 403;再写一个最小 Cordis 插件,用 --patch 插进 headless profile。
这篇记录按实践顺序写。UI 能打开只能算入口。能读写 workspace、跑测试、留下 session/event、加载 patch 插件,才碰到了 Harness 的运行时。

我实际跑过的路径
我没有改系统 Node。实践目录里单独放运行时,先确认版本,再装包:
node -v
npm install @deepseek-ai/dsh@0.1.0-rc.6
Node v24.x 这条路先失败了,原因在 node-pty rebuild。切到 Node v22.19.0 后,安装和启动都顺了。
接着启动 Web UI:
dsh web --host 127.0.0.1 --port 3080
页面回读 HTTP 200 后,再跑一次 headless:
dsh --profile headless "Reply with exactly OK."
这一步很朴素。它检查 profile、provider、凭据加载和模型请求链路。网页壳能加载,headless 任务也能返回,底座才算站住。

dsh web 启动了一棵 Cordis plugin tree
官方 README 的入口命令很短:
npx @deepseek-ai/dsh web
这个命令会选择 Web 相关的 profile 和 bundle,把模型 provider、工具、session、workspace、settings、client UI 装进同一棵 Cordis plugin tree。headless 入口也走 dsh,加载的是另一组能力。两个入口共用运行时概念,差别在 profile 选了什么、bundle 带了什么、patch 改了哪里。
profile 目录通常有两个文件:package.json 和 cordis.patch.yml。package.json 记录依赖和 dsh.profile.bundles,cordis.patch.yml 描述这个 profile 自己的装配改动。运行时会按顺序叠 bundle patch、profile patch、$DSH_HOME/cordis.patch.yml、命令行 --patch。后面的 patch 可以插入插件,也可以改前面已有的节点。
读 Harness 时,先把这几个词放到脑子里:
dsh:启动器。- profile:一次运行的装配方案。
- bundle:可复用能力包。
- patch:改装运行时树的配置层。
- Cordis plugin tree:最终激活的能力图。
Web UI 任务:修一个带测试的小仓库
我给 Harness 准备了一个小 Node.js 仓库。文件只有 package.json、src/quote.js、test/quote.test.js。里面有一个故意写错的 bug:discountPercent 传入 10,语义是 10%,代码却把它当成原始乘数。
给 Web UI 的任务很短:读项目文件,找出测试失败原因,修 estimateQuote 的百分比计算,运行 npm test,再写 PRACTICE_RESULT.md 记录改动和测试结果。
下面是实践回读的 Web UI。截图只保留页面主体:左侧有 webui-workspace,中间是任务输入和 Workspace Write 权限,历史会话里留下了那次修复百分比计算的任务。地址栏、机器名、内网地址、绝对路径、账号和凭据都没有出现在图里。

这轮工具链能从日志里拼出来:注入上下文,读 package.json,读 src/quote.js,读 test/quote.test.js,改 src/quote.js,跑 npm test,写 PRACTICE_RESULT.md,最后回读结果。服务端确认两个测试通过,结果文件也存在。
我现在更信这类证据。模型自然语言报告只能当线索。文件 diff、测试退出码、结果文件、session 里的工具调用链合在一起,才构成一次可验收的 agent 任务。
那次 403 排障
Web UI 首次打开后,添加 workspace 失败。浏览器请求 /api/host.listDirectory,后端返回 HTTP 403。
排障点在 Host 和 Origin。浏览器带着公开入口的 Origin,后端看到的 Host 却被 public edge 改成了另一侧 authority。Harness 的 trust fence 拒绝了这次目录枚举。
修复方式很小:在 public edge 上给这个入口单独配 vhost,保留浏览器请求的 Host。随后带 Origin 的 /api/host.listDirectory 返回 HTTP 200,Web UI 的目录选择器恢复。
这段经历改变了我的验收方式。部署 Harness 时要检查页面、API、Host/Origin、workspace 边界和日志。它背后连着文件系统、shell、模型工具调用和权限策略,网页可见只覆盖了最外层。
--patch 插件验证
DeepSeek Harness 文档强调 Everything is a Plugin。我写了一个最小 Cordis 插件,用命令行 --patch 插入 headless profile。
插件只做两件小事。apply(ctx) 被调用时写出宿主侧 marker;同时通过 ctx.systemPrompt.section() 注入一段提示,让模型路径返回:
DSH_PRACTICE_PLUGIN_ACTIVE
运行日志里还留下:
PLUGIN_EXTENSION_VERIFIED=1
这里踩了两个细节。相对路径加载树外插件失败,因为 loader 按 profile 侧规则解析模块路径。改成 file://<plugin-path> 后插件进入树里。headless 单跑时还缺 provider 环境,后面复用 Web 启动时的安全加载方式,只检查 present,不打印任何密钥值。
这轮验证让我确认:--patch 贡献的是运行时配置。模块路径、provider 环境、profile 选择、Cordis 依赖等待,都在同一套装配规则里。
turn flow 才是调试入口
官方架构文档里的 turn flow 很有用。一次 turn 从 turn/start 开始,运行时 claim 输入,拼 prompt section 和 tool schema,进入 agent/pre-step。step 开始后,用户消息写进 log,运行时从 session log 推导模型历史,发起 agent/request,接收 llm/stream,生成 assistant chunk 和 assistant message。
模型调用工具时,会经过 tools/pre-execute、tools/execute、tools/post-execute。工具结果再回到 session。step 结束后,turn stopping 决定是否继续。
这条链路把 agent 行动拆成很多可查点。session/event 尤其该盯。文档里的原则是:model-visible means logged。进入模型请求的内容,应该能从 log 重建。出问题时,我会先看 prompt 里有没有那段上下文、tool schema 是哪个版本、审批策略有没有拦命令、provider streaming 中间有没有断、UI 是否漏掉 session 里的事实。
Cordis 的作用也在这里显出来。插件可以参与 prompt assembly,可以影响 claimed messages,可以接入模型请求,可以挂工具执行前后的阶段。Harness 暴露的是 runtime seam:prompt、LLM、tool、session、workspace、sandbox、provider。接入这些位置会带来能力,也会带来权限和追踪负担。
Cordis 给了检查插件系统的词
DeepSeek Harness README 指向 Cordis 和论文《A Programming Paradigm for Spatiotemporal Composability》。读 Harness 时,我主要拿 Cordis 检查两件事。
Temporal composability 关心时间。插件注册 tool、监听事件、添加 prompt section、打开连接或挂 UI node,卸载时这些影响要能撤回。放到 agent runtime 里,就是工具、prompt、session hook、provider adapter、审批策略在 profile 切换或插件卸载后要干净退出。
Spatial composability 关心依赖空间。一个插件可能依赖模型 provider,另一个依赖 workspace provider,还有一个依赖 shell backend 或 sandbox policy。运行时要知道谁依赖谁,谁可以激活,谁要等待,依赖变化时谁需要停用或重接线。
Cordis 论文里的 revertible effects 和 reactive coeffects,解释了 Harness 为什么把 profile、bundle、patch、plugin tree 放到前台。effect 要能跟踪和撤销,coeffect 要能声明上下文依赖。对应到 Harness,就是工具注册在哪里、provider 谁提供、workspace 权限从哪里来、session hook 怎么撤、profile 切换是否干净。
Cordis 论文不能替代 Harness 实测,也不能证明 Harness 已经稳定。它提供的是一套检查语言。用它去看 Harness,我会问:effect 能否撤销,coeffect 能否声明,profile 切换有没有残留,plugin reload 后 session/event 是否还能回放,sandbox 和 workspace provider 边界是否清楚。
我现在会怎么用它
DeepSeek Harness 现在适合研究 agent runtime,也适合在受控环境里做插件、profile、workspace 实验。官方已经标着 developer preview,并提醒会有 breaking changes。
我会按这条路径上手:先读 docs/architecture.md,看 turn flow、session log、prompt assembly、tool pipeline、provider seam 和 sandbox;再跑 headless smoke;准备一个小仓库,让 Web UI 做可回读修改和测试;最后写一个 marker 插件,用 --patch 证明它进入宿主和模型路径。
现在的判断很克制:DeepSeek Harness 还早,但它把 agent 工程里那些麻烦问题摊到了运行时层面。一次错误工具调用怎么追踪,插件怎么升级,workspace 权限怎么收口,团队 profile 怎么复用,session 怎样回放,模型上下文怎样解释,这些问题都能沿着 Harness 的 runtime seam 去查。
参考链接
- DeepSeek Harness 官方仓库:https://github.com/deepseek-ai/deepseek-harness
- DeepSeek Harness Architecture:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.md
- DeepSeek Harness User Guide:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/guide/index.md
- DeepSeek Harness First Plugin:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/index.md
- DeepSeek Harness Capability Seams:https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/capability-seams.md
- Cordis 论文仓库:https://github.com/cordiverse/paper