"一切皆插件"这句话本身没错,但它是结论不是解释。要听懂 DeepSeek Harness(dsh)牛在哪,得反过来问:它把一个 Agent 系统里"本来会被写死"的那些东西,到底怎么变成了插件?变成插件后又拿到了什么别人拿不到的能力?
下面按源码结构一层层拆。
先建立一个总图景:dsh 是一棵"插件树",不是一栋"大楼"
大多数 Agent 框架的画像是:中央有个固定的 Agent Loop 大核心,外面挂一些 tool 扩展点。dsh 不一样,它基于自研的 Cordis 插件内核,整个运行中的 dsh 实例是一棵插件树,由启动时的各层配置按顺序叠加而成:
空根 ↓ profile 里列出的各个 Bundle(按声明顺序) ↓ profile 的 cordis.patch.yml ↓ Harness home 级的 patch ↓ 命令行 --patch overlay
dsh-base 是第一层,提供模型适配器、工具、持久化、沙箱、审批策略、设置、凭据、遥测;dsh-web-app 加浏览器界面;dsh-headless 加"跑一次就退"的无服务器模式。越往后叠的层权力越大,任何一条启动配置都能被你的 patch 按 id 替换。
💡 这意味着:连 UI 都是配置文件里的行。打开
~/.dsh/profiles/web/cordis.patch.yml,加三行禁用id: ui-sidebar的那一行,reload,侧边栏消失;删掉那三行,它又回来。
这才是"一切皆插件"的真正含义——不是"给你加个插件接口",而是没有特权核心。文档原话:"不存在需要打补丁的特权内核"。模型适配器、工具注册表、会话日志、agent loop 本身、UI、沙箱、审批策略,全都是平等的插件。
源码层面,它的"核心"小到不可思议
这是 dsh 最反直觉的地方。整个 50+ 包的 Monorepo 里,**唯一包含具体循环逻辑的包是 packages/core/agent-loop**。
文档里写得很直白:
"This is the only package in the harness that contains concrete loop logic. Everything else is an abstract service or a plugin against extension points — new behavior goes into plugins, not here."
也就是说,核心循环只干一件事:拿着用户的输入去问模型,模型说要调用什么工具,就去调,把结果拿回来再问模型,直到模型说可以回复了。
至于"调用工具"具体意味着什么——是执行 bash?是改文件?是发 HTTP 请求?是委派给子 Agent?——核心循环一概不管,它只认识 ctx.tools 这个服务接口。具体的工具实现全是插件挂在 ctx.tools 上的。
核心包与 ctx 键的映射非常干净:
所有插件通过 ctx.xxx 这种稳定的键来查找服务,而不是硬编码 import。这是"无特权核心"能在代码层面成立的关键。
Cordis 的三个机制,决定了它为什么"牛"
光有架构图不够,得看 Cordis 提供了哪三个具体机制,让"一切皆插件"不是一句空话。
1. 插件 = Service 对象,inject 声明依赖
import type { Context } from "@deepseek-ai/cordis";export const name = "tool-plugin";export const inject = ["tools"];export function apply(ctx: Context) { ctx.tools.register(/* tool definition */);}
Cordis 会等 tools 这个服务就绪后才调用 apply,自动解析注入顺序,避免手动管理依赖。
2. 注册是可逆的 Effect
插件通过 ctx 做的任何注册(工具、监听器、事件、UI 组件),在插件卸载时自动按反顺序撤销。如果需要清理定时器、关闭连接这类非 Cordis 原生资源,用 ctx.effect() 返回一个 disposer 就行。
ctx.effect(() => { const connection = connectExternal(); return () => connection.close(); // 卸载时执行});
这就是论文里说的"时间可组合性"——组件被移除时必须能完全撤销副作用,回到安装前的状态。带来的直接好处:插件可在不重启系统的情况下加载/卸载,热重载时能精确卸载,不会留下 dangling 状态。
3. 类型化事件的四种分发模式
服务之间通过事件协作,Cordis 支持四种模式:emit(通知)、waterfall(中间件链,监听器可调用 next() 传递或短路)、parallel(并行)、serial(串行)。
waterfall 模式是安全管道的基础——后面会看到它怎么用在工具执行上。
真正体现功力的两点设计
光是插件化还不够。dsh 有两个设计,是它区别于"又一个插件框架"的关键。
🎯 设计一:Session 是"事件溯源"的仅追加日志
传统做法是维护一个 messages 数组,同时维护一个日志,两者可能不同步。dsh 的做法:只存储事件日志(append-only),LLM 看到的消息历史是从这份日志实时派生的。
用户消息 → 写入日志模型回复 → 写入日志工具调用 → 写入日志工具结果 → 写入日志子 Agent 调度 → 写入日志每一次上下文注入 → 写入日志
因为消息历史是派生的,重放日志 = 重建一切。这让几个能力变得天然可行:
fork:从某次事件分叉出新会话 resume:断点续跑 replay:完整重现一次 Agent 运行 search:在历史事件中检索
📌 设计铁律:"模型可见即已记录"。Trace UI 展示的调用轨迹、Token 数量——全部来自日志派生,不需要额外的插桩代码。
对企业级部署、安全合规审计来说,这个能力是刚需。
🎯 设计二:工具执行是带"洋葱模型"的五道关卡
工具调用不是"模型说执行什么就执行什么"。每个工具调用都要走这样一条管道:
pre-execute → monotonic guards → execute → post-execute → finalize
对应到 Cordis 的事件机制,就是 tools/dispatch 这条 waterfall 事件链上挂着一系列监听器:
pre-execute:权限校验——允许、拒绝或询问用户 execute:实际执行工具逻辑(带 around-dispatch 包装器) post-execute:检查或替换结果 finalizeContent:将结果转换为模型可消费的格式 tools/result:写入会话日志,成为权威结果
每一层都可以拦截、修改或拒绝。文档里特别强调了一句很硬的话:
"先检查权限部分。跳过它,模型就拥有了一条绕过你自己规则的有效路径。"
这是安全管控的核心机制——不是事后审计,而是事中拦截。配合进程沙箱的"失败关闭(fail-closed)"原则:沙箱不可用时直接报错,绝不允许静默绕过。
把上面这些拼起来,看"牛"在哪
现在可以正面回答你的问题了。dsh 的"牛"不是因为它功能多,而是它在源码层面做到了四件事:
1. 核心极小,扩展极大。 整个 harness 唯一的具体循环逻辑在 agent-loop 一个包里,其他全是抽象服务或插件。新行为进插件,不进核心——这意味着核心 bug 面极小,且不会被业务代码腐蚀。
2. 没有"特权核心"需要打补丁。 这是 Cordis 架构的直接后果。扩展系统的唯一方式是在核心旁边挂一个新插件,而不是去改核心源码。注册是可逆副作用,卸载自动回滚。这解决了插件化框架最大的痛点:装了卸不干净。
3. 单一事实源 + 派生视图。 所有交互以仅追加事件日志存储,LLM 上下文、UI 轨迹、Token 统计全从日志派生。这让 fork/resume/replay/search 成为架构的自然产物,而不是事后打补丁补出来的功能。
4. 安全是管道的一等公民,不是外挂。 工具执行的五道关卡是 waterfall 事件链上的监听器,权限检查在执行链的最前面,跳过就等于给模型开了绕过规则的口子——所以架构上根本不允许跳过。
举个具体的例子,感受一下这套设计的威力
假设你想把"模型适配器"从 DeepSeek 换成 Claude。在传统框架里这可能要改一堆 import、改配置解析、改错误处理逻辑。
在 dsh 里,你只需要在 cordis.patch.yml 里替换 llm 这一行的 provider id:
- id: llm provider: anthropic config: apiKey: ${ANTHROPIC_API_KEY}
因为 core/agent-loop 只依赖 ctx.llm 这个接口,不依赖具体实现,换 provider 对循环逻辑零影响。同理,换沙箱后端、换持久化存储(JSONL ↔ SQLite)、换 UI,全部是配置层的替换。
⚠️ 需要提醒:dsh 目前是 Developer Preview 阶段,官方明确说会有 breaking changes,不要直接上生产。
为什么这件事在 2026 年特别重要
回到 DeepSeek 自己的公式:Agent = Model + Harness。
当各家模型能力趋同时,真正决定一个 Agent 产品好不好用的,是 Harness 这一层——上下文怎么管、工具怎么调、权限怎么控、失败怎么回滚、多 Agent 怎么编排。dsh 的价值在于:它把这些"胶水工作"标准化、插件化、可组合化了。
所以"一切皆插件"翻译成人话就是:dsh 把 Agent 系统从"一个写死的流程"重构成了一个"可替换、可回滚、可审计、可热扩展的运行时"。核心循环小到不能再小,所有变化都发生在插件边界内——这就是它在工程上的真正厉害之处。
最值得直接读的两个源码文件是 packages/core/agent-loop(看核心循环到底有多精简)和 packages/mcp/mcp-client/src/index.ts(看一个外部协议是怎么被 170 行代码"收编"成 Cordis 插件的,这个例子最能体会"统一注册路径"的威力)。
有时间写一个解读。
夜雨聆风