乐于分享
好东西不私藏

别急着啃源码:DeepSeek Harness 到底应该怎么学?

别急着啃源码:DeepSeek Harness 到底应该怎么学?

从跑通 Demo,到理解“一切皆插件”,再到真正读懂 Agent 是如何运转的。

DeepSeek Harness 开源之后,很多人的第一反应都是:

怎么安装?从哪个目录开始看?有没有教程?

这些问题当然重要,但我觉得,在打开源码之前,还有一个更关键的问题:

DeepSeek Harness 到底应该怎么学?

因为它不是一个学会几个 API、照着示例接上模型,就算掌握了的项目。

如果只是想体验,跑一条命令就够了;但如果想真正理解它,甚至基于它开发自己的 Agent,只盯着工具调用、Prompt 和模型适配器,很容易越看越乱。

DeepSeek Harness 真正值得研究的地方,不是“它又做了一个 Coding Agent”,而是它试图用一种彻底插件化的方式,重新组织 Agent 系统里的模型、工具、会话、循环、文件系统、沙箱和界面。

所以,学习它的顺序也应该随之改变。

这篇文章不打算逐行教你写代码,而是想给出一条我认为更合理的学习路线:先建立直觉,再理解设计哲学;先看系统如何组装,再看 Agent 如何运行;最后用一个插件验证自己是否真的理解。


一、先搞清楚:你学的不是一个“聊天机器人项目”

很多 Agent 项目都可以用下面这条链路来理解:

用户输入 → 模型推理 → 调用工具 → 返回结果 → 继续推理

DeepSeek Harness 当然也有这条链路。

但它更关心另一个问题:

组成这条链路的每一部分,能不能被独立加入、替换、组合和卸载?

在 Harness 中,模型适配器是插件,工具系统是插件,会话存储是插件,Agent Loop 是插件,沙箱和文件系统也是插件,甚至 UI 本身也可以被视为插件。

这就是官方反复强调的那句话:

Everything is a Plugin.

它不是一句营销口号,而是理解整个代码库的入口。

因此,学习 Harness 时不要只问:

  • • 它有哪些工具?
  • • 它支持哪些模型?
  • • 它能不能替代 Claude Code 或 Codex?

还要继续追问:

  • • 这些能力是怎样注册到系统里的?
  • • 插件之间怎样声明和获得依赖?
  • • 插件被卸载后,它产生的事件监听、服务和其他副作用如何清理?
  • • 同一套组件为什么可以组合成不同形态的 Agent?

当你开始问这些问题,才算真正进入 Harness 的学习语境。


二、第一阶段:先跑起来,但不要停在“跑起来”

学习任何大型项目,第一步都不应该是从源码第一行开始读,而应该先获得整体感受。

按照当前官方文档,安装 Node.js 后,可以直接运行:

npx @deepseek-ai/dsh web

默认情况下,Web UI 会运行在:

http://127.0.0.1:3080

这一阶段的目标不是测试模型有多聪明,也不是让它完成一个多复杂的任务,而是观察系统暴露出来的结构。

你可以重点看四件事:

  1. 1. 一个 Agent 由哪些能力组成;
  2. 2. 切换不同 Profile 后,工具和行为发生了什么变化;
  3. 3. 一次任务如何从用户输入进入模型,再进入工具执行;
  4. 4. 会话、权限、工具调用和运行状态如何呈现在界面中。

官方提供的不同运行模式,可以理解为几份已经组装好的“Agent 配方”:标准模式偏向完整使用,PTC 模式强调程序化工具调用,极简模式只保留基础能力,创造模式则更适合观察和调整插件组合。

这里最值得建立的第一个认知是:

Profile 不是给同一个 Agent 换一套皮肤,而是在重新决定“这个 Agent 由什么组成”。

这一阶段学到什么算过关?

不是“成功打开了 3080 页面”,而是你能够回答:

为什么同一个 Harness 可以通过不同配置,表现成不同类型的 Agent?


三、第二阶段:补上 Cordis,理解“一切皆插件”为什么成立

直接进入 Harness 的 packages/ 目录,很容易看到大量模块,却不知道它们为什么以这种方式组织。

要解决这个问题,需要先认识 Cordis。

官方 README 对两者的关系写得很清楚:DeepSeek Harness 采用“一切皆插件”的架构,而这套架构由 Cordis 提供支撑;Cordis 的设计,则来自论文《A Programming Paradigm for Spatiotemporal Composability》。

你不一定要一开始就把整篇论文逐页推导完,但至少应该抓住两个概念。

1. 时间可组合性

一个插件被加载时,可能会注册服务、订阅事件、修改上下文,或者启动某些任务。

问题是:当插件被移除时,这些影响能不能一起撤销?

如果插件表面上卸载了,监听器却还在,状态仍然残留,系统运行得越久就越不可控。

所谓时间可组合性,关注的正是组件在不同时间被加入和移除时,其副作用能否被正确追踪和恢复。

2. 空间可组合性

插件很少真正孤立存在。

一个工具可能依赖权限系统,一个 Agent Loop 可能依赖模型和会话,一个 UI 又可能依赖运行状态与事件流。

这些依赖不是简单的静态导入。插件出现、消失或被替换时,其他组件需要感知环境变化,并重新满足自己的依赖。

空间可组合性关注的,就是多个组件同时存在时,依赖关系如何声明、解析并动态维持。

Cordis 可以看作论文思想的工程落点:它负责上下文、插件生命周期、依赖关系和副作用管理;Harness 则在这套机制上组装出 Agent 所需的各种能力。

论文应该怎么读?

不要把目标定为“读完 88 页”。更有效的方式是带着三个问题读:

  1. 1. 普通插件系统在动态卸载时会遇到什么问题?
  2. 2. 可逆副作用和响应式依赖分别解决了什么问题?
  3. 3. 这些抽象在 Cordis 与 Harness 的代码里分别对应什么?

先读摘要、引言、核心定义和 Cordis 实现部分,再回到代码中寻找对应关系。遇到不理解的形式化内容,可以先放下;等你写过插件后再回来看,很多概念会突然变得具体。

这一阶段学到什么算过关?

你能够用自己的话解释:

“一切皆插件”为什么不只是把代码拆成很多包,以及插件卸载为什么是一个需要专门设计的问题。


四、第三阶段:不要按目录顺序读源码,要按“一次任务”读

Monorepo 最容易制造一种错觉:好像必须把每个 package 都看完,才能理解项目。

实际上,更好的方法是选一条完整链路,从头跟到尾。

对于 Harness,这条链路就是一次 Turn。

可以沿着下面的顺序追踪:

用户发出消息
    ↓
创建一次 Turn
    ↓
读取会话与运行上下文
    ↓
组织模型请求
    ↓
模型返回文本或工具调用
    ↓
执行工具并写入结果
    ↓
进入下一个 Step,或结束本轮任务

这里要区分两个概念:

  • • Turn:围绕一次用户任务展开的完整处理过程;
  • • Step:Turn 内的一次模型请求及其相关工具执行。

一个 Turn 可能只包含一个 Step,也可能因为多次工具调用而包含多个 Step。

沿着这条链路,再有选择地阅读核心模块:

  • • core/session:会话事实怎样被追加、存储与恢复;
  • • core/agent:Agent 对外提供怎样的抽象;
  • • core/agent-loop:默认运行循环怎样推进 Turn 和 Step;
  • • llm/llm:消息怎样流向不同模型适配器;
  • • 工具与事件相关模块:调用怎样被注册、观察、拦截和记录。

这样读代码,你看到的不是一堆孤立文件,而是一次任务如何穿过整个系统。

一个特别重要的观察:事件有不同职责

阅读时要留意两类信息:

  • • 需要成为长期事实、重启后仍能恢复的信息;
  • • 只在当前运行过程中用于观察或干预的信息。

前者更接近会话日志,后者更接近飞行中的 Agent 事件。分清两者,才能理解 Harness 如何同时处理持久化、界面更新、运行控制与扩展能力。

这一阶段学到什么算过关?

你能从一次用户输入开始,画出它经过会话、Agent Loop、模型和工具系统的完整路径,并指出关键状态最终记录在哪里。


五、第四阶段:用 Profile 和 Bundle 学会“组装”,不要急着造轮子

理解运行链路之后,下一步不是马上开发复杂插件,而是先学会修改现有组合。

这是理解 Harness 最省力的一步。

Profile 是什么?

可以把 Profile 理解为一份命名的 Agent 组装方案。

它决定加载哪些插件、使用什么配置,以及最终向用户呈现出怎样的能力集合。

Bundle 是什么?

Bundle 更接近一组可以复用和分发的组合单元。它把相关插件与配置组织在一起,使一套能力能够被其他 Profile 或项目采用。

推荐的练习方式

不要一上来重写 Agent Loop。先做几个小实验:

  1. 1. 从一个现成 Profile 中移除某项能力;
  2. 2. 替换一个实现,观察其他模块是否仍能工作;
  3. 3. 通过配置叠加修改某个插件,而不改它的源码;
  4. 4. 比较两份 Profile 的插件树,解释它们行为不同的原因。

这个阶段会让你真正理解:Harness 的扩展性首先来自组合,其次才来自编写更多代码

这一阶段学到什么算过关?

你可以在不修改核心源码的情况下,组合出一个能力明显不同的 Agent,并且知道每项能力来自哪个插件。


六、第五阶段:写一个“小到不能再小”的插件

直到这里,才适合开始写第一个插件。

第一个插件不需要接数据库,不需要调用复杂 API,更不需要做一个完整产品。一个能够注册服务、监听事件,并在卸载时正确清理的 Hello World 插件,反而更适合验证理解。

这个练习应该覆盖三个动作:

  1. 1. 向共享上下文贡献一个能力;
  2. 2. 使用或监听系统中的某个事件;
  3. 3. 卸载插件,确认相关副作用一起消失。

第三步尤其重要。

很多教程只验证“插件加载后能不能工作”,但对于 Cordis 和 Harness 来说,“卸载后是否不留痕迹”同样是核心能力。

之后再逐步增加复杂度:

  • • 写一个实用工具插件;
  • • 为插件增加配置项;
  • • 把多个插件组织成 Bundle;
  • • 为某类任务制作专属 Profile;
  • • 最后再研究自定义 Agent Loop、远程执行环境或多 Agent 编排。

这一阶段学到什么算过关?

你的插件不仅能加载和工作,也能被安全卸载;你能解释它依赖什么、贡献什么,以及生命周期结束时清理了什么。


七、一条更合理的 DeepSeek Harness 学习路线

把前面的内容压缩一下,我推荐的顺序是:

体验 Web UI
    ↓
比较不同 Profile
    ↓
理解 Everything is a Plugin
    ↓
阅读论文的核心问题
    ↓
理解 Cordis 的生命周期与依赖机制
    ↓
沿一次 Turn 追踪核心源码
    ↓
修改 Profile 和 Bundle
    ↓
编写并卸载第一个插件
    ↓
开发自己的 Agent 组合

这条路线背后的原则很简单:

先看到系统,再理解抽象;先学会组合,再学习实现;先写小插件验证生命周期,再挑战复杂 Agent。


八、几条容易踩坑的错误路线

误区一:一上来就通读整个仓库

Harness 是一个规模不小、仍在快速变化的 Monorepo。没有问题意识地顺着目录读,很快就会迷失。

先选一条运行链路,再按需展开模块,效率更高。

误区二:只看 Prompt 和工具定义

Prompt、模型与工具很显眼,但它们不是 Harness 最独特的部分。

真正值得研究的是:能力如何进入上下文、依赖如何得到满足、状态如何被记录、插件如何安全退出。

误区三:把论文当作入门门槛

论文重要,但不意味着必须先完全读懂形式化推导,才有资格运行项目。

正确方式是“体验—论文—代码—再回论文”,让抽象概念和工程现象互相印证。

误区四:背当前 API,却忽略项目仍在快速迭代

官方目前将 DeepSeek Harness 标记为 Developer Preview,并明确提醒未来可能发生破坏兼容性的变化。

所以现阶段更值得沉淀的是稳定的思想:插件边界、生命周期、依赖、事件、会话与组合方式。具体命令、目录和配置字段,则应随时以当前官方文档为准。


结语:真正要学的,是 Agent 如何成为一个“可组合的系统”

如果只是想使用 DeepSeek Harness,跑起来、配置模型、选择一个合适的 Profile,可能已经足够。

但如果你想通过这个项目学习 Agent 工程,那么最值得追的并不是“它今天又多了什么工具”,而是这些更底层的问题:

  • • 一个复杂 Agent 应该如何拆分能力?
  • • 插件之间怎样形成依赖,却不彼此绑死?
  • • 运行时加入和移除组件,怎样避免残留副作用?
  • • 会话、事件、工具和 Agent Loop 怎样组合成可观察、可替换的系统?

DeepSeek Harness 给出的是一套仍在演进中的答案。

而学习它最好的方式,也不是把源码从头读到尾,而是沿着一条清晰路线,逐层验证自己的理解:

先会用,再看懂;先组合,再开发;最后回到设计哲学。

接下来,如果继续深入,可以分别拆开讲:论文中的“时空可组合性”、Harness 的一次完整 Turn、Profile 与 Bundle 的配置方式,以及一个插件从加载到卸载的全部生命周期。


参考资料

  • • DeepSeek Harness 官方仓库
  • • 《A Programming Paradigm for Spatiotemporal Composability》

注:本文依据 2026 年 8 月的 Developer Preview 版本整理。项目迭代较快,具体命令、目录结构与接口请以官方仓库最新说明为准。