一句话总结:DeepSeek 开源的这个智能体运行时,把"模型可插拔"这件事做到了骨头缝里——不只是模型能换,连"agent 该怎么思考、下一步干什么"这个决策循环本身,都是一块能拔下来换掉的插件。这篇文章拆开看它的三层配置组合、事件管线和能力接缝设计,代码全部标注真实文件路径;最后聊聊同一套设计哲学,在企业级场景里是怎么落地的。

全文约 6000 字,基于 deepseek-harness 仓库源码与仓库自动生成文档逐条核实,文末附太一企业版与 MateClaw 的开源实现。

在这里插入图片描述


目录


一、先说个数字:不到 24 小时,5 万 Star

写这篇之前,我先去 GitHub API 上核了一遍数字,没敢直接抄网上流传的说法:

curl -s https://api.github.com/repos/deepseek-ai/deepseek-harness | \
  python3 -c "import json,sys;d=json.load(sys.stdin);\
  print(d['stargazers_count'], d['created_at'], d['pushed_at'])"

结果:仓库创建于 2026-08-13T11:56:32Z,我核验的时间点是 2026-08-14T01:49:28Z,上线还不到 24 小时,star 数已经冲到 52,959,按 24 小时算,平均每小时涨了将近 2200 颗。fork 数 4279,issue 数是 0——不是没人提问题,是仓库还没开放 issue,一个典型的"先扔出来看看反应"的开发者预览发布。

这么猛的涨势,通常有两种原因:要么是营销做得好,要么是内容本身戳中了工程师的痒点。翻完源码之后我倾向于后者——它解决的不是"模型能不能调工具"这种已经被无数框架讲烂的问题,而是"agent 这套骨架本身要怎么设计,才能撑得住五年后的维护"这个更难的问题。


二、这是个什么项目

DeepSeek Harness,仓库里简称 dsh,是 DeepSeek 官方开源的一套智能体运行时(agent harness)。README 里写得很直白:还在开发者预览阶段,接口会变,包会重命名,别指望现在就稳定。

它构建在一个叫 Cordis 的插件框架之上,核心理念项目自己总结为一句话:everything is a plugin,一切皆插件。

这句话在大多数框架里只是营销用语——留几个回调函数、加个中间件接口,就敢叫"插件化架构"。但 dsh 做得更彻底:连 agent 的主循环本身也是一个插件。模型怎么接、工具怎么注册、会话怎么存、沙箱策略怎么定,乃至"该看什么、该问模型什么、下一步该干嘛"这套决策循环,全部是可以被整体替换的组件,不存在一个焊死的"内核"。

理解这个项目,只需要记住一个前置概念:capability seam(能力接缝)——一套"接口定义 / 可插拔实现 / 消费者"三件套模式。第五节会展开讲。


三、三层拼装:profile / bundle / patch

dsh 的配置组合方式是三层结构,理解它能少走很多弯路。

bundle(预制配置包)→ profile(你自己的组合方案)→ patch(改造单)
  • bundle:打底配置包。dsh-base 打的是每个 profile 都要用到的底子——模型适配器、工具箱、持久化、沙箱与审批策略、凭据、遥测。再叠一层模式包:要浏览器界面叠 dsh-web-app,只跑一次任务叠 dsh-headless
  • profile:你自己的组合方案,决定叠哪些 bundle,再写一份自己的 cordis.patch.yml
  • patch:改造单,按行 id 定位、整段替换目标配置,不是逐字段深合并。四层改造单(bundle → profile patch → 全局 patch → 命令行 --patch)依次盖上去,最后一层生效。

在这里插入图片描述

这套设计认真到什么程度?举个实锤——Windows 和 macOS/Linux 用不同的命令行执行器,这种平台差异在大多数项目里会写成 if-else,但在这里它是同一张改造单上两条互斥的行,一字不改摘自 packages/bundle/base/cordis.patch.yml

- id: bash-sandbox
  name: '@deepseek-ai/dsh-bash-sandbox'
  disabled: !!js process.platform === 'win32'

- id: pwsh-sandbox
  name: '@deepseek-ai/dsh-pwsh-sandbox'
  disabled: !!js process.platform !== 'win32'

- id: tool-bash
  name: '@deepseek-ai/dsh-tool-bash'
  disabled: !!js process.platform === 'win32'

- id: tool-pwsh
  name: '@deepseek-ai/dsh-tool-pwsh'
  disabled: !!js process.platform !== 'win32'

四行 disabled 条件两两互斥,同一台机器上永远只剩一套 shell 栈生效。平台差异被当成数据处理,而不是揉进代码分支——这是"配置即架构"的一个很干净的例子。

想看最终拼出来的完整配置树,一条命令:

dsh --profile web --dump-config

四、一次对话的八步管线

dsh 里模型和用户的一次交互是个套娃结构:一个 turn(回合),里面套着零到多个 step(步),直到没活儿要干了才收尾。拆开来看是这八步:

在这里插入图片描述

其中第 3 步"插件插话"最值得细看,术语叫 waterfall(瀑布链):一堆插件排成队,每个都能看一眼消息、改一改,改完必须显式调用 next() 才轮到下一个;漏调一次,整条链就断在这儿,后面的插件全部收不到消息。这不是没写完的功能,是故意设计成这样——谁截胡了消息,代码里一眼能看出来。

这一步的官方定义,一字不改摘自 packages/core/agent/src/runtime-types.ts

/**
 * @param payload.agent - the agent proposing the step.
 * @param payload.messages - messages removed from the inbox for this step.
 * @param payload.turn - the turn that will own the step.
 * @param payload.step - the step proposed by the loop.
 * @param payload.signal - the current turn's cancellation signal.
 * @mode waterfall
 */
'agent/pre-step'(
  this: Scoped<Agent>,
  payload: { agent: Agent; messages: UserMessage[]; turn: number; step: number; signal: AbortSignal },
  next: () => Promise<PreStepDecision>
): Promise<PreStepDecision>

@mode waterfall 这行注释不是随手写的说明文字,而是会被自动生成脚本扫进 docs/event-producer-consumer.md 的正经元数据——这套体系后面第六节详细讲。


五、能力接缝(capability seam):全篇最值得学的设计

如果整篇文章只让我留一个知识点,我会选这个。

dsh 把几乎所有"能力"都抽象成了一套标准接口,项目文档管这套模式叫 capability seam(能力接缝),拆开是三个角色:

角色含义
① 接口定义只约定能力长什么样,比如 ctx.fs 只约定要有 read / write / edit 三个方法
② 可插拔实现挑一个装上,同一时刻只挂一个,比如 fs-local(本地磁盘)、fs-sandbox(沙箱围栏)、fs-e2b(云端沙箱容器)三选一
③ 消费者只认接口,不管背后是哪个实现——模型可见的 read/write/edit 工具只认 ctx.fs,换掉背后的实现,消费者一行代码都不用改

在这里插入图片描述

项目文档特意强调:只有一个角色,不能叫"接缝"——光有接口没实现不算数,光有实现没有稳定消费者也不算数,三个角色凑齐才是完整的一套能力。这样的三件套,全项目出现了三十多次:

接口可插拔实现谁在用
ctx.llmllm-deepseek · llm-pi-ai · llm-replay(测试)agent-loop
ctx.fsfs-local · fs-sandbox · fs-e2btool-fs
ctx.shellbash-local · bash-sandbox · pwsh-localtool-bash / tool-pwsh
ctx.subprocesssubprocess-local · subprocess-e2bbash/PTY/LSP/子Agent 执行器
ctx.subagentsspawn/fork-in-process · acp · codex · claude-code · dsh-sdktool-subagent · tool-ralph
ctx.webweb-search-exa/perplexity/deepseek · web-fetch-httptool-web
ctx.sessionPersistencesession-persistence-jsonl · -sqliteagent-loop · session-query
ctx.approvalacp(ACP 桥应答)core/tools · tool-bash;无应答即拒绝

这套设计不是文档层面的约定,而是被类型系统摁在地上强制执行的。整个工具注册表——所有模型能调用的能力的总管——本身就是一个继承自 Cordis Service 的普通类,摘自 packages/core/tools/src/index.ts

export class ToolRuntime extends Service {
  static inject = ['systemPrompt']

  static Config: z<Config> = z.object({
    mode: z.union(['native', 'code', 'both'] as const).default('native'),
    maxParallelSubCalls: z.natural().min(1).default(10),
  })
  // ……注册表、around-dispatch 守卫管线都挂在这个类上
}

连工具注册表自己都要在 static inject 里声明依赖谁,不能搞特殊。"一切皆插件"不是宣传语,是编译期约束。


六、事件管线:三种"插话权限"

第四节提到的 agent/pre-step 只是一个例子,dsh 的整套扩展机制都建立在事件上,而且明确区分了三种"插话权限":

模式含义
waterfall(瀑布链)必须显式调用 next() 才能继续往下传,可以拦截、改写
serial(串行)依次执行,不需要显式放行
emit(广播)纯广播,谁都拦不住

挑几个关键事件列出来(数据来自项目自动生成并在 CI 里校验新鲜度的 docs/event-producer-consumer.md):

事件模式干什么
agent/pre-stepwaterfall这一步开始前,插件可改写或拒绝要发给模型的消息
agent/request-errorwaterfall请求模型失败时的恢复入口(比如触发压缩重试)
tools/pre-executewaterfall工具真正执行前的策略检查
tools/executewaterfall环绕执行——超时、检查点挂在这一层
tools/post-executewaterfall结果出来后的策略——超长结果溢出存储、重复调用提醒
agent/turn-stoppingserial回合要收尾了,插件可以阻止真正停下
session/eventemit每条日志广播出去,23 个包在监听
fs/write-intentwaterfall写文件前的门禁——"没读过就不让改"策略挂在这
approval/requestwaterfall一次性权限决策,没人应答默认拒绝

一个事件到底能不能被插件拦下来改主意,看它标的是哪种模式,源码里一眼能看明白,不需要翻十八层调用栈猜。这份事件矩阵本身也不是手写维护的——它由静态分析 TypeScript 源码自动生成,少声明一个 @mode,生成脚本就报错。


七、模型可见 ⟺ 已记录:审计怎么落地

dsh 有一条贯穿全局的硬规矩,项目里给它取了个学名叫 “Model-visible ⟺ logged”模型看到的每一句话,必须能从日志里原样重建出来。

翻译成工程语言:模型不能"偷偷看到"任何没被记下来的东西。想让模型多看到一种新信息,必须先在日志格式(SessionEventMap)里正式开一个位置,不能走后门直接塞进去。

具体实现上,整个对话过程被当成一份只增不改的日志(session log)来记录:每一条模型看到的消息、每一次工具调用、每一个状态变化,都追加写进这份日志。它不是"记个日记",而是重放整场对话、给会话分叉、断点续跑、生成遥测统计的唯一真源

这条规矩换来的直接好处是:一个智能体半夜自己续跑了三个小时,理论上你能把整场对话原样倒带出来看,而不是对着一堆"看起来结果没错"的最终产出猜过程。做过线上排障的工程师应该懂这种价值——最怕的不是系统坏了,是坏了但说不清怎么坏的。


八、二十个能力域全景 + 内置工具清单

仓库有 300 多个 workspace 包,按功能收拢一下,大致是这二十个能力域,每一块都是独立插件,能单独开关、单独替换、单独测试:

在这里插入图片描述

能力域干什么主要包
Shell / 终端跑命令行,一次性或持久 PTY 两种shell/*, terminal/*
文件系统读写编辑 + 内置 ripgrep 搜索,改前强制先读fs/*
进程沙箱bwrap / Landlock / Seatbelt / Windows ACL 围住能碰哪些文件sandbox/*, native/
子 Agent6 种委派方式:进程内、ACP、Codex、Claude Code、SDKsubagent/*
工作流 / 后台作业脚本编排 + 新鲜循环 Ralph;统一的后台任务控制workflow/*, jobs/*
Code Mode模型写一段 TS 程序,一次性并发调用多个工具core/tools, code-runtime/*
技能 SkillSKILL.md 目录,先看名字/描述,匹配上再加载完整说明skill/*
Web 访问 / LSP网页搜索抓取;四种归一化的代码导航查询web/*, lsp/*
计划 / 目标 / 定时先出方案审过再动手;长任务自动续跑;会话本地到点提醒plan/*, goal/*, schedule/*
人机审批一次性权限决策,没人应答默认拒绝(fail-closed)interaction/*
自我修改智能体自己写代码,动态挂/卸自己的插件(vm 沙箱执行)extensions/*
Hook 桥接 / MCP忠实执行既有 Claude Code / Codex hooks.json;接入外部 MCP 工具hooks/*, mcp/*
Web GUI / 对外协议30+ 插件拼出浏览器界面;ACP / JSON-RPC SDK 给别的程序驱动 dshclient/*, host/*, acp/, sdk/*

这张表来自项目自己的 docs/tool-catalog.md——生成方式挺硬核:不是拿正则扫代码文本,而是真的把每一个工具插件启动起来,读它运行时暴露出来的 schema,因为有些工具名和参数是运行时拼出来的,静态扫描扫不出来。少注册一个工具包,脚本直接报错不给过。

拿最常用的 bash 举例,它真正发给模型的 JSON Schema(原样摘自生成文档):

{
  "properties": {
    "command":     { "type": "string" },
    "description": { "type": "string" },
    "timeoutMs":   { "type": "number" },
    "workdir":     { "type": "string" },
    "run_in_background": { "type": "boolean" }
  },
  "required": ["command", "description"]
}

留意 run_in_background 这个参数——设成 true,调用立刻返回一个任务 id,真正的输出靠 job_output 另外去取。这是"后台作业"能力域和"Shell"能力域怎么勾连起来的实锤:一个工具身上的一个参数,背后调用了另一整个能力接口,模型完全不用知道这层弯弯绕。


九、同一套设计哲学,企业级怎么落地:太一企业版与 MateClaw

讲了这么多 dsh 的架构,聊点题外话。dsh 从 agent 运行时这个方向,把"模型是可替换的模块,而不是绑死的地基"这条设计原则做到了极致;这条原则我们在企业级场景里,从另一个方向也做了两年——太一企业版(mate-hive 引擎)和它的开源底座 MateClaw

两边技术栈完全不同:dsh 是 TypeScript + Cordis 插件框架,走的是"agent 运行时"路线;MateClaw 是 Spring Boot + Spring AI Alibaba,走的是"企业级治理平台"路线。但殊途同归,核心判断是同一句话:

dsh 的设计MateClaw / 太一企业版对应的实现
ctx.llm 能力接缝,模型是可插拔实现Purpose 路由:业务只声明"要什么能力",不声明"要哪个模型";14+ 家模型厂商可切换、主备熔断
profile / bundle / patch 三层配置组合starter 化交付:装什么 starter、有没有 license,决定是开源版还是企业版
session log:模型可见 ⟺ 已记录全链路审计:Thought / Action / Observation 全轨迹落库,runId 贯穿网关到模型调用
capability seam 三件套(接口/实现/消费者)Filter 链治理:ToolGuardFilter → AuditFilter → DesensitizeFilter,加一层治理 = 加一个 Bean
一切皆插件,连 agent-loop 本身也是插件Agent 定义落库,是组织资产不是散在 prompt 里的字符串;草稿/发布双槽,可回滚

MateClaw 是这套企业级实现的开源版本:

git clone https://github.com/mateaix/matecloud    # DDD 微服务底座
git clone https://github.com/mateaix/mateclaw     # AI Agent 平台,Apache 2.0

它基本对应上面表格右列的实现:14+ 家模型厂商路由与故障切换、数字员工(ReAct + Plan-and-Execute 编排)、Skills 体系、MCP/ACP 双协议接入、RBAC + 审批流 + 审计留痕 + 内容合规扫描,外加 LLM Wiki(带引用溯源)、工作流引擎(7 种步骤模式)、8 个 IM 渠道接入。技术栈是 Spring Boot 3.5 + Spring AI Alibaba + MyBatis Plus + Flyway,前端 Vue 3 + TS + Vite + Element Plus。协议是 Apache 2.0,README 上有句话我很喜欢:free, no metered tokens, no seat billing——免费,不按 token 计量,不按坐席收费。

至于太一企业版,干的就是把这套能力做成生产级:租户隔离、审计回放、工作流和知识沉淀这些长期值钱的东西留在企业自己手里。它和 MateClaw 是同一份核心代码,装什么 starter、有没有 license,决定它是开源版还是企业版——丢 jar 即点亮,拔 jar 即降级。商业咨询与私有化部署入口:mate.vip/enterprise

一个 TypeScript 生态验证了这套架构范式,一个 Java 生态把它做进了企业级治理——这大概说明,"模型可替换、能力可插拔"这条路不是谁拍脑袋想出来的,做 agent 基础设施的人,走到最后都会走到这儿。


十、总结与自检清单

核心观点回顾

  1. 循环本身也要设计成可替换组件——大部分框架把主循环焊死在内核里,dsh 把它做成一个服务,扩展包只依赖抽象接口,不依赖具体实现
  2. 能力用三件套接口隔离——接口定义 / 可插拔实现 / 消费者,三个角色缺一不可,这是"一切皆插件"真正能落地的原因
  3. 模型可见即已记录——把"必须能重放"提到架构约束层面,而不是"最好记个日志"这种口头建议
  4. 文档由代码生成,不是手写的——工具目录靠真启动插件读 schema,事件矩阵靠静态分析源码,两者都在 CI 里做新鲜度校验
  5. waterfall 事件强制显式放行——没有隐式的"默认往下传",想拦截就拦截,想放行必须显式调用
  6. 审批默认拒绝(fail-closed)——没人应答,请求直接判定为不可用,而不是放行

六个自检问题

不谈架构美学,全是能当场对照自己项目验证的:

  1. 你的 agent 主循环,能不能不改内核代码就换掉?
  2. 模型供应商明天涨价一倍,你的业务代码要不要跟着改?
  3. 出了问题,你能不能把整场对话原样倒带出来看,而不是猜?
  4. 你的事件/中间件机制,插件想拦截和想放行,代码上分得清楚吗?
  5. 你的工具文档,是手写的还是自动生成校验的?多久没更新过了?
  6. 高风险操作没人审批的时候,你的系统默认是放行还是拒绝?

六个问题如果有一半答不上来,那不是 agent 能力不够,是运行时骨架还没设计对。


参考资料

  • deepseek-ai/deepseek-harness 仓库 README.md / AGENTS.md
  • 仓库自动生成文档:docs/architecture.md · docs/capability-seams.md · docs/tool-catalog.md · docs/event-producer-consumer.md
  • 源码:packages/core/agent/src/runtime-types.ts · packages/core/tools/src/index.ts · packages/bundle/base/cordis.patch.yml
  • GitHub API star 数据,核验于 2026-08-14 01:49 UTC(仓库创建于 2026-08-13 11:56 UTC)
  • MateClaw · MateCloud README
  • 太一企业版产品页:mate.vip/ee

声明:本文架构图均为原创绘制。deepseek-harness 相关代码片段均标注真实文件路径,摘录用于说明架构,非完整源码复制,仓库仍在开发者预览阶段,具体接口以你核对时的源码为准;本文与 DeepSeek 官方无隶属关系,属第三方技术解读。GitHub star 数据经 API 实时核验,具体数字请以你阅读时刻的最新数据为准。MateClaw / 太一企业版相关功能点取自项目 README 与产品页。

如果这篇对你有用,欢迎点赞收藏。具体架构问题,评论区聊。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐