乐于分享
好东西不私藏

DeepSeek Harness 源码拆解:一个国民级AI团队是怎么理解Agent的,怎么设计Harness的

DeepSeek Harness 源码拆解:一个国民级AI团队是怎么理解Agent的,怎么设计Harness的

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

点击关注#互联网架构师公众号,领取架构师全套资料 都在这里

上一篇:2T架构师学习资料干货分享

大家好,我是互联网架构师!

说实话,DSH刚出来的时候,我的第一反应是——又一个Coding Agent?翻完源码之后,想法变了。这东西压根不是给你"用"的,是给你"拆"的。

一、先搞清楚:Harness 不是 Agent

8月13号,DeepSeek Harness(简称DSH)开源了,MIT协议,开发者预览版。GitHub上 stars 涨得飞快,圈子里吵成一锅粥。有人打开一看界面简陋,直接给差评;有人看到速度快就吹上天;也有人翻了两眼源码急着下结论。

我觉得吧,这些反应都正常,但起点可能都歪了。

DSH 官方最亮眼的一句话是 "Everything is a plugin"——万物皆插件。结合它的名字你大概能品出来:DeepSeek Harness 的定位,首先是一个运行时框架。所谓 Harness,就是套在模型外面那层让想法变成现实的系统工程。任务怎么继续、工具怎么执行、权限怎么拦、进程崩了怎么恢复,全是 Harness 的活。

至于它能不能 Coding、能不能 Design,那都是底层能力的映射。在 DSH 里,模型适配器是插件,工具注册表是插件,会话日志是插件,Agent Loop 也是插件——就连 Agent 本身都能换掉

所以如果你拿它跟 Claude Code 或 Codex 比"好不好用",这个比较本身就不太对劲。后两者是产品,DSH 是底座。产品关心的是"用户爽不爽",底座关心的是"开发者能不能看清每一行代码在干嘛"。

这个区分很重要,后面聊到架构差异的时候还会回来。

二、那棵树:DSH 的运行时全景

如果你准备跟着往下拆源码,先别满仓库乱翻。主线基本就在这几处:

packages/core/agent/           → Agent 身份、Inbox 和状态packages/core/agent-loop/      → 默认 Loop,Turn / Step 在这里跑packages/core/system-prompt/   → Prompt Section 的注册与组装packages/core/session/         → Event Log、恢复、Fork 和投影packages/core/tools/           → 工具 Registry 与执行链packages/preset/agent-presets/ → 每个 Agent 怎么装配packages/subagent/             → 子 Agent 的 Activation 与所有权packages/extensions/           → 动态 Cordis 扩展

DSH 的运行时架构可以概括为"一棵树"。

中间那根主干叫 Cordis Runtime,管插件怎么装上、对谁可见、什么时候激活、拔掉时怎么收尾。Agent Loop 没有什么"内核特权",它跟 Tools、Session、Shell、Subagent 一样,都是插在主干上的一块能力。

最上面是入口层。Web 是浏览器界面;headless 没有界面,跑完一次任务就结束;ACP 面向编辑器或自动化工具;SDK 给外部程序调用。四种入口都能发起任务,不是各养一套 Agent 内核——这点设计得很干净。

往下是装配层。Profile 是一次启动的"总装配方案",决定叠哪些 Bundle。Bundle 就是一组可复用的插件配置包。Patch 是覆盖层,可以针对某个插件替换配置。Preset 再决定某个会话里的 Agent 具体带哪些工具、Prompt 和能力。

第四层是能力与策略。文件系统、Shell、子进程、终端、LSP、Web、Skill、Subagent 各有实现;Sandbox、Permission、Approval、Guard 决定这些能力什么时候能用、怎么拒绝、什么时候找人确认。

最底下是 Session Event Log。模型看过的消息、工具调用和结果、Turn 与 Step、权限变化、压缩后的上下文,最终都回到这条事实流里。Web 页面、恢复、Fork、遥测和下一次模型请求,再从日志投影出各自需要的视图。

这就是典型的"观测回溯"设计——单源事实,多视图投影。做过分布式系统的同学应该很熟悉这个思路。

三、Cordis:这个底座有点东西

不少 Agent 框架也支持插件。通常做法是留一个 registerTool() 入口,外部传进名称、参数和执行函数,插件系统就算完成了。

但 DSH 说的"插件"深得多。深到是一套完整的系统

这个想法靠 Cordis 落地。Cordis 本身也是一个开源项目,已经有四年历史,之前是 Koishi 聊天机器人框架的底座。DeepSeek 基于 Cordis v4 搭建了 DSH——v4 的发布时间和 DSH 开源是同一天,不是巧合。

Cordis 背后有一篇论文,《A Programming Paradigm for Spatiotemporal Composability》,名字听着唬人,核心就两个概念:

  • Temporal composability(时间可组合性):组件卸载时,它的所有副作用必须能被完全撤销。Event 监听器、工具定义、内存分配、命令处理器——全部消失,系统回到"就像这个插件从来没装过"的状态。

  • Spatial composability(空间可组合性):组件可以声明依赖关系,运行时自动管理加载顺序和响应式更新。A 提供的服务被 B 消费,B 必须在 A 就绪后才能加载,A 停止前 B 必须先卸载。

落到代码里,Cordis 给 DSH 提供了四个关键机制:

1. Service:能力从哪来

工具消费者依赖 ctx.shell,不直接 import 本地 Shell 类。今天 Provider 用 Node 子进程执行,明天换成远程沙箱,消费者代码不用改,模型看到的工具也不用重写。这就是面向接口编程在 Agent 运行时的落地。

2. Event:谁能在中途插手

模型请求前、工具执行前后、Turn 停止前,都有带顺序语义的事件。有些是普通通知,有些是 Waterfall:插件处理完要调用 next(),后面的处理者才能继续。有些是单调 Guard:一旦某个插件拒绝,后面的插件不能又把它改成允许。

权限系统最怕的就是"大家都能改最终答案,最后谁覆盖谁全看运气"。Cordis 的 Guard 机制解决了这个问题。

3. Effect:卸载以后谁收尾

注册一个工具、监听器、计时器或 UI 区域时,同时登记清理动作。插件撤走,贡献也跟着撤走;Cordis 还会等它拥有的活动真正停下来。

否则所谓热更新,跑几次就会长出重复工具、幽灵监听器和杀不掉的后台进程。做过 VS Code 插件开发的同学应该深有体会。

4. Scope:这项能力对谁可见

全局工具、某个 Preset 的工具、某个 Agent 临时挂上的工具可以同时存在,查找时按 agent → preset → global 逐层解析。两个会话可以共用一套插件实例,又不会把 Session 状态混在一起。

不过要强调一点:Scope 不是安全沙箱。某个 Agent 看不到一项服务,只说明组合上不可见,不代表同一进程里的恶意代码绝对碰不到它。组合隔离和安全隔离是两回事。

普通插件系统关心"装了什么",Cordis 还要回答"什么时候生效、对谁生效、撤掉时谁负责收尾"。Agent 运行时比编辑器插件麻烦就麻烦在这——一个插件手里可能正握着子进程、审批请求和半个模型流,不能从数组里删个名字就假装它消失了。

四、Agent 不是 new 出来的,是叠出来的

理解 DSH,不能一上来就钻进 agent-loop 找入口。它启动的第一件东西是一棵 Cordis 插件树。

DSH 的 Agent 是通过四层配置叠出来的:

Bundle 提供配件。模型、工具、会话、入口可以分别打包,形成可复用的插件配置包。

Profile 组织产品。选择并叠加多个 Bundle,形成 Web、headless 等可运行的产品外壳。

Patch 做覆盖。针对某个插件行替换完整 config,不是深度合并;误配尽量在加载阶段就失败,而不是运行到一半才爆。

Preset 最终收口。决定某个 Agent 带什么 Prompt、Tools、Persona 与能力组合——在 Agent"出生"前就锁定。

所以打开 DSH 的 Web 界面新建会话时,能选四种模式:standard、PTC、minimal、cordis。它们不是四个不同二进制,只是四份 agent.cordis.yml 配置,决定这个 Agent 继承哪些工具和 Prompt。

官方默认的 Coding Agent,就是一行行插件配置拼出来的:

id: tool-bash  name: '@deepseek-ai/dsh-tool-bash'id: tool-fs  name: '@deepseek-ai/dsh-tool-fs'id: tool-skill  name: '@deepseek-ai/dsh-tool-skill'

看到这里感觉似曾相识——这不就是配置式 Agent么!

你能换掉的东西,和 DeepSeek 自己在用的东西,是同一份配置。没有内部特供版。不少框架嘴上说插件化,官方功能走内部通道,第三方走插件 API,两条路。DSH 不是。

这里多说一句。其他 Agent Harness 里常见的 MCP、Skill、Hook,DSH 里全都有,但存在形态完全不同。在 Codex 或 Claude Code 里,MCP、Skill、Hook 是三套独立的扩展机制,各有各的配置文件、加载方式和生命周期。在 DSH 里,它们全部是 Cordis 插件:MCP Client 是个插件,把外部 MCP Server 的工具注册到 ctx.tools 上;Skill Provider 是个插件,负责发现和加载 Skill 目录;Hook Bridge 也是插件,把 Claude Code 和 Codex 的 hooks.json 翻译成 Cordis 的拦截点。

同一套插件生命周期,同一套装载/卸载/清理规则。不用为每种扩展机制单独写一套管理逻辑——这个设计选择很 DeepSeek,就是"把复杂留给自己,把简单留给用户"。

当然,代价也明显。排错从"哪个函数错了"变成"当前 Profile 叠了什么 Bundle、哪层 Patch 替换了配置、Agent 属于哪个 Preset、服务落在哪个 Scope"。框架把扩展空间打开了,排查复杂度也跟着上来了。

自由从来不免费。

五、Turn 和 Step:任务到底怎么跑起来的

好,现在来看一个具体例子。用户说:"把项目里的端口配置改名,跑一遍测试,失败就继续修。"

这句话进来,系统得决定:当前装了哪些工具,读哪份系统提示,允许写哪个目录,Shell 在本机还是远程执行,工具结果怎么落盘,中途点停止哪些进程要杀掉,崩溃后怎么知道那条命令到底执行过没有。

DSH 怎么处理?

入口先创建 Agent。ctx.agents.create() 会建一个局部 Scope,在未发布状态下安装 Preset、Persona、工具限制和权限覆盖。全部成功,Agent 才进入 Registry。中途失败整体回滚,外面永远不会看见一个只装了一半能力的 Agent——这个原子性设计很到位。

Agent 和 Agent Loop 在源码里是两个包。Agent 负责身份、输入队列、状态和生命周期;ReactLoopAgent 只是驱动它工作的默认实现。换 Loop 不用重造 Session、Tools 和 Shell——"Loop Engineering"在 DSH 里是真的能换,不只是概念。

一次用户任务从收到到彻底完成,源码里叫 Turn。Turn 里模型可能请求多次:先看文件,接着编辑,再跑测试,最后总结。每一次"组装上下文、请求模型、执行这一轮工具"叫一个 Step。一个 Turn 可以没有 Step,也可以有很多个 Step。

Step 结束的标志是:模型这轮没再请求新工具,或者达到了停止条件。Turn 结束的标志是:用户任务彻底完成,下一条 followup 才进入新 Turn。

这个区分不是文字游戏。Step 对应的是一次模型请求,Turn 对应的是用户的一次完整意图。中间态(比如工具结果)写进 Session Log,但用户看不到——Web 界面只展示 Turn 级别的消息。这种"内部 Step 对用户透明"的设计,既保证了可观测性,又避免了界面信息过载。

另外,DSH 的输入模型分三种:

  • User Input:用户直接说的话,进 Inbox 队列。

  • Tool Result:工具执行完的结果,也进 Inbox。

  • System Event:系统内部事件,比如权限变化、子 Agent 完成通知。

三种输入走同一条队列,Loop 按顺序消费。这个统一队列的设计让并发和优先级处理变得简单——所有输入都是一等公民。

六、工具执行链与权限:不是"能不能用",而是"怎么拦"

工具在 DSH 里不是简单的"注册一个函数、模型调用、返回结果"。

一条工具调用从发起到落盘,要经过完整的执行链:

模型请求工具 → Schema 校验 → 权限检查 → 审批策略 → 实际执行 → 结果后处理 → 写入 Session Log

每一环都可以被插件拦截。Schema 校验失败,模型会收到格式错误提示;权限检查失败,Guard 插件直接拒绝;审批策略要求人工确认,执行暂停等用户点"允许"。

Sandbox 在 DSH 里也是一个插件化的概念。文件系统、Shell、子进程各自有 Provider,本地跑还是远程跑,由配置决定。shipped 的 sandbox 主要隔离文件系统效果,不是完整的机器隔离——网络访问和进程可见性默认没切。官方文档也明确说了这一点,没藏着掖着。

权限模型分几档:read-only、workspace-write、danger-full-access。danger-full-access 是故意不设防的,绕过沙箱而不是创建更宽的安全边界。这个设计很诚实——与其假装安全,不如把选择权交给用户

不过这里要提醒一句:如果你打算在生产环境用 DSH,现在还不是时候。官方 README 写得明明白白:developer preview,会有兼容性破坏的变更。Sandbox 不是完整隔离,Creator Mode 还能让模型写 JavaScript 跑在运行时里——这相当于给了模型 shell 级别的信任。

七、Session Event Log:为什么"可回放"比"可追溯"更重要

DSH 的 Session Event Log 是一个追加式事件流。System Prompt、思维链、工具调用和结果、子 Agent 调度、上下文注入——全部落盘。

这个设计的价值在哪?

想象一下:Agent 跑了三十多步之后做了一个错误决策。没有日志,你只能猜——是模型判断错了?工具返回的数据有问题?Prompt 被改了?还是上下文注入的时候塞了不该塞的东西?

有了追加式日志,你可以精确回溯到那一刻模型实际看到的上下文。不是"大概记得",是逐条事件回放。恢复、Fork、搜索、遥测,全部基于同一条事件流。

OpenAI Agents SDK 和 LangGraph 也把 tracing、持久化和恢复当作 Agent 运行时的重要能力。这说明一件事:可观测性已经从"调试工具"变成了 Agent 基础设施的标准组件

当然,追加式日志也带来了新的数据治理问题。完整的事件流可能包含代码、凭证线索、内部文件内容和工具返回结果。回放能力提高了可审计性,但也扩大了需要保护的数据面。

八、横向对比:DSH、LangChain、Codex、Claude Code

聊到这里,有必要把 DSH 放到更大的坐标系里看一眼。

DSH vs LangChain

LangChain 那一代框架的设计目标是降低 Agent 开发门槛——向上封装,Chain、Tool、Memory、Retriever 这些高度抽象把运行时细节藏起来,让开发者少操心。好处是上手快,代价是模型本身已经是黑盒,框架再叠一层封装黑盒,调试和优化就得穿两层不透明。

DSH 反过来。它的设计目标不是降低开发门槛,而是降低 Agent 体验和成本优化的复杂度。插件化颗粒度拆到极细,Session Event Log 记录一切事实,Agent 的每一次运行都有迹可循、可回放、可分叉、可审计。

黑盒越少,看得越清,优化空间越大。

开发门槛确实更高——你得理解更多底层细节。但换来的是:在模型本身解释性弱的现实下,至少框架这层是透明的。

目标不同,架构就不同。LangChain 范式向上封装,DSH 范式向下拆开。哪个会走得更远?不知道。但两者代表了 Agent 基础设施的两个极端方向。

DSH vs Codex / Claude Code

Codex 和 Claude Code 是产品。它们把模型、工具、界面、权限、云托管全部打包,开发者开箱即用。Claude Code 的 Hook 系统有 31 个生命周期事件,Codex 的内核沙箱用 Seatbelt/Landlock/seccomp 做 OS 级隔离——这些都是成熟产品的工程深度。

DSH 是框架。它不替你做决定,它把做决定的能力交给你。

有意思的是,DSH 甚至支持把 Codex 或 Claude Code 作为子 Agent 调用。也就是说,你可以用 DSH 的 Harness 做编排层,把具体子任务丢给 Codex 或 Claude Code 去执行。这不是竞争关系,是互补关系——DSH 想做的是 Agent 世界的"操作系统",而不是某个具体的"应用程序"。

维度
DeepSeek Harness
Claude Code
Codex
定位
开源 Agent 框架
终端原生产品
ChatGPT 生态产品
模型锁定
无,支持多 Provider
Claude 为主
GPT 为主
插件化
极致(Loop 都可换)
强(Hook/MCP/Skill)
强(MCP/Skill)
可观测性
追加式事件流
Trajectory + 日志
日志 + 追踪
沙箱
插件化,非完整隔离
OS 级 + 应用层
内核级
成熟度
Developer Preview
成熟商业产品
成熟商业产品
许可证
MIT
商业
CLI Apache 2.0

九、四种模式,四种用法

DSH 开箱自带四种 Agent Preset,不是四个二进制,是四份配置:

Standard 模式:功能完整的编码 Agent,文件编辑、Shell、文件与网页检索、Skills、计划、目标、子代理和工作流——日常开发用这个。

PTC 模式(Code 模式):具备 Standard 的全部能力,但通过 Code Mode SDK 呈现工具,让模型用一个 TypeScript 程序组合多步操作。这能把多个工具调用 round trip 压缩成一次程序执行,减少模型请求次数

Minimal 模式:仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。DeepSeek 自己跑官方模型基准测试用的就是这个模式。所以如果你看到 V4 Pro 的 benchmark 数字,要知道那是在 Minimal 环境下测的——生产环境的工具面和 Prompt 面都比 Minimal 大得多,实际表现会有差异。

Creator 模式:用于创建自定义 Agent preset,具备 Standard 模式的全部能力,加上运行时检查、插件实验和 preset 创作指导。这个模式给了模型写 JavaScript 跑在运行时的能力——信任边界等同于 shell 级别,别在重要代码库上乱试。

十、写在最后:它到底适合谁

说实话,现阶段 DSH 不是面向普通用户的 2C 产品。界面简陋、配置复杂、文档还在迭代,这些都是事实。

但它是一套面向开发者的 Agent 底座。如果你是以下这些人,值得花时间看看:

  • Agent 基础设施开发者——你想理解一个国民级 AI 团队怎么设计 Harness,DSH 是目前最透明的参考实现。

  • 需要定制化 Agent 的企业——你可以不 Fork 主循环,拼出只读审计 Agent、带远程沙箱的 Coding Agent、无 Web 的自动化 Agent。

  • 模型研究者——想控制变量做实验?DSH 的插件化让你可以只换 Loop、只换 Prompt 组装逻辑、只换工具执行链,其他保持不变。

  • 对 LangChain 封装感到窒息的人——DSH 把黑盒一层层拆开,至少框架这层是透明的。

不适合谁?

  • 想要"下载即用、界面精美"的开发者——去用 Claude Code 或 Codex。

  • 需要生产级稳定 API 的团队——DSH 还在 developer preview,breaking changes 是官方明确承诺会有的。

  • 对安全隔离要求极高的场景——shipped sandbox 不是完整机器隔离,Creator Mode 更是高风险。

DeepSeek 选 Cordis 做底座,而不是自己从头撸一个插件系统,这个选择本身就有信息量。Cordis 已经跑了四年,经历过 Koishi 聊天机器人的真实插件 churn,有社区、有论文、有形式化保证。DSH 的"Everything is a plugin"不是一句口号,是建立在可逆副作用和响应式依赖管理之上的工程承诺。

最后说一句可能被喷的话:DSH 的真正价值,可能不在它今天作为产品好不好用,而在它把 Harness 这层"该怎么做"摊开了。 Agent = Model + Harness,这个公式行业里喊了很久,但把 Harness 的每一层拆开给你看、让你能换、让你能审计的,DSH 是第一个。

至于它能不能成?让代码自己证明吧。


(本文基于 DeepSeek Harness v0.1 开发者预览版源码及官方架构文档撰写。DSH 迭代很快,部分细节可能随版本变化。)

1、2T架构师学习资料干货分享

2、10000+TB 资源,阿里云盘,牛逼!!

3、基本涵盖了Spring所有核心知识点总结

  · END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描上方二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连点赞、转发、在看