写在前面
昨天晚上,DeepSeek 发布了自家的 Harness 简称 dsh,黑色鲸鱼Logo,我也Clone下来部署,并直接用 dsv4-pro 来解析 dsh。

本文将结合 DeepSeek Harness 解析 DeepSeek Harness 的结果来给大家展开说一下整个 dsh 的架构。
整体架构
之前 Claude Code 源码泄漏的时候,我们解析过 CC 的架构。CC是一个非常稳健的架构:Agent Loop 是固定的,Tool 是列表里挂上去的,扩展靠 Hook 和 MCP 从边上插进来。

这种工程设计很稳,也能保证广度和深度的扩展,但如果真想改 主干,那要fork大改。
而整个 dsh 架构,我给你最简洁、最直接、最不绕弯儿的一句话总结:
DeepSeek Harness is a plugin-based agent harness on vendored Cordis: everything is a plugin
这里的 everything,除了 Tool 是插件,provider 是插件外,连 agent loop 本身都是一个插件 。 说白了就是这个 harness 没有内核。你在别的框架里要动内核才能干的事,在这里只是在 YAML 里改一行。
DSH的一次执行
下面这张图从左到右展示一次运行的组成:

- 启动组合层:dsh CLI 选择 web profile,再把 dsh-base、dsh-web-app 和用户 patch 叠成最终配置。
- Cordis Runtime :
维护共享 context。插件通过 ctx.sessions、ctx.tools、ctx.llm 等服务协作,Typed Event 负责把策略插入运行过程。 - Capability Seams :
可替换能力接缝。LLM、Shell、文件系统、沙箱、审批、Skill、SubAgent 并不直接写死进 Loop, 通过 Definition、Provider、Consumer 三个角色接上 Runtime ,让某种底层能力可以整体替换,而不用修改上层 Agent 或调用者。 - Surface / Output:同一套后端能力可以被 Web、ACP/JSON-RPC 等入口调用;Session JSONL 保存可重放事实。
看到这里,你可能对一些新概念很陌生,不要担心,下面我会一个个跟你讲明白的。
dsh web 启动时做了什么?
入口先准备一个空的 Cordis 根插件树,再把多个 Patch Layer 按顺序叠上去。 Patch 是对这棵插件配置树进行"添加、替换或禁用"的配置操作,Patch Layer 则是一组 Patch。启动关系如下:

⚠️ 我们这里先注意三个基本概念:
- Plugin:一个具体能力
- Bundle:一套能力组合包
- Profile:决定本次启动使用哪些组合包
当前默认 web profile 的两个主要 bundle 是:
dsh-base:包含模型、Agent Loop、Session、Tools、Shell、审批、沙箱等基础配置,共 78 行配置;dsh-web-app:包含 Web Server、API、浏览器模块和 UI 插件等配置,共 51 行配置。
两者合计 129 行。这就是 129 个可被 patch 定位的配置行。

同一个 id 被后层命中时,后层取得更高优先级,但配置排在前面不等于插件必须先启动。真正决定激活时机的是 Cordis 的 Service 依赖:Consumer 声明 inject,缺少依赖就等待,依赖到齐再激活。配置顺序负责覆盖,配置解决"最终装什么",依赖图解决"什么时候能运行"。
⚠️ 注意:一条 patch 是按 id 定位条目、然后替换它的整个 config,不是深度 merge。
Cordis 插件与事件
在 dsh 中,一个插件通常会做三类事情:
- 向共享 Context 注册 Service;
- 监听带类型的事件,参与某段流程;
- 注册可撤销 Effect,让资源跟随插件生命周期释放。
Service 像是稳定插座,Event 像是流程中的插针点,Effect 则负责"拔掉插件时把现场恢复干净"。 这三者合在一起,才让 Everything is a Plugin 不至于退化成一堆全局回调。
事件分成三个域:

Turn / Step 状态机:一次对话发生了什么?
接下来我们来看 ReactLoopAgent。它的核心实现没有想象中庞大,关键方法只有 preStep()、turn()、step() 等几段。先用图看一次完整流转:

官方定义:
- Step:一次模型请求,加上这次请求发起的 ToolCall;
- Turn:零个或多个 Step,从领取输入开始,直到没有后续工作为止。
为什么 Turn 里不是固定一个 Step?因为模型第一次请求可能只返回 ToolCall。工具结果写入 Session 后,模型还要在下一次请求中看到它,才能继续推理或给出最终答案。实际流程可以拆成七步:
- Inbox 领取一条输入,写入 turn/start;
systemPrompt.assemble()汇总 Prompt Section、变量和 Tool Schema;agent/pre-step允许插件改写输入或拒绝本次 Step;- 写入 step/start 与 user/message;
- 从 Session Log 投影模型历史,
llm.prepareCall()绑定本次精确 Adapter,再流式请求; - 每个流式片段写成
assistant/chunk,完成后再写assistant/message; - 若存在 ToolCall,进入 Tool Pipeline,写入
tool/result后再开下一 Step;否则关闭 Step 与 Turn。
这样可以让 流式体验和最终语义分开保存 ,既保证消息原始可重放,模型上下文又不必塞进一堆原始 chunk,并且Loop 也不需要承担策略 ,是否批准工具、如何改请求、Prompt 多一段什么内容、工具结果要不要裁剪,都由 Event 或 Service Plugin 完成,Loop 只维护状态机和持久化顺序。
Capability Seam:换 Shell,不改 Tool,更不改 Loop
"可插拔"最容易停留在接口层。DeepSeek Harness 更进一步,把一项能力拆成三个角色:
- Service Definition:只声明能力契约;
- Service Provider:提供一种实现;
- Consumer:使用能力,常见形式是暴露给模型的 Tool。
举个例子:

shell定义ShellServicebash-local、bash-sandbox、pwsh-local提供不同实现tool-bash作为 Consumer,把能力暴露给模型。
Consumer 注入的只是 Shell 契约,所以更换 Provider 时,Tool 和 Agent Loop 都不必产生平台分支。
官方文档强调:只有 Definition、Provider、Consumer 三者齐全,才构成真正的 Capability Seam。只有一个接口,叫抽象;只有一个 Tool,叫功能;三者能独立替换,才叫 能力缝。
Session Log:模型上下文不是 messages 数组
很多 Agent 原型会在内存里维护一个 messages,再顺手把它渲染到 UI。DeepSeek Harness 反过来:先把事实写进 Session Log,再为不同用途生成投影。
下面这张图把后端 Session 与前端启动放在一:

core/session维护 append-only 的SessionEvent日志。user/message、assistant/message、tool/result等模型可见事实全部从这里产生。deriveMessages再按 Surface 规则投影出下一次 LLM 请求所需的消息。
同一份日志还可以生成:
- 持久化 JSONL;
- Web 实时事件;
- Fork、Resume 与 Replay;
- Transcript、Telemetry 与 Compact 后的新历史。
官方是这样概括它:Model-visible means logged. 任何进入模型请求的内容,都必须能从日志重建。
Web UI 也没有逃离插件架构。
- Host 扫描各包的
dsh.client声明,生成带依赖边的启动清单 - 再把
window.__DSH_BOOT__注入首页; - 浏览器根据清单加载
/plugins/<id>/client.js, - 最后组合 React Shell。
也就是说,后端和前端共享的是同一种思想:先声明组件与依赖,再由运行时组合。
最后
DeepSeek Harness 把 Agent 工程里散落的几件事连成了一个闭环:
- Profile 把配置组合成插件树;
- Cordis 用 Service、Event、Effect 管理运行时协作;
- Capability Seam 隔离契约、实现与调用者;
- Agent Loop 只维护 Turn / Step 状态机;
- Session Log 为模型、持久化与 UI 提供同一事实来源。
浓缩成一句话:
DeepSeek Harness 的架构中心不是 Agent Loop,是
可组合、可替换、可回放的能力网络。
参考信息
- 原项目:DeepSeek AI,deepseek-harness
- 项目 README:Developer Preview 与启动方式
- 架构文档:DeepSeek Harness Architecture
- Cordis 入门:Cordis Primer