本文面向第一次接触 DeepSeek Harness 的开发者,按“先建立整体模型,再进入实现细节”的顺序说明它的定位、架构、运行方式、适用场景与可能的发展方向。
内容以仓库当前公开实现为依据,版本背景为 0.1.2-alpha 系列开发预览版(核对时仓库 package.json 为 0.1.2-alpha.2,版本以仓库为准)。文中“当前实现”与“发展判断”会明确区分;社区讨论中的想法不等同于官方路线图。
目录
- 术语速查
- 它是什么
- 先建立一个整体模型
- 为什么说 Everything is a Plugin
- 启动、Profile 与 Bundle
- Agent Loop:模型如何完成一个任务
- Session Event Log:为什么它不是普通聊天记录
- 工具系统与安全控制
- Subagent、Workflow 与 Agent Teams
- 更多能力家族速览
- Web、SDK 与 API
- 它适合解决什么问题
- 它的优势与代价
- 发展方向:事实与判断
- 推荐阅读路径
- 快速上手与构建环境
- 常见误解
术语速查
第一次阅读时把它当作词典:遇到不认识的词回来查;每个词在正文中都有更完整的解释。
| 术语 | 一句话定义 |
|---|---|
| Harness | 围绕大模型构建可运行 Agent 的基础运行时,负责模型调用、上下文、工具、会话、权限与扩展的组合 |
| Plugin(插件) | 注册服务、监听事件、声明依赖的 Cordis 单元;Agent 的能力由一组插件共同组成 |
| Seam(能力缝) | 一个可替换能力的三段式结构:Service Definition(定义)+ Provider(实现)+ Consumer(接入 Agent) |
| Scope(作用域) | 注册的可见范围:贡献要么全局可见,要么只属于某个 Agent;子代理不继承父代理的作用域 |
| Profile | 一套命名的运行时组成,例如 web、headless、sdk、acp |
| Bundle | 一组可安装的 Cordis 配置行与代码,可作为基础包或 patch 层叠加到 Profile |
| Turn / Step / Round | step = 一次模型请求及其引发的工具执行;turn = 零个或多个 step;round = 外层策略的一次迭代(如目标轮) |
| Session Event Log | 会话的追加式事件日志,是运行时事实来源;模型上下文、UI、恢复、分叉、遥测都从它派生 |
| Projection(投影) | 从事件流派生的只读视图,例如模型消息历史、Web Transcript、持久化状态 |
| Compaction | 接近上下文上限时对旧历史做摘要压缩,并裁剪过大的工具输出 |
| Goal(目标) | 附着在会话上的持久化完成目标,带阶段与轮次上限,可驱动自动续跑 |
| Human Command | 以 / 开头的命令(如 /plan、/compact、/goal),由人触发、不经模型回合直接执行 |
1. 它是什么
DeepSeek Harness 是 DeepSeek AI 开源的通用 Agent Harness。这里的 Harness 可以理解为“围绕大模型构建可运行 Agent 的基础运行时”,它负责把模型调用、上下文、工具、会话、权限、子代理、工作流、Web UI 和 SDK 组合成一个可扩展系统。
它不是一个只提供聊天窗口的应用,也不是一个只封装 HTTP 请求的模型 SDK。它更接近一个“可配置的 Agent 操作系统”:模型是决策者,Harness 负责提供能力、保存状态、执行动作、承接扩展,并把运行过程投影到用户界面或外部协议。
项目的核心定位可以概括为三点:
- 以 Cordis 插件系统为运行时基础,所有主要能力都可以被装配、替换或裁剪。
- 以事件日志作为会话事实来源,使模型上下文、UI、恢复、分叉和遥测可以从同一条记录派生。
- 以工具和能力扩展为中心,把一个简单 Agent 逐步组合成多代理、工作流和可动态扩展的运行环境。
官方仓库仍将项目标注为开发预览版,接口和存储格式可能发生不兼容变化。项目的整体说明见 官方 README。
2. 先建立一个整体模型
从外部看,用户提交一个任务,模型思考并调用工具,最后返回结果。从内部看,DeepSeek Harness 会把这个过程拆成多个相互协作的层:
用户 / Web UI / TypeScript SDK / Python SDK / ACP
|
API 与连接层
|
Profile + Bundle + Cordis Context
|
Session | Agent Loop | System Prompt | Tool Runtime
|
LLM Provider | Shell | FS | Web | LSP | Sandbox | Subagent
|
JSONL / SQLite / 文件系统 / 外部进程
可以把它理解成四个方向的组合:
- 向上是交互入口:Web 页面、命令行、SDK 和自动化协议。
- 中间是 Agent 主干:会话、提示词、工具运行时和 Agent Loop。
- 向下是能力提供者:模型、文件系统、Shell、网页、LSP、沙箱和子代理。
- 横向是插件与事件:它们把能力注册到共享的 Cordis Context,并用事件连接运行时各部分。
仓库的架构总览、包分组、启动规则和 Agent Loop 语义集中写在 docs/architecture.md。如果只读一份源码文档,优先读它。
2.1 一次真实任务的时间线
用一个具体任务把上面的分层串起来。假设用户通过 Web UI 提交“帮我看看项目里哪个测试失败了”:
dsh web启动后,Web Profile 组合出包含 Agent Loop、工具、Session 持久化的运行时。- 用户输入进入会话 inbox,
turn/start打开一个 turn。 - Agent Loop 从 Session 事件派生模型历史,加上 System Prompt 与可见工具 Schema,向 LLM 发出请求。
- 模型返回流式文本(
assistant/chunk→assistant/message),UI 实时显示。 - 模型调用
bash工具运行测试:tools/pre-execute先做权限与审批检查,tools/execute执行,tool/result把输出写回事件流。 - 工具结果成为下一步请求的一部分,模型据此定位失败原因并给出结论;直到没有更多工具调用,
turn/end关闭。 - 每一条事实都以事件追加进 Session 日志;即使进程重启,也能从日志恢复并继续。
- 如果上下文接近上限,Compaction 会压缩早期历史;如果设置了目标,Goal 系统会在 turn 结束后继续推进自动工作(分别见 6.4 与 5.5)。
3. 为什么说 Everything is a Plugin
3.1 Cordis 提供什么
DeepSeek Harness 使用 Cordis 作为插件框架。一个 Cordis 插件可以注册服务、监听事件、声明依赖,并通过可撤销的 effect 管理生命周期。
这意味着 Agent 不是把所有逻辑硬编码在一个巨大的主类中,而是由一组插件共同组成。例如:
- LLM 插件提供模型调用能力。
- Session 插件提供会话和事件记录。
- System Prompt 插件负责拼装系统提示词。
- Tools 插件管理工具注册、参数校验、执行管线和结果。
- Agent Loop 插件驱动每一轮模型请求与工具调用。
- Shell、FS、Web、LSP 和 Sandbox 插件提供外部世界的操作能力。
- Subagent 和 Workflow 插件提供多代理协作与程序化编排。
插件之间不是通过大量全局变量互相引用,而是通过 Context 中的服务和事件通信。Cordis 的服务、依赖注入、事件模式和生命周期语义见 Cordis Primer。
3.2 Capability Seam:能力的三段式结构
一个完整能力通常由三类角色构成:
| 角色 | 责任 |
|---|---|
| Service Definition | 声明稳定的类型、方法和事件 |
| Service Provider | 提供具体实现,例如本地进程、远程服务或持久化后端 |
| Consumer | 把能力接入 Agent,例如注册模型、暴露工具或驱动 UI |
例如,Shell 能力可以拥有统一的 Service Definition,然后分别接入本地 Shell、PowerShell 或受控执行环境。Agent 只依赖能力定义,不需要把每一种底层实现写死在循环里。
3.3 这种设计解决了什么
它主要解决的是“同一个 Agent 主干,如何在不同环境中拥有不同能力”:
- Web Profile 可以挂载浏览器 UI 和远程连接。
- Headless Profile 可以只保留命令行任务所需能力。
- SDK Profile 可以把 Agent 暴露为 JSON-RPC 服务。
- 测试环境可以替换模型、存储和工具实现。
- 用户可以通过配置文件选择插件和覆盖配置,而不用修改 Agent Loop。
代价是理解成本更高。阅读一个功能时,通常要同时寻找定义、实现、消费者、配置行和事件,而不是只打开一个文件。
3.4 作用域(Scope):能力如何对每个 Agent 定制
插件组合解决“系统由哪些能力构成”,作用域解决“同一个能力对不同 Agent 呈现什么”。注册到共享 Context 的贡献——工具、提示词片段、变量、监听器——要么是全局的,要么属于某个 Agent 的作用域;约定是“一个存活中的 Agent 就是它自己作用域的 key”。
几个必须理解的行为:
- 子代理不继承父代理的作用域。父子关系只作为数据(lineage:父会话、委托深度)存在,不影响可见性。因此“给子代理一套不同的工具”不是继承裁剪,而是在创建时组合出来的。
- Setup Window 是创建子 Agent 时注入其专属世界的时机:作用域与 Agent 对象已存在,但 Agent 尚未发布、第一轮提示词尚未组装。Setup 负责注册,从不驱动 Agent。
- Shadowing(遮蔽) 是“同名覆盖”:作用域内注册的同名工具或提示词片段替换全局同名项,这正是 per-agent persona 和 per-agent 工具变体的机制。
- Restriction(限制):
tools.restrict按交集过滤全局工具集,被过滤掉的工具对模型既不可见也拒绝执行,与“不存在的工具”没有区别。
作用域语义的官方说明见 Scope 子系统 与 glossary。
4. 启动、Profile 与 Bundle
4.1 Profile 是一套运行时组成
DeepSeek Harness 不把“启动应用”理解为直接执行某个包的 bin,而是通过 dsh 启动一个命名 Profile。仓库当前的主要 Profile 包括:
- web:启动浏览器端 UI 和服务端连接。
- headless:执行一次性无界面任务。
- sdk:通过 JSON-RPC 暴露完整 SDK 运行时。
- sdk-minimal:提供更小的 SDK 组成树。
- acp:面向自动化的 Agent Client Protocol 服务。
这些 Profile 共享一部分基础插件,再按用途叠加不同能力。常见的公共层是 dsh-base;Web、Headless、SDK 和 ACP 在此基础上分别添加自己的入口和连接方式。
4.2 Bundle 是可分发的配置层
Bundle 是一组可安装的 Cordis 配置行和代码。它可以作为基础能力包,也可以作为 patch layer 叠加到某个 Profile 上。
配置合成大致遵循以下顺序:
Bundle 默认配置
↓
Profile 补丁
↓
用户目录补丁
↓
命令行 --patch
↓
最终 Cordis 配置
一个 patch 通常针对完整配置行,而不是隐式地修改某个深层字段。这种方式让“当前运行了哪些插件、每个插件使用什么配置”可以被检查和复现。
Profile 和启动约束的具体说明见 架构文档中的 Application Launch 与 Profiles,基础配置可以参考 dsh-base 的 Cordis patch。
4.3 为什么不鼓励直接运行包入口
项目把应用启动集中到 dsh,是为了让 Profile、配置层、生命周期、构建产物和运行环境保持一致。单独执行某个包的 bin,可能绕过这些组合规则,导致“源码能启动但正式 Profile 行为不同”的问题。
因此,理解 DeepSeek Harness 时应把 dsh 看成应用启动器,把各个 npm workspace 包看成可装配的运行时部件。
5. Agent Loop:模型如何完成一个任务
5.1 一次任务不是一次请求
Agent Loop 的核心不是“调用一次模型然后输出文本”,而是反复执行“读取上下文、请求模型、执行工具、记录结果、继续请求”的循环。
典型流程如下:
turn/start
→ 获取下一条用户输入和队列消息
→ agent/pre-step
→ step/start
→ 写入 user/message
→ 从 Session 派生模型历史
→ agent/request
→ LLM 流式响应
→ assistant/chunk*
→ assistant/message
→ tool/call*
→ tools/pre-execute
→ tools/execute
→ tools/post-execute
→ tool/result*
→ step/end
→ 继续下一步,或 agent/turn-stopping
→ turn/end
星号表示可能出现多次。模型没有工具调用时,一步可能直接结束;模型产生工具调用时,工具结果会被记录,并成为下一步模型请求的一部分。
Agent Loop 的实现位于 agent-loop 的 README 和 agent.ts。
5.2 Agent 的状态与控制
Agent Loop 需要处理的不只是正常成功路径,还包括:
- 用户在运行中追加消息。
- 用户 steer 当前任务,改变后续方向。
- 用户 follow-up,让 Agent 在当前任务结束后继续处理。
- 取消当前运行。
- 工具并行执行与互斥执行。
- 模型请求失败和重试。
- 等待 Agent 进入 idle 状态。
- 工具结果要求继续下一步,或要求结束当前 turn。
这也是它与简单的“while 循环调用模型”之间的主要差异:循环本身是一个带生命周期、事件和可恢复状态的运行时组件。
5.3 请求如何生成
在构造模型请求时,Agent Loop 会组合:
- 持久化的请求头信息。
- System Prompt 的当前内容。
- 从 Session 事件派生的消息历史。
- 当前 Agent 可见的工具及其 JSON Schema。
- 当前会话标识、取消信号和运行时上下文。
模型请求不是独立的临时变量,而是 Session 记录和当前插件状态的投影。这为恢复、审计、UI 展示和 Snapshot 测试提供了共同基础。
5.4 循环层级:turn、step 与 round
官方 glossary 用三个词定义循环的层级:
- Step:一次模型请求加上它引发的工具执行。
- Turn:零个或多个 step,从认领第一批输入开始,到模型与工具都不再欠工作为止。
- Round:外层策略的一次迭代,例如一个 goal round,或 Ralph 循环中的一轮新会话尝试。轮次计数属于外层策略,不等于 session 里每个 turn 都算一轮。
Ralph 循环值得单独解释:它是把同一个目标交给“全新会话的模型”反复执行的前台工作流;每轮子会话不携带父会话与上一轮会话的对话种子,跨轮状态通过共享 workspace 与一份有界的结构化交接报告传递。它不是 session 内的 goal,也不是调度器。
5.5 目标(Goal):持久化的长任务推进
“用户提交一个任务,模型做完就停”只是基础形态。Goal 机制让一个 session 拥有一个持久化的完成目标:目标带 active / paused / blocked / complete 阶段和轮次上限,模型工具可以创建和更新目标,/goal 命令让人不经过模型回合直接控制,自动续跑驱动会把 active 目标变成一轮轮自动工作。
三个容易误解的点:
- Goal 是状态,不是调度器,也不是独立会话。目标状态就住在 Session 事件日志里,不另设存储。
- 一次只有一个目标生效;无关的人工 turn 不消耗目标轮次上限。
- 续跑激活(armed)是进程内的,刻意不进入持久化回放:恢复或分叉后,必须先有人类授权的 resume 动作才能继续自动工作。这与第 7 章的安全主题一致——自动续跑默认不会在无人确认时自己恢复。
6. Session Event Log:为什么它不是普通聊天记录
6.1 Session 是事件流
Session 保存的是事件序列,而不是简单的 messages 数组。事件可能包括:
- turn 和 step 的生命周期。
- 用户消息、助手消息和流式文本块。
- 模型请求头与请求上下文。
- 工具调用、工具执行阶段和工具结果。
- 权限、计划、子代理、文件、Shell、遥测等能力事件。
事件流是运行时事实来源,其他视图都可以从它派生:
事件流
├─→ 模型消息历史
├─→ Web UI Transcript
├─→ 恢复与继续执行
├─→ 会话分叉
├─→ 工具审计与遥测
└─→ 测试 Snapshot
其中,模型真正看到的内容必须能够由 Session 事件重建。这个原则可以避免 UI 显示了一些模型无法看到的隐式状态,也避免恢复时缺少影响决策的输入。
6.2 原始流式块与派生消息
流式响应通常会先产生多个 assistant/chunk 事件,随后形成完整的 assistant/message。这样做有两个目的:
- UI 可以实时显示模型输出。
- 恢复和模型调用可以使用稳定的完整消息。
因此,事件流既服务于实时体验,也服务于事后重建。它不是为某一个消费者定制的日志格式。
6.3 持久化方式
项目提供 JSONL 和 SQLite 两种持久化方向。JSONL 适合透明的追加写入和调试;SQLite 适合结构化查询、压缩流式块和更稳定的本地存储。
持久化层会处理写入延迟、崩溃恢复和逻辑事件流重建。崩溃恢复的目标不是伪造一条完整成功记录,而是明确记录中断状态,让后续恢复能够识别未完成的 turn。
会话类型、事件词汇和持久化语义见 Session 源码 与 持久化子系统说明。
6.4 上下文压缩:长会话如何不溢出
模型上下文有上限,长会话不可能永远原样增长。Compaction 能力族解决这个问题,包含三个层次:
- 自动压缩:token 压力接近上限时,把较早的历史浓缩成摘要,随后的模型请求基于摘要继续。
- 按需压缩:通过
/compact命令手动触发。 - 工具输出裁剪:过大的工具结果先被压缩或裁掉(例如只保留结论),减少需要浓缩的内容。
另一条缓解路径是 Spill:当单个工具结果超过字节上限时,完整文本被保存为 artifact,模型只看到有界预览加一个可后续读取或搜索的定位符。
压缩不是删除:压缩结果仍然作为事件写回日志,恢复与审计依旧可以追溯。官方说明见 Compaction 子系统 与 Spill 子系统。
7. 工具系统与安全控制
7.1 Tool Runtime 的执行管线
工具系统不仅负责“注册一个函数”。一个工具通常包含名称、描述、参数 JSON Schema、执行逻辑、结果以及可选的 UI 展示信息。
执行过程可以被多个阶段拦截:
模型产生工具调用
↓
tools/pre-execute 权限、审批、策略
↓
tools/execute 实际执行与包装器
↓
tools/post-execute 收尾、指标、清理
↓
tool/result 写入结果并反馈给模型
Tool Runtime 还负责并发上限、执行包装器、错误处理、结果归一化和工具可见范围。源码见 packages/core/tools/src/index.ts。
7.2 工具可见性与渐进披露
工具不一定要在每次请求中全部暴露给模型。运行时可以限制当前 Agent 能看到的工具,或者使用 ToolSearch 一类机制,让模型先搜索工具再按需加载详细 Schema。
这能减少上下文开销,也能把大量能力以插件方式安装而不必一次性塞进每个模型请求。
7.3 安全模型的实际含义
工具可以访问文件、Shell、网络、进程和凭据,因此“能运行”不等于“安全”。官方 SAFETY.md 明确提醒:项目没有完成安全审计,不应被视为生产安全系统;模型生成的代码和命令、第三方插件以及宿主机访问都可能带来风险。
审批、沙箱和权限控制可以降低误操作概率,但不应被理解为绝对隔离。运行不受信任任务时,应使用最小权限、无敏感凭据的临时环境,并优先使用一次性虚拟机或容器。
这一点会长期影响项目发展:工具数量越多、插件越丰富、Agent 权限越高,插件供应链、能力隔离、审计、恢复和权限策略就越重要。
7.4 审批、凭据与沙箱的具体机制
仓库提供了与上一节原则对应的具体机制:
- 审批(Approval):一次请求对应一个一次性授权,
allowed-once只放行被询问的那一个动作;缺失、拒绝、取消或应答方不可用一律 fail-closed,不会开门。UI 通道提供人工应答,ACP 自动化桥为自身 Agent 提供机器决策。见 Approval 子系统。 - 凭据(Credentials):密钥按名字存储与引用,轮换时无需修改任何配置文件;配置文件与渲染结果里只出现名字,不出现明文。需要“问人要”的凭据走 authorization flow。见 凭据包组。
- 沙箱(Sandbox):进程执行通过
ctx.sandbox后端约束;除本地后端外还有实验性的 E2B 远程 Linux 沙箱,可以把文件、命令与终端整体搬进远端临时环境,宿主进程、模型调用与 Session 状态都不迁移。见 Sandbox 子系统 与 E2B 包组。
这些机制降低误操作概率,但正如上一节所说,它们不等于绝对隔离。
8. Subagent、Workflow 与 Agent Teams
8.1 Subagent
Subagent 允许一个 Agent 把工作交给另一个 Agent。子代理通常拥有独立的子 Session 和一次激活过程,父 Agent 通过工具或 Provider 管理子任务。
它适合以下任务:
- 把检索、实现、审查拆给不同角色。
- 并行处理多个互相独立的文件或问题。
- 让子 Agent 使用与父 Agent 不同的提示词、工具过滤器或模型。
- 把长任务拆成可继续的子会话。
重要的是,Subagent 不是简单的函数递归。它涉及子会话持久化、激活生命周期、深度限制、取消、父子关系和冷恢复。
8.2 Workflow
Workflow 更像程序化的 Agent 编排。它允许开发者用代码表达 agent、parallel、pipeline、phase 和 log 等结构,也可以实现 Ralph 风格的迭代循环(Ralph 的定义与 turn/step/round 层级见 5.4)。
可以用下面的方式区分二者:
| 机制 | 决策主体 | 更适合 |
|---|---|---|
| Agent Loop | 当前模型 | 动态决定下一步和工具 |
| Subagent | 父 Agent 与子 Agent | 委派、分工、隔离上下文 |
| Workflow | 开发者编写的流程 | 固定阶段、并行、流水线和重复执行 |
Workflow 可以改善可观测性和可复现性,但它本身不是安全边界。工作流中调用的工具仍然需要独立的权限和隔离策略。
8.3 Agent Teams
仓库还包含实验性的 Agent Teams 方向。它反映出项目正在探索多个 Agent 之间的协作、消息传递和角色分工,但实验目录中的能力不应视为稳定公共 API。
9. 更多能力家族速览
除核心循环外,仓库还按能力族组织了一批可选包,dsh 基础组合默认启用其中一部分,其余按需挂载。理解它们的方式与理解工具相同:先看 Service Definition 定义了什么,再看 Provider 怎么实现、Consumer 如何接入 Agent。
| 能力 | 一句话说明 | 官方文档 |
|---|---|---|
| Session Query | 对实时与持久会话做精确查询、关系 trace 与全文搜索;Web 端可通过 /export 导出会话 | session-query 子系统 |
| Jobs | 后台任务注册为 job,归属发起它的 Agent,完成以会话内消息通知,而不是阻塞轮询 | jobs 子系统 |
| Schedule | 会话内定时提醒:到点以普通消息回到同一会话;提醒跨重启存活,但没有邮件或推送 | schedule 子系统 |
| Webhook | 接收经过认证的外部事件,由受信任规则创建新的根 Session | webhook 子系统 |
| Terminal | 持久、归属 Agent 的 PTY 会话:cwd、环境变量、已激活环境跨工具调用存活(进程内,不跨重启) | terminal 子系统 |
| Code Runtime | 模型写一个程序调用宿主提供的函数,运行时在隔离的 worker 线程或 CPython 子进程执行,失败作为结果的一部分返回 | code-runtime 子系统 |
| Skills | 可复用的任务指令:Provider 贡献 → 注册表合并 → 会话目录 + skill 工具按需加载完整指令 | skills 子系统 |
| Guard | 循环卫生:检测模型重复调用同一工具并提醒改变策略;为声明了超时的工具调用设置时间上限 | guard 包组 |
| Hooks | 桥接已有 Claude Code / Codex 的 hooks.json,让旧配置在 Agent 运行的关键时刻照常触发 | hooks 包组 |
| MCP | 把外部 Model Context Protocol 服务器的工具作为原生工具接入;只桥接工具,不支持 resources/prompts,默认全关 | MCP 包组 |
9.1 Human Command:斜杠命令平面
/plan、/compact、/goal、/export 这类命令构成独立的交互层:human command 由人触发,通过 ctx.commands 由 UI 适配器解释执行,不经过模型回合,也不等于 shell 命令。命令输出属于 UI 状态,除非处理器另行写入持久化领域。理解这一层,Web UI 上的许多交互才不会与“模型工具”混淆。见 commands 子系统。
9.2 Plan Mode:先设计,后执行
/plan 进入计划模式:模式激活时,Agent 先探索和设计,把完整计划呈现给用户审批,批准后再执行。计划模式是引导而非限制——所有工具仍然可用,沙箱与审批等限制单独配置。见 plan 子系统。
10. Web、SDK 与 API
10.1 Web Profile
Web Profile 提供浏览器 UI、会话列表、设置、实时输出和工具交互。浏览器看到的内容主要来自 Session 事件和持久化结果,而不是直接读取 Agent 内部对象。
这种设计使 Web UI 成为 Agent 运行时的一个投影,而不是 Agent Loop 的唯一使用方式。未来可以用命令行、SDK、自动化协议或其他客户端连接同一类运行时。
10.2 TypeScript 与 Python SDK
SDK 通过 JSON-RPC 和 NDJSON 通信。TypeScript Client 与 Python SDK 都可以启动对应版本的 dsh SDK Profile,然后通过标准输入输出交换请求和事件。
这种方式的优点是客户端不必复制 Agent Loop,也不必直接依赖内部 TypeScript 类。客户端只依赖协议和生成的类型投影,从而保持运行时实现与调用方解耦。
10.3 Typert 与远程连接
远程 API 使用 Typert 相关的类型图和 RPC 网关,把 TypeScript 类型、服务方法和连接层组合起来。它的目标不是单独提供一个 REST CRUD 后端,而是把插件化服务投影到远程客户端。
这也解释了项目为什么同时维护 Host 和 Client 两个编译面:Host 运行插件和 Agent,Client 负责浏览器或 SDK 侧的类型与交互。
11. 它适合解决什么问题
11.1 个人开发助手
在受控环境中,它可以执行代码、搜索文件、运行测试、调用 LSP、访问网页,并把每一步保存在可恢复的 Session 中。
11.2 Agent 产品原型
如果要快速验证一个“模型 + 工具 + 会话 + UI”的产品,插件和 Profile 机制可以减少从零搭建运行时的工作。
11.3 多代理和自动化
Subagent、Workflow 和 ACP 使它能够承载代码审查、资料整理、任务分解、定时工作和长流程自动化。
11.4 Harness 研究
它特别适合研究 Agent 的基础设施问题,例如:
- 如何记录和恢复模型上下文。
- 如何限制模型可见工具。
- 如何让模型在运行时发现新能力。
- 如何协调多个 Agent。
- 如何把 Agent 投影到不同客户端。
- 如何测试一个包含模型、工具和持久化的完整循环。
12. 它的优势与代价
优势
- 插件化程度高,模型、工具、存储、UI 和协议可以独立组合。
- 事件日志让实时输出、恢复、分叉、审计和测试共享同一事实来源。
- Profile 与 Bundle 支持按场景裁剪运行时。
- 工具管线提供审批、并发、重试、指标和结果处理等扩展点。
- Subagent、Workflow 和 SDK 让它不仅能做聊天,也能承载复杂任务系统。
- 直接围绕 DeepSeek 模型和工具使用场景设计,适合研究和快速迭代。
代价
- 学习曲线明显高于单一 Agent 示例项目。
- 一个功能可能分布在 Service Definition、Provider、Consumer、配置行、事件和测试中。
- 插件组合越自由,配置错误和版本不匹配的可能性越高。
- 事件持久化、恢复和多代理生命周期带来了较高实现复杂度。
- 访问宿主机能力的工具需要真实的安全工程,不能只依赖 UI 审批。
- 项目仍处于早期预览阶段,升级时需要接受 API、配置和存储格式变化。
一句话评价:DeepSeek Harness 的重点不是“让模型回答得更像人”,而是“把模型变成可以被配置、观察、恢复和扩展的任务执行运行时”。
13. 发展方向:事实与判断
13.1 当前实现已经显示出的方向
从当前仓库的模块组织和公开文档,可以确认以下方向已经进入实现范围:
- 能力插件化:模型、工具、Shell、FS、Web、LSP、Sandbox、Skills 和 Subagent 都有独立能力分组。
- 长生命周期任务:Session 持久化、恢复、分叉、标题、遥测和子会话已经成为核心能力。
- 多代理编排:Subagent、Workflow 和实验性的 Agent Teams 共同覆盖委派与协作。
- 多客户端投影:Web、Headless、TypeScript SDK、Python SDK 和 ACP 使用不同入口连接相同的 Agent 思路。
- 运行时扩展:扩展模块允许模型检查 Cordis 服务、动态定义和运行临时插件包。
运行时扩展的约束尤其值得注意:动态定义的包是进程内版本,重启后不会自动保留,也不会替模型写入仓库文件或 Cordis 配置。可参考 extensions README 和 tool-cordis README。
13.2 可以合理推断的后续重点
下面是基于现有实现的工程判断,不是官方承诺的路线图:
- 稳定的插件协议:随着插件数量增加,Service Definition、配置、事件和版本兼容会比单个 Agent 功能更重要。
- 更强的安全隔离:本地 Shell、文件、网络、凭据和第三方插件需要更清晰的权限模型、审计和沙箱边界。
- 更成熟的长任务恢复:需要处理挂起、重试、部分完成、子代理恢复和跨进程运行。
- 更系统的评测:Agent Loop 的质量不能只用最终答案评价,还需要评估工具选择、上下文重建、恢复结果、权限行为和成本。
- 更好的开发者体验:插件模板、配置诊断、运行时检查、可视化事件流和稳定的文档会直接决定生态能否扩展。
- 更强的模型无关性:虽然项目由 DeepSeek 驱动,但能力接口若保持清晰,未来可以容纳更多模型提供者和不同推理策略。
社区已经出现关于 Harness 自我学习、反思机制和可评估 Plugin Packs 的讨论,例如 Harness Intelligence 提案 与 任务条件化 Harness 演化提案。这些内容代表社区探索,不应当当作官方路线图。
官方早期讨论也明确把项目定位为快速演进中的预览版本,可参考 v0.1 讨论 和 CONTRIBUTING.md。
14. 推荐阅读路径
建议按下面顺序阅读,避免一开始就陷入大量包源码:
- 先看 官方 README,了解项目启动方式和预览版定位。
- 再看 架构总览,建立 Profile、Bundle、核心包和事件流的地图。
- 用 Cordis Primer 补齐插件、服务、事件和 effect 的概念。
- 读 Scope 子系统,理解“能力如何对每个 Agent 定制”。
- 阅读 Agent Loop 实现,重点跟踪 turn、step、request 和工具调用。
- 阅读 Session 实现,理解事件如何变成模型消息和可恢复会话。
- 阅读 持久化说明,理解 JSONL、SQLite 和崩溃恢复。
- 阅读 Tool Runtime 实现,理解工具注册、Schema、执行阶段和结果。
- 读 Compaction 子系统 与 Goal 子系统,理解长会话如何不溢出、长任务如何被持久化推进。
- 读 Commands 子系统,理解斜杠命令平面与模型工具的区别。
- 最后阅读 扩展 Cookbook,把抽象能力对应到实际扩展方式。
带着三个问题阅读源码会更有效:
- 这个能力由哪个 Service Definition 定义?
- 哪个 Provider 负责实现它,哪个 Consumer 把它接入 Agent?
- 它对模型可见的状态是否通过 Session 事件记录?
15. 快速上手与构建环境
15.1 最小的源码构建路径
仓库根目录的常用命令包括:
pnpm install
pnpm run build
pnpm run test
pnpm run typecheck
pnpm run lint
从源码构建后,直接运行:
pnpm dsh web
pnpm run build 准备仓库产物,pnpm dsh web 直接使用这些产物而不重新构建。如果只想快速体验,也可以不克隆仓库:
npx @deepseek-ai/dsh web
默认在 http://127.0.0.1:3080 启动 Web UI 并打开浏览器;SSH 启动只打印宿主机 URL,因为本地端口转发由 SSH 客户端或编辑器负责。其他 Profile(headless、sdk、acp)的用法见官方 README 或 dsh --help。
实际使用时,优先通过 dsh Profile 启动应用,而不是绕过 Profile 直接运行内部包。
15.2 Node 版本提醒
项目要求 Node.js 版本为 ^22.19.0 || >=24.0.0。如果当前是 Node.js 22.16.0,pnpm 会给出 Unsupported engine 警告;这不代表电脑必须安装 nvm,而是说明当前 Node 版本低于项目声明的最低 22.x 版本。
nvm 只是切换 Node 版本的一种工具,不是项目的必需依赖。可以使用 Homebrew、fnm、asdf 或其他方式安装满足要求的 Node.js;关键是让终端中的 node --version 达到 22.19.0 及以上,或使用 24.x 版本。
15.3 共享和引用说明
本文中的仓库文件引用均指向 GitHub 上的 deepseek-ai/deepseek-harness,便于在 GitHub、Markdown 阅读器或聊天工具中直接打开。由于项目仍在快速迭代,指向 master 的链接可能随仓库更新;需要固定阅读版本时,可将链接中的 master 替换为对应 tag 或 commit。
16. 常见误解
- 插件不等于工具。插件是组成系统的运行时单元(注册服务、监听事件、声明依赖);工具只是插件暴露给模型的一种能力形态。
- 事件日志不是聊天记录。它是追加式事实来源,聊天记录只是它的一个投影(见第 6 章)。
- Profile 不是配置文件。它是一套命名的运行时组成,配置只是其中一部分。
- 作用域不是继承。子代理不继承父代理的作用域,父子关系只是数据(见 3.4)。
- Goal 不是调度器。目标是状态,自动续跑是刻意挂载的消费方,且恢复后需要人类授权(见 5.5)。
- Compaction 不是删除。压缩结果仍作为事件写回日志,可追溯(见 6.4)。
- Plan Mode 是引导不是限制。它不收紧工具权限,沙箱与审批单独配置(见 9.2)。
- MCP 只桥接工具。外部服务器的 resources 与 prompts 不支持(见第 9 章)。
- “能运行”不等于“安全”。审批、沙箱、凭据管理降低误操作概率,但不是绝对隔离(见 7.3)。
总结
DeepSeek Harness 的核心价值可以归纳为一条链:
Cordis 插件组合
→ Agent Loop 驱动
→ 工具与外部能力执行
→ Session 事件持久化
→ Web / SDK / ACP 多端投影
→ Subagent / Workflow / 动态扩展
如果把普通 LLM 应用看成“模型加几个函数”,DeepSeek Harness 则是在研究“如何把模型、函数、状态、权限、生命周期和多客户端组织成一个可长期运行的系统”。它当前更适合开发者、研究者和需要深度定制 Agent 的团队;在用于生产环境之前,应先完成版本固定、安全隔离、权限审计、故障恢复和针对真实任务的评测。
DeepSeek Harness 深入解读
https://java.li/archives/DeepSeek-harness
评论