DeepSeek Harness(简称 dsh)是 DeepSeek AI 于 2026 年 7 月底随 DeepSeek-V4-Flash 模型一同开源的智能体框架(Agent Harness)。它并非又一个聊天前端,而是一套面向「Agent = Model + Harness」这一等式的工程基础设施——把模型能力转化为可信赖、可扩展、可定制的智能体行为所需的全部运行时支撑。其最显著的设计特征是「一切皆插件」(everything is a plugin):会话日志、系统提示词组装、工具注册表、Agent 循环本身,无一例外都是可替换的插件,没有不可触碰的特权内核。
dsh 底层基于 Cordis 框架(一个源自 Koishi 社区的插件化应用框架,其设计理念在论文《A Programming Paradigm for Spatiotemporal Composability》中有系统阐述)。Cordis 提供了服务注册、类型化事件、可逆副作用三大原语,dsh 在此之上构建了会话(session)、工具(tools)、LLM 适配(llm)、Agent 循环(agent-loop)等核心子系统。整个项目采用 pnpm monorepo 组织,包含 50+ 个工作区包,覆盖从本地终端到 Web UI、从沙箱执行到 MCP 协议的完整能力栈。
本文从第一性原理出发,系统梳理 deepseek-harness 产生的技术背景、它所要解决的核心问题、以及它所采用的解法。在此基础上,本文进一步剖析 dsh 的代码结构、核心架构、关键概念与端到端流程,并给出一份面向初学者的文档导览。本文的目标读者包括:希望理解现代 Agent 框架设计原理的应用开发者、需要定制 Agent 行为的工程师、以及希望参与 dsh 生态贡献的开源开发者。阅读本文无需预先具备 Cordis 经验,但需要对 TypeScript 和异步编程有初步了解。

第一章 第一性原理:为什么需要 deepseek-harness

1.1 Agent = Model + Harness:一个等式的诞生

要理解 deepseek-harness 的存在价值,必须先理解 2025 至 2026 年间 Agent 领域形成的一个核心共识:一个可用的智能体(Agent)等于模型(Model)加上框架(Harness)。

  • 模型提供的是「原始智能」——理解指令、生成文本、调用函数的能力;
  • 而框架提供的是「工程支撑」——把模型的原始能力包装成可信赖、可观测、可控制的行为所需的全部基础设施。

这个等式的提出,标志着 Agent 工程从「调 API 拼字符串」的蛮荒时代,走向了系统化的工程范式。

  • 在等式的左侧,模型能力在快速迭代。从 2025 年的 DeepSeek-V3、R1,到 2026 年的 V4-Flash、V4-Pro,模型在推理、编码、工具调用上的能力每几个月就有显著提升。
  • 但在等式的右侧,框架层却长期处于碎片化状态:OpenAI 的 Codex、Anthropic 的 Claude Code、各类开源 Agent 框架,各自为政,能力参差不齐,且大多与特定模型深度绑定。
  • 这种不对称意味着,即便模型能力已经足够强,如果没有一个好的框架来承载,Agent 的实际表现也会大打折扣。

DeepSeek 作为模型提供方,深刻体会到了这种不对称带来的痛点。用户反馈「DeepSeek 模型很强,但用起来不如 Claude Code 顺手」时,问题往往不在模型,而在框架。与其让每个用户自己去拼凑框架,不如提供一个开源的、模型无关的、工程成熟的 Agent 框架,让 DeepSeek 模型的能力得到充分释放。这就是 deepseek-harness 诞生的直接动机——补齐「Agent = Model + Harness」等式中框架这一侧的空白。


1.2 现有 Agent 框架的三大痛点

在 dsh 出现之前,市面上的 Agent 框架(无论是闭源的 Claude Code、Codex,还是开源的各类 Agent 工具)普遍存在三个结构性痛点。理解这些痛点,才能理解 dsh 的设计为何如此强调「一切皆插件」。


痛点一:内核不可替换,扩展靠 fork

  • 传统 Agent 框架通常有一个「特权内核」——核心的 Agent 循环、会话管理、工具调度逻辑被硬编码在框架内部,用户无法替换。当用户想要修改某个核心行为(比如改变会话历史的压缩策略、自定义工具的执行流水线、替换 Agent 循环的调度逻辑)时,唯一的选择是 fork 整个框架,修改源码,然后维护一个私有分支。这种做法的代价极高:上游每次更新都需要手动 merge,私有修改容易与官方演进冲突,长期维护成本巨大。
  • 更深层的问题是,fork 式扩展破坏了生态的可组合性。A 团队 fork 出一个版本加了沙箱能力,B 团队 fork 出另一个版本加了 MCP 支持,两个版本无法同时使用。社区的力量被分散到无数 fork 中,无法形成合力。这正是 dsh 要彻底解决的问题——通过「一切皆插件」,让任何核心行为都可以通过挂载一个插件来替换或增强,无需 fork。

痛点二:能力耦合,无法独立演进

  • 在传统框架中,LLM 调用、工具执行、文件系统访问、沙箱隔离等能力往往被揉在一起,共享同一套代码和配置。这意味着,如果你想替换 LLM 后端(比如从 DeepSeek 切到 OpenAI),可能不得不连带修改工具执行逻辑;如果你想更换沙箱实现(从本地进程切到 E2B 云沙箱),可能要改动文件系统访问代码。能力之间的耦合,使得每一项能力的独立演进都变得困难。
  • 这种耦合还带来了测试和复用的问题。耦合的代码难以单独测试,也难以被其他项目复用。一个团队开发了优秀的沙箱实现,却因为与特定框架耦合,无法被其他框架的用户使用。dsh 通过「能力接缝」(capability seam)设计来解决这个问题——每项能力被拆分为服务定义(Service Definition)、服务提供者(Service Provider)、消费者(Consumer)三个角色,三者通过 ctx 上的稳定键解耦,可以独立替换和演进。

痛点三:状态不持久,崩溃即丢失

  • Agent 任务往往是长周期的——一个编码任务可能运行数十分钟甚至数小时,期间 Agent 会执行大量工具调用、读写文件、与用户多轮交互。如果框架的状态管理是内存式的(即所有会话状态只存在于运行进程中),那么一旦进程崩溃或重启,所有进度都会丢失。这对生产环境是不可接受的。
  • 传统框架的持久化往往是事后补丁——在内存模型之上加一层序列化/反序列化逻辑,把内存对象转成 JSON 存盘。这种做法的问题在于,内存模型和持久化模型容易不一致,且难以支持细粒度的崩溃恢复(比如恢复到第 17 步工具调用之前的状态)。dsh 从一开始就采用「事件溯源」(event sourcing)架构——会话状态是一个只追加的事件日志(append-only log),所有状态都从事件重放派生,持久化就是存事件日志本身。这种设计天然支持崩溃恢复、时间旅行调试、会话分叉等高级能力。

1.3 Cordis:插件化范式的基石

dsh 选择 Cordis 作为底层框架,并非偶然。Cordis 是一个成熟的插件化应用框架,其设计理念在论文《A Programming Paradigm for Spatiotemporal Composability》中有系统阐述。Cordis 的核心思想可以概括为五个理念,这五个理念构成了 dsh「一切皆插件」的技术基础。

  • 第一个理念是「插件即服务」。一个插件是一个实现了 Service 接口的对象,它可以是带有可选 inject 和 apply(ctx) 字段的函数,也可以是 Service 的子类。Cordis 负责把插件的生命周期挂载到当前上下文中。
  • 第二个理念是「上下文即服务仓库」。一个上下文(context)是服务的仓库,服务通过声明稳定的 ctx 键(如 ctx.tools、ctx.llm、ctx.sessions)来注册自己,其他插件通过键而非导入具体实现来查找服务。
  • 第三个理念是「通过 inject 声明服务依赖」。一个插件如果声明了所需的服务,会等待这些服务就绪后才激活,因此加载顺序通过服务需求来表达,而非手动编排启动序列。
  • 第四个理念是「类型化事件通信」。服务通过 TypeScript 声明合并来声明事件名,然后根据监听者是观察、包装、扇出还是顺序执行,分别用 emit、waterfall、parallel、serial 来派发。
  • 第五个理念是「可逆副作用」。每次注册都应该有对应的清理函数(disposer),插件卸载时所有注册自动回滚,保证系统状态的一致性。

这五个理念合在一起,提供了一种强大的组合范式:插件之间通过服务键和事件解耦,加载顺序自动解析,副作用可逆。这意味着,你可以随时挂载或卸载一个插件,系统会自动调整,不会留下残留状态。这正是 dsh 能够实现「一切皆插件」的根本原因——Cordis 提供了让插件安全组合、安全替换的形式化保证。


1.4 dsh 的定位:开源、模型无关、工程成熟

基于上述背景,dsh 确立了自己的定位:一个开源的、模型无关的、工程成熟的 Agent 框架。开源意味着社区可以自由使用、修改、贡献,不会被单一厂商锁定。模型无关意味着 dsh 不绑定 DeepSeek 模型,通过 LLM 适配层可以对接任何兼容 OpenAI/Anthropic 协议的模型。工程成熟意味着 dsh 从第一天就考虑了持久化、崩溃恢复、并发控制、可观测性等生产级需求,而非事后补丁。
dsh 的发布时机也值得注意。2026 年中,Agent 领域正处于从「玩具」走向「工具」的关键转折点——用户不再满足于能聊天的 demo,而是要求 Agent 能真正完成编码、数据分析、自动化等复杂任务。这种需求对框架的工程成熟度提出了极高要求。dsh 的出现,正是对这一需求的回应。它不是最早的开源 Agent 框架,但它是少数从第一性原理出发、用系统化思维设计的框架之一。

第二章 deepseek-harness 要解决什么问题


2.1 核心问题清单

综合 dsh 的架构文档与设计笔记,我们可以把它要解决的问题归纳为以下七个层面。这些问题并非孤立,而是层层递进——前一个问题是后一个问题的前提,解决全部问题才能构成一个可用的 Agent 框架。


问题一:如何让一切皆可替换

  • 这是 dsh 最根本的设计目标。会话日志、系统提示词、工具注册表、Agent 循环、LLM 适配器——这些在传统框架中是「内核」的部分,在 dsh 中都必须是可替换的插件。这意味着不能有任何硬编码的特权组件,所有能力都必须通过统一的服务注册机制暴露。这个问题不解决,「一切皆插件」就是空谈。

问题二:如何让插件安全组合

  • 插件化最大的风险是组合爆炸——当几十个插件同时运行时,它们之间的交互可能产生意料之外的副作用。dsh 需要一套机制,保证插件挂载和卸载时系统状态的一致性,保证插件之间的依赖关系自动解析,保证事件的派发有序且可追溯。Cordis 的可逆副作用和类型化事件机制是解决这个问题的核心。

问题三:如何让会话状态可持久化、可恢复

  • Agent 任务的长周期性要求会话状态必须持久化,且支持崩溃后恢复到精确的状态点。dsh 需要一种状态模型,既能高效支持实时交互(低延迟读写),又能完整持久化(崩溃不丢数据),还能支持高级操作(分叉、回放、时间旅行)。事件溯源架构是 dsh 对这个问题的回答。

问题四:如何让工具执行安全可控

  • Agent 调用的工具(文件读写、命令执行、代码运行)往往涉及敏感操作,必须有完善的安全控制。dsh 需要支持权限审批、沙箱隔离、文件系统守卫、结果改写等多种安全策略,且这些策略本身也要是可插拔的。工具执行流水线(tool execution pipeline)是 dsh 对这个问题的回答。

问题五:如何让 LLM 适配解耦

  • 不同 LLM 提供商(DeepSeek、OpenAI、Anthropic)的 API 协议、流式格式、工具调用规范各不相同。dsh 需要一个抽象层,让上层 Agent 逻辑无需关心底层用的是哪个模型,同时又能充分利用每个模型的特有能力(如 DeepSeek 的前缀缓存、Anthropic 的 prompt caching)。LLM 能力接缝(llm seam)是 dsh 对这个问题的回答。

问题六:如何让 Agent 行为可编排

  • 不同的应用场景需要不同的 Agent 行为模式——单轮问答、多轮对话、子 Agent 委派、目标驱动的长任务。dsh 需要提供一套编排原语,让这些模式可以通过组合插件来实现,而非硬编码。Agent 循环(agent-loop)、子 Agent(subagent)、工作流(workflow)、目标(goal)等模块共同构成了 dsh 的编排能力。

问题七:如何让框架可观测、可调试

  • Agent 行为的复杂性使得调试极其困难——一个任务可能涉及数十次模型调用、上百次工具执行,任何一环出错都可能导致整体失败。dsh 需要提供完善的日志、追踪、指标、会话回放能力,让开发者能够精确理解 Agent「为什么这么做」。事件日志、运行时诊断(runtime-diagnostics)、会话查询(session-query)等模块服务于这个目标。

2.2 设计目标

基于上述问题,dsh 确立了五个核心设计目标。

  • 第一是「一切皆插件」:没有任何特权内核,所有能力都通过 Cordis 的服务注册机制暴露,可替换
  • 第二是「能力接缝化」:每项能力拆分为服务定义、提供者、消费者三角色,通过 ctx 键解耦,独立演进。
  • 第三是「事件溯源」:会话状态是只追加的事件日志,持久化即存日志,支持崩溃恢复和回放。
  • 第四是「组合优于配置」:通过 Profile 和 Bundle 机制,让用户以声明式方式组合插件,而非编写胶水代码。
  • 第五是「工程成熟」:从第一天就考虑持久化、并发、可观测性,面向生产环境。

这五个目标之间是相互支撑的。例如,「一切皆插件」需要「能力接缝化」来保证插件之间的解耦;「事件溯源」需要「一切皆插件」来保证事件类型可扩展(通过声明合并添加新事件类型);「组合优于配置」需要「一切皆插件」来保证任何组合都是合法的。理解这五个目标的内在联系,是理解 dsh 架构决策的关键。

第三章 dsh 怎么解决:核心机制详解


3.1 一切皆插件:Cordis 的服务注册模型

dsh 的「一切皆插件」并非口号,而是通过 Cordis 的服务注册模型严格实现的。在 dsh 中,没有一个组件是「特殊的」——会话管理是 ctx.sessions 服务,工具注册是 ctx.tools 服务,LLM 调用是 ctx.llm 服务,Agent 循环是 ctx.agentLoop 服务。每个服务都由某个插件提供,任何插件都可以替换某个服务的实现。
这种模型的关键在于「服务定义」与「服务实现」的分离。

  • 服务定义是一个抽象的 Service 类(或带 ctx 键的接口),它声明了服务的 API 契约和事件词汇,但不包含具体实现。
  • 服务实现是具体的插件,它继承或实现了服务定义,提供具体逻辑。消费者是使用服务的插件,它通过 inject 声明依赖,通过 ctx.键 调用服务方法。

这三者的分离,使得任何一端都可以独立变化——换实现不影响消费者,换消费者不影响实现。
以 Shell 能力为例:dsh-shell 包定义了 ShellExecutor 服务(服务定义),dsh-bash-local 和 dsh-bash-sandbox 分别提供本地执行和沙箱执行两种实现(服务提供者),dsh-tool-bash 作为工具消费 Shell 能力(消费者)。如果你想新增一种 Shell 实现(比如远程 SSH 执行),只需写一个新的提供者插件,无需改动 dsh-tool-bash。这种解耦是 dsh 扩展性的根基。


3.2 能力接缝:Service Definition / Provider / Consumer 三角色

「能力接缝」(capability seam)是 dsh 架构中最核心的概念之一。一个接缝是一项可替换能力的完整描述,由三个角色组成:服务定义(拥有 ctx 键和类型词汇的 Service 类)、一个或多个服务提供者(具体实现)、一个或多个消费者(注入并使用服务的插件)。接缝是完整的能力,而非单一角色。
dsh 内置了大量能力接缝,覆盖 Agent 运行的方方面面。

  • ctx.llm 是 LLM 适配接缝,由 dsh-llm 定义,dsh-llm-deepseek 等提供具体实现,agent-loop 消费。
  • ctx.tools 是工具注册与执行接缝,由 dsh-tools 定义,各种 dsh-tool-* 插件提供具体工具,agent-loop 消费。
  • ctx.sessions 是会话存储接缝,由 dsh-session 定义,dsh-session-persistence 提供持久化实现。
  • ctx.fs 是文件系统接缝,ctx.sandbox 是沙箱接缝,ctx.approval 是审批接缝,ctx.skills 是技能接缝——每一个都是独立可替换的能力。

这种接缝化设计带来了极大的灵活性。你可以为同一个接缝挂载多个提供者(比如同时启用本地 Shell 和沙箱 Shell,根据工具的敏感度选择),也可以在运行时热替换提供者(比如调试时用本地文件系统,生产时用沙箱文件系统)。更重要的是,接缝化让能力可以「按需付费」——你只需要挂载你用到的能力的提供者,未用到的能力不会占用资源。


3.3 事件溯源:会话即只追加日志

dsh 的会话模型采用了事件溯源(event sourcing)架构。一个会话(Session)是一个只追加的事件日志(append-only log),记录了 Agent 交互的全部历史。LLM 的消息历史不是单独存储的,而是从事件日志派生(derive)出来的——重放就是从同一批事件重新派生。这种设计使得持久化变得简单(存日志即可),且天然支持崩溃恢复、时间旅行、会话分叉等高级能力。
会话事件词汇(SessionEventMap)是可扩展的。

  • 核心事件包括 turn/start、turn/end(一轮对话的边界)、step/start、step/end(一次模型调用加工具执行的边界)、user/message(用户消息)、assistant/chunk(流式 token 块)、assistant/message(组装后的助手消息)、tool/call、tool/result(工具调用与结果)等。
  • 插件可以通过 TypeScript 声明合并添加新的事件类型——例如压缩模块添加 compaction/start、compaction/summary、compaction/end 事件,hook 协议模块添加 hook/invoked、hook/result 事件。

事件溯源的一个关键优势是「可重放性」。因为所有状态都从事件派生,你可以把一个会话的事件日志导出,在另一个环境中重放,精确复现 Agent 的行为。这对调试极其有价值——当 Agent 在生产环境出现异常时,你可以把事件日志拉到本地,逐步重放,定位问题。此外,事件溯源还支持「会话分叉」——从某个事件点分叉出一个新会话,探索不同的行为路径,而原始会话不受影响。


3.4 工具执行流水线:pre-execute / execute / post-execute


工具执行是 Agent 框架中最需要安全控制的环节。dsh 设计了一条分阶段的工具执行流水线,把策略、钩子、沙箱、文件守卫、结果改写、结果观察、UI 渲染等关注点串联起来,而不改变 Agent 循环本身的结构。这条流水线由三个 waterfall 事件组成:tools/pre-execute、tools/execute、tools/post-execute。

  • tools/pre-execute waterfall 最先运行,承载钩子、权限、沙箱策略。
    • 它之后是注册的单调守卫(monotonic guards),这些守卫可以否决或弃权,但身份受保护(不能被其他插件冒充)。如果守卫否决,或审批拒绝,工具体被跳过。
    • ctx.approval 提供一次性审批提示,缺席或无法回答时拒绝。
  • tools/execute waterfall 包裹实际派发,承载超时、重试、指标采集。注册的工具 execute() 函数体在这里运行。
  • tools/post-execute waterfall 最后运行,可以接受、阻止、替换或添加上下文。

这种分阶段设计的好处是,不同的关注点可以独立挂载,互不干扰。安全团队可以挂载一个 pre-execute 钩子做权限检查,性能团队可以挂载一个 execute 包装做指标采集,产品团队可以挂载一个 post-execute 钩子做结果美化——三者各自独立,通过 waterfall 串联。文件系统的写前检查(read-before-edit)则在 tool-fs 内部的 fs/* 事件上完成,不占用通用流水线。这种分层设计让工具执行既安全又灵活。

3.5 Profile 与 Bundle:声明式组合

dsh 的「一切皆插件」带来了一个自然的问题:用户如何选择和组合插件?答案是 Profile 和 Bundle 机制。
一个运行中的 dsh 实例是一棵插件树,在启动时从有序的层(layers)组合而来。Profile 是存储在 Harness home 中的命名组合,它列出了要堆叠的 Bundle,持有任何树外插件,并保存用户自己的 cordis.patch.yml。web 和 headless 是随 dsh 发布的两个模板 Profile。
Bundle 是 Cordis 配置行及其所挂载代码的分发格式——它插入的任何内容都保持可被上层 patch。这意味着,用户可以通过 cordis.patch.yml 覆盖 Bundle 中的任何配置,而无需修改 Bundle 本身。这种「层叠 + 补丁」的组合方式,让用户可以在不 fork 任何代码的前提下,深度定制 Agent 行为。例如,用户可以启用官方的 web Bundle,然后通过 patch 把默认 LLM 从 DeepSeek 换成 OpenAI,把默认沙箱从本地换成 E2B,而所有这些定制都集中在一个 patch 文件中,可追踪、可版本管理。
Profile 和 Bundle 机制是 dsh「组合优于配置」理念的体现。传统框架的定制往往需要修改配置文件或编写初始化代码,而 dsh 让定制变成声明式的——你只需要描述「我要哪些插件、每个插件什么配置」,剩下的组合、依赖解析、加载顺序都由 Cordis Loader 自动处理。这大大降低了定制的门槛,也让定制结果可复现、可分享。

第四章 代码结构详解


4.1 顶层目录概览

deepseek-harness 是一个 pnpm monorepo,顶层目录遵循「源码 + 文档 + 工具链」的标准组织。理解这个顶层结构是阅读源码的起点。

deepseek-harness/
├── packages/          # 核心工作区(50+ 个 @deepseek-ai/dsh-* 包)
├── apps/              # 可运行应用(web、headless 等)
├── docs/              # 架构文档、子系统文档、用户指南
├── vendor/            # Vendored Cordis 源码(pinned 上游 SHA)
├── website/           # 官网源码
├── python/            # Python 侧组件(如 MCP server)
├── native/            # 原生组件(如 code-runtime)
├── scripts/           # 构建/校验/代码生成脚本
├── .agents/           # Agent 笔记、技能、决策记录
├── AGENTS.md          # 仓库级 Agent 指南
├── CLAUDE.md          # 符号链接到 AGENTS.md
└── pnpm-workspace.yaml

图 1:deepseek-harness 顶层目录结构
packages 是整个项目的核心,包含 50+ 个工作区包,每个包是一个独立的 npm 包(@deepseek-ai/dsh-* scope)。

  • apps 是面向最终用户的可运行应用入口,如 Web UI 和 headless 模式。
  • docs 是极其详尽的架构文档,这是 dsh 区别于许多开源项目的一大特色——几乎每个设计决策都有文档记录。
  • vendor 目录存放 Cordis 框架的 vendored 源码,dsh 把 Cordis 作为 peer dependency 一起发布,避免在上游命名空间 squat。

4.2 packages/core:产品 API 主干

packages/core 是 dsh 的产品 API 主干,包含每次组合启动时都会加载的包:事件溯源的会话日志、系统提示词组装、工具注册表、Agent 类型、以及驱动它们的具体循环。这些是「产品级」包——插件和消费者构建其上的稳定表面。
core 组包含六个关键包。

  • scope 提供作用域上下文注册原语,是库而非服务(无 ctx 键)。
  • session 提供事件溯源的会话日志和内存存储(ctx.sessions)。
  • system-prompt 提供提示词和工具 schema 的组装注册表(ctx.systemPrompt)。
  • tools 提供作用域工具注册表和执行流水线(ctx.tools)。
  • agent 提供 Agent 接口、注册表和事件词汇(ctx.agents)。
  • agent-loop 提供默认的具体 Agent 驱动(ctx.agentLoop)。
  • 此外还有 agent-default-model 提供部署默认模型选择(ctx.agentDefaultModel)。

这六个包的关系是:agent 拥有公共契约(Agent 接口、事件词汇),agent-loop 是其默认实现。扩展插件依赖接缝(agent)而非具体实现(agent-loop),因此驱动保持可替换。scope 为所有包提供共享的作用域原语——一个贡献(工具、提示词段、变量、限制、监听器)要么是全局的(对所有 Agent 可见),要么是作用域的(仅属于某个 Agent)。这种作用域机制让多 Agent 场景下的隔离成为可能。


4.3 packages/llm:LLM 能力家族

packages/llm 是 LLM 能力家族,包含抽象服务定义和各个提供商的适配器。这个组的设计充分体现了「能力接缝」理念——服务定义与消费者在同一包(dsh-llm),而各个提供者在独立包中,独立演进。
dsh-llm 定义了 LLM 服务的抽象接口,包括消息词汇(Message、ContentBlock、StreamChunk)、模型请求格式、流式响应协议。它同时是服务定义和消费者——agent-loop 通过 ctx.llm 调用模型,而不关心具体是哪个提供商。dsh-llm-deepseek 提供 DeepSeek 模型的适配,dsh-llm-replay 提供回放模式(用于测试和调试),dsh-llm-pi-ai 提供 pi.ai 的适配。这种设计使得新增一个模型提供商只需写一个新的适配器包,无需触碰 agent-loop 或任何工具。
LLM 子系统还处理流式响应的复杂性。模型的流式输出包含 token 级别的块(chunk),dsh 把每个 chunk 作为 assistant/chunk 事件记录在会话日志中,保证 token 级别的回放保真度。组装后的完整消息作为 assistant/message 事件记录,携带该步的 usage(token 计数)。派生的历史使用 assistant/message,而原始 chunk 保留在日志中用于精确回放。这种「双事件」设计兼顾了派生效率和回放保真。


4.4 packages 中的工具家族

dsh 的工具能力通过一系列 dsh-tool-* 包提供,每个包是一个独立的工具插件。这些工具都注册到 ctx.tools,通过统一的执行流水线被调用。dsh 内置了丰富的工具家族,覆盖文件操作、命令执行、代码运行、Web 访问、子 Agent 委派等场景。

  • 文件相关工具包括 dsh-tool-fs(文件读写、编辑、搜索)、dsh-tool-terminal(终端命令执行)。
  • 代码运行工具包括 dsh-tool-cordis(Code Mode,运行代码块)。
  • Web 工具包括 dsh-tool-web(网页抓取、搜索)。
  • 交互工具包括 dsh-tool-ask-user(向用户提问)、dsh-tool-todo(任务管理)。
  • 高级工具包括 dsh-tool-subagent(子 Agent 委派)、dsh-tool-skill(技能调用)。

每个工具都定义了自己的 schema、执行体、结果格式化逻辑,通过 ctx.tools.register 注册。
工具的执行都经过统一的流水线(pre-execute / execute / post-execute),这意味着所有工具都自动获得权限检查、沙箱隔离、指标采集、结果美化等能力,而无需每个工具单独实现。这种「一次挂载、全局生效」的设计,大大降低了工具开发的门槛,也保证了安全策略的一致性。社区开发者贡献新工具时,只需关注工具本身的逻辑,安全性和可观测性由框架保证。


4.5 packages 中的基础设施

除了核心和工具,packages 还包含大量基础设施包,它们为 Agent 运行提供支撑能力。

  • sandbox 提供沙箱执行后端(本地、E2B 云沙箱)。
  • fs 提供文件系统能力接缝和守卫。
  • subprocess 提供子进程管理。
  • credentials 提供凭证管理。
  • storage 提供存储抽象。
  • compaction 提供会话历史压缩(当上下文过长时自动摘要)。
  • context 提供上下文管理。
  • jobs 提供后台任务管理。
  • schedule 提供定时任务。
  • todo 提供任务跟踪。
  • plan 提供计划模式。
  • goal 提供目标管理。

这些包各司其职,通过 ctx 键暴露服务,可按需挂载。
值得一提的是 mcp 包,它提供 Model Context Protocol 的支持。MCP 是 Anthropic 提出的开放协议,用于让 Agent 连接外部工具和数据源。dsh 的 mcp 包让 dsh 能够作为 MCP 客户端连接任何 MCP 服务器,也可以作为 MCP 服务器被其他客户端连接。这种互操作性让 dsh 能够融入更广泛的 Agent 生态,而非成为一个封闭系统。
另一个重要的基础设施包是 typert(Type Runtime)。它是一个类型图生成器、加载器和运行时注册表,为 dsh 的类型安全提供基础。dsh 大量使用 TypeScript 的类型系统来保证插件契约的正确性,typert 负责在运行时维护这些类型信息,支持动态类型查询和校验。这是 dsh 工程成熟度的一个体现——类型安全不是可选的,而是内建的。


4.6 apps 与 vendor:应用入口与框架源码

apps 目录包含面向最终用户的可运行应用。web 应用提供浏览器端的 Web UI,是 dsh 的主要交互界面,默认在 http://127.0.0.1:3080 启动。headless 应用提供无界面的命令行模式,适合自动化场景和服务器部署。这些应用本质上是 Profile 的实例化——它们加载一组预定义的 Bundle,组合出完整的 Agent 运行时。
vendor 目录存放 Cordis 框架及其基础库的 vendored 源码。dsh 把 cordis、cosmokit、schemastery、cordis-plugin-loader、cordis-plugin-include 等上游包的源码 pin 到特定 SHA,复制到 vendor 目录下,并以 @deepseek-ai 重新 scope 后发布。
这种 vendoring 策略有几个好处:

  • 第一,保证 dsh 使用的 Cordis 版本完全可控,不受上游意外更新影响;
  • 第二,dsh 可以对 Cordis 做必要的本地修改(修改记录在 vendor/README.md 中);
  • 第三,发布 dsh 时一并发布 Cordis,用户无需单独安装上游包。更新时通过同步 procedure 拉取上游新版本,重新应用本地修改。

第五章 核心架构与核心概念


5.1 核心概念词典


阅读 dsh 源码前,必须先建立一套术语体系。以下概念贯穿整个代码库,理解它们是理解 dsh 的前提。本节按「从插件到运行」的逻辑顺序逐一解释这些概念。

概念定义所在模块
Plugin(插件)实现 Service 接口的对象,dsh 的一切能力都以插件形式存在。vendor/cordis
Context(上下文)服务仓库,插件通过 ctx.键 注册和查找服务。vendor/cordis
Service(服务)挂在 ctx 上的能力单元,有定义、提供者、消费者三角色。vendor/cordis
Capability Seam(能力接缝)一项可替换能力的完整描述:定义+提供者+消费者。packages/*
Session(会话)只追加的事件日志,Agent 交互的全部历史,状态由此派生。packages/core/session
SessionEvent会话日志中的一个事件,如 turn/start、assistant/chunk、tool/call。packages/core/session
Turn(轮)一次排空已接纳输入的循环,模型和工具停止后结束。packages/core/agent-loop
Step(步)一次模型请求加其触发的工具执行,一个 turn 含零或多个 step。packages/core/agent-loop
Round(回合)包含一个 turn 的外层策略迭代,如 goal round 或 Ralph round。packages/goal, packages/workflow
Agent(智能体)一个交互实体,拥有独立的会话、工具作用域、事件流。packages/core/agent
Agent Loop(Agent 循环)驱动 Agent 执行的具体循环,claim 输入、调模型、派工具。packages/core/agent-loop
Tool(工具)Agent 可调用的能力单元,经统一流水线执行。packages/core/tools
Profile命名的插件组合,存储在 Harness home,列出堆叠的 Bundle。packages/boot
BundleCordis 配置行及代码的分发格式,可被上层 patch。packages/bundle
Scope(作用域)注册的作用范围:全局(所有 Agent 可见)或作用域(单一 Agent)。packages/core/scope
inject插件声明服务依赖的方式,等待所需服务就绪后激活。vendor/cordis
waterfall事件派发模式之一,监听者可包装或替换结果,链式传递。vendor/cordis
Ralph一种前台全新 Agent 工作流,向不可变目标推进的多回合循环。packages/workflow


表 1:deepseek-harness 核心概念词典


5.2 核心模块详解


5.2.1 Session:事件溯源的会话日志

Session(packages/core/session)是 dsh 状态模型的核心。一个 Session 是一个只追加的事件日志,记录了 Agent 交互的全部历史。LLM 的消息历史不是单独存储的,而是从事件日志派生出来的——重放就是从同一批事件重新派生。这种设计使得持久化变得简单(存日志即可),且天然支持崩溃恢复、时间旅行、会话分叉。
SessionEventMap 是会话事件的词汇表,它是可合并扩展的——插件通过 TypeScript 声明合并添加新事件类型。
核心事件覆盖了交互的完整生命周期:

  • turn/start 和 turn/end 标记一轮对话的边界;
  • step/start 和 step/end 标记一次模型调用加工具执行的边界;
  • user/message 记录用户消息(直接人类输入、agent.inject 合成上下文、或目标续推进回合);assistant/chunk 记录流式 token 块(保证 token 级回放保真);
  • assistant/message 记录组装后的完整助手消息(携带 usage);
  • tool/call 和 tool/result 记录工具调用与结果。

Session 的派生机制是其精髓。消息历史不是直接存储的,而是通过遍历事件日志、应用每个事件的 surfaceOp(表面操作)来派生的。这意味着,同一个事件日志可以被不同的派生策略解读——比如压缩模块可以在派生时跳过被摘要的事件,从而产生更短的消息历史给模型。这种「日志为源、派生为用」的设计,让上下文管理变得极其灵活,且不丢失任何信息(原始日志始终完整)。


5.2.2 Agent 与 Agent Loop:交互实体与驱动循环

Agent(packages/core/agent)定义了智能体的公共契约——Agent 接口、注册表和事件词汇。一个 Agent 是一个交互实体,拥有独立的会话、工具作用域、事件流。

  • Agent 暴露的核心方法包括:followup(提交后续轮次)、send(路由输入到 inbox 边界并可选唤醒驱动)、runMaintenance(运行维护任务)、inject(注入模型可见上下文)等。
  • Agent 还维护状态机:idle(空闲)、running(运行中)、cancelled(已取消)、disposed(已销毁)。

Agent Loop(packages/core/agent-loop)是 Agent 的默认具体驱动。它实现了 Agent 契约定义的行为:claim 排队的输入、在会话日志上开启 turn、通过 systemPrompt 组装请求前缀、从日志派生历史、通过 LLM 接缝流式获取模型响应、通过 tools 注册表派发工具调用、把每个模型可见的事实追加回日志,然后进入下一步。这个循环是 dsh 的「心跳」,理解它就理解了 Agent 如何工作。
Agent Loop 的关键设计是「claim 机制」。驱动器不是被动等待输入,而是主动 claim(认领)排队的输入。当用户提交 followup 时,消息进入 inbox 但不立即处理;驱动器在当前工作完成后,claim 下一个待处理的输入,开启新的 turn。这种设计支持优雅的取消——当用户取消当前任务时,驱动器在当前 step 完成后停止,已排队但未 claim 的输入可以保留或丢弃。claim 机制还支持「唤醒」——新的高优先级输入可以唤醒空闲的驱动器。


5.2.3 Tools:注册表与执行流水线


Tools(packages/core/tools)是 dsh 的工具注册表和执行流水线。它提供 ctx.tools 服务,工具通过 ctx.tools.register 注册,Agent Loop 通过 ctx.tools.dispatch 派发。但 Tools 的核心价值不在于注册和派发,而在于其分阶段的执行流水线。
一次工具执行经过:tools/pre-execute waterfall(钩子、权限、沙箱策略)→ 注册的单调守卫(否决或弃权)→ ctx.approval 审批(一次性提示)→ tools/execute waterfall(超时、重试、指标)→ 工具 execute() 函数体 → 文件系统写意图检查(fs/write-intent 或 fs/edit-intent)→ 工具拥有的会话事件(todo/write、fs/observed 等)→ tools/post-execute waterfall(接受、阻止、替换、添加上下文)→ 定义拥有的 finalizeContent → tools/result 事件(观察不可变结果)。
这条流水线的关键特征是「关注点分离」。安全策略在 pre-execute,性能指标在 execute,结果美化在 post-execute,各自独立挂载,互不干扰。注册表会无损快照候选结果,在可见定义的 finalizeContent 回调前规范化快照失败,保证同步的内容不变式。tools/result 随后观察不可变的、无损 JSON 的结果。这种设计让钩子可以跨工具家族生效,而无需把工具耦合到某个策略服务。


5.2.4 LLM Seam:模型适配的抽象层

LLM Seam(packages/llm)是 dsh 的模型适配抽象层。dsh-llm 定义了 LLM 服务的抽象接口和消息词汇(Message、ContentBlock、StreamChunk),同时作为服务定义和消费者。各个提供商适配器(dsh-llm-deepseek、dsh-llm-replay 等)是服务提供者,实现具体协议。Agent Loop 通过 ctx.llm 调用模型,完全不关心底层是哪个提供商。
LLM Seam 处理的核心复杂性是流式响应。模型的流式输出是 token 级别的块,dsh 把每个 chunk 作为 assistant/chunk 事件记录,保证 token 级回放保真。组装后的完整消息作为 assistant/message 事件记录,携带 usage。这种双事件设计兼顾了派生效率(派生历史用 assistant/message)和回放保真(原始 chunk 保留在日志中)。LLM Seam 还处理工具调用格式的转换——不同提供商的工具调用 JSON 格式不同,Seam 负责归一化为 dsh 内部的 ContentBlock 表示。
LLM Seam 的另一个重要能力是「重放模式」。dsh-llm-replay 可以读取之前记录的会话事件,重放模型的响应,而不实际调用模型。这对测试和调试极其有用——你可以在不消耗 API 配额的前提下,精确复现 Agent 的行为。这种能力是事件溯源架构的自然产物——既然所有响应都记录在日志中,重放就是读取日志而非调用模型。


5.3 模块协作关系

理解 dsh 的架构,关键是理解核心模块如何协作完成一次 Agent 交互。一次完整的交互流程涉及六个核心包的协作:

  • agent-loop(驱动器)claim 排队的 prompt,在 session(会话日志)上开启 turn,通过 system-prompt(提示词组装)组装请求前缀并从日志派生历史,通过 llm(LLM 接缝)流式获取模型响应,通过 tools(工具注册表)派发工具调用,把每个模型可见的事实追加回日志,然后进入下一步。
  • 这六个包通过 ctx 上的服务键协作,而非直接导入彼此的实现。agent-loop 注入 ctx.sessions、ctx.systemPrompt、ctx.llm、ctx.tools,通过这些键调用服务方法。这意味着,任何一个包的实现都可以被替换,只要新实现遵守服务定义的契约。例如,你可以把 ctx.llm 的实现从 dsh-llm-deepseek 换成自定义的 mock 实现,agent-loop 完全无感知。这种松耦合是 dsh「一切皆插件」的实质。

模块协作还通过事件系统增强。

  • agent-loop 在关键节点派发 agent/* 事件(如 agent/pre-step、agent/post-step、agent/turn-stopping),其他插件可以监听这些事件实现拦截、策略、观察。例如,compaction 模块监听 agent/pre-step 在上下文过长时触发摘要;guard 模块监听 agent/* 实现安全策略;feedback 模块监听 agent/* 收集用户反馈。
  • 这种事件驱动的协作方式,让插件可以在不修改 agent-loop 的前提下,深度介入 Agent 行为。

第六章 端到端流程


6.1 启动流程:从命令行到 Agent 就绪

dsh 的启动流程: 从用户执行 npx @deepseek-ai/dsh web 或 pnpm dsh web 开始。这个看似简单的命令背后,经历了一系列精心编排的步骤,把一组离散的插件组装成一个可运行的 Agent 实例。理解这个启动流程,是理解 dsh 如何「从配置到运行」的关键。

  • 第一步是解析命令行参数,确定要启动的 Profile(默认是 web 或 headless)。Profile 是存储在 Harness home 中的命名组合,它列出了要堆叠的 Bundle。
  • 第二步是 Cordis Loader 介入,读取 Profile 指定的 Bundle 列表,解析每个 Bundle 的 cordis.yml 配置行,确定要加载的插件及其配置。Loader 会处理依赖关系——通过 inject 声明,等待所需服务就绪后才激活插件,因此加载顺序是自动解析的,无需手动编排。
  • 第三步是应用用户的 cordis.patch.yml。这个补丁文件可以覆盖任何 Bundle 中的配置——修改插件参数、禁用某些插件、添加树外插件。补丁机制让用户可以在不修改任何 Bundle 代码的前提下深度定制 Agent 行为。
  • 第四步是实例化插件树。Cordis 按解析后的顺序实例化每个插件,调用其 apply(ctx) 方法,插件在此时注册自己的服务、事件监听器、工具等。每个注册都返回一个 disposer,保证卸载时可逆。
  • 第五步是初始化核心服务。session 服务创建内存会话存储,system-prompt 服务组装默认提示词,tools 服务初始化工具注册表,llm 服务加载配置的模型适配器,agent-loop 服务准备驱动器。当所有核心服务就绪后,Agent 进入 idle 状态,等待用户输入。

整个启动过程通常在数秒内完成,之后 Web UI 在 http://127.0.0.1:3080 可访问,用户可以开始与 Agent 交互。


6.2 Agent 循环:一次 Turn 的完整旅程

Agent 循环是 dsh 的心跳。一次完整的 Turn(轮次)从用户提交输入开始,到模型和工具停止、轮次结束为止。理解这个循环的每一步,就理解了 Agent 如何工作。以下按时间顺序拆解一次 Turn 的完整旅程。

  • 第一步,用户提交输入。用户通过 Web UI 或 SDK 调用 agent.followup(content),消息进入 Agent 的 inbox。此时派发 agent/inbox/spliced 和 agent/inbox/inserted 事件,通知 UI 和 SDK 监听器。消息排队但不立即处理——驱动器会在当前工作完成后 claim 它。
  • 第二步,驱动器唤醒并 claim 输入。agent-loop 检测到排队的输入,将状态从 idle 切换到 running,派发 agent/status running 事件。驱动器 claim 待处理的 next-step 输入加上一个排队的 prompt,在会话日志上开启 turn(turn/start 事件)。claim 操作会派发 agent/inbox/claimed 事件,标记哪些消息被认领。
  • 第三步,pre-step waterfall。驱动器派发 agent/pre-step waterfall 事件,钩子监听器可以权威地拒绝或进入(enter messages)。如果提议的 step 被拒绝或 pre-step 失败,claimed 批次被退回,驱动器回到 idle。这个 waterfall 是策略拦截的关键点——guard、compaction、plan-mode 等模块在此介入。
  • 第四步,组装请求并调用模型。如果 pre-step 通过,驱动器通过 ctx.systemPrompt 组装请求前缀(系统提示词、工具 schema),从会话日志派生消息历史,构造完整的模型请求。然后通过 ctx.llm 流式调用模型,每个 token 块作为 assistant/chunk 事件记录在日志中。模型响应可能包含文本内容和工具调用块。
  • 第五步,工具执行。如果模型响应包含工具调用,驱动器通过 ctx.tools.dispatch 派发每个工具调用。工具经过完整的执行流水线(pre-execute → guards → approval → execute → post-execute → finalize → result),结果作为 tool/result 事件记录。工具执行可能产生新的会话事件(如 todo/write、fs/observed)。所有工具结果追加到会话日志后,进入下一个 step——再次调用模型,模型基于工具结果决定下一步。
  • 第六步,Turn 结束。当模型响应不再包含工具调用(即模型认为任务完成或需要用户输入)时,当前 step 结束。如果没有更多排队的输入,Turn 结束(turn/end 事件),驱动器回到 idle 状态,派发 agent/status idle。如果还有排队的输入,驱动器 claim 下一个输入,开启新的 Turn。整个过程中,所有状态变更都记录在会话日志中,保证可持久化和可回放。

6.3 持久化与崩溃恢复流程


dsh 的事件溯源架构使得持久化和崩溃恢复变得优雅。

  • 持久化的核心是会话事件日志——把 append-only 的事件序列写入持久存储(SQLite 或文件系统)
  • dsh-session-persistence 包提供持久化实现,dsh-session-query-sqlite 提供 SQLite 后端。持久化策略由 on-checkpoint-policy 拥有,决定每个请求的持久化检查点时机。

崩溃恢复的流程是:进程重启后,从持久存储读取会话的事件日志,在内存中重建会话状态。由于状态是从事件派生的,重建就是重放事件——应用每个事件的 surfaceOp,重建消息历史和会话状态。恢复到崩溃前的最后一个完整事件点,Agent 可以从那里继续。这种恢复是精确的——不会丢失已确认的事件,也不会重放未完成的事件(因为未完成的 turn/step 不会有 turn/end 或 step/end 事件,恢复时会被识别为不完整而回滚)。
dsh 的持久化设计还支持「会话分叉」。ctx.sessions.fork(source, boundary?, childSessionId?) 可以从某个事件点分叉出一个新会话。分叉的新会话继承源会话到分叉点的全部事件,之后独立演进。这对探索性任务非常有用——你可以从某个点分叉,尝试不同的提示词或策略,比较结果,而原始会话不受影响。这种能力是事件溯源架构的自然产物,传统内存式状态模型难以实现。

第七章 面向小白的 deepseek-harness 文档导览


7.1 学习路径建议

对于一个刚接触 deepseek-harness 的初学者,直接扎进 50+ 个包的源码很容易迷失。建议按照「先用起来、再理解、后深入」的三阶段路径学习。

  • 第一阶段的目标是让 dsh 在本地跑起来,建立对产品的直观感受。
  • 第二阶段的目标是理解 Agent 循环的整体流程,能够画出数据流图。第
  • 三阶段才是深入某个具体模块的源码,理解实现细节。

具体流程如下:

  • 第一阶段,建议从 README 的快速开始入手,执行 npx @deepseek-ai/dsh web 启动 Web UI。先不要纠结配置,直接用默认配置体验 Agent 的对话、工具调用、文件操作等能力。观察 Web UI 中 Agent 的行为——它如何响应、如何调用工具、如何展示结果。体验后,尝试修改一些配置(如更换模型、启用沙箱),观察行为变化。这个阶段的目标是建立「dsh 能做什么」的感性认识。
  • 第二阶段,建议通读 docs/architecture.md 和 docs/cordis-primer.md,配合本文的第五章和第六章,画出 dsh 的数据流图。重点理解「一次 Turn 的数据如何流动」「插件如何通过 ctx 协作」「事件如何被记录和派生」这三个问题。这个阶段不需要深入每个包的实现,只需要建立全局视图。建议同时浏览 docs/glossary.md,熟悉核心术语。
  • 第三阶段,选择一个最感兴趣的方向深入。如果对插件机制感兴趣,可以深入 vendor/cordis 的源码,理解 Service、Context、事件系统的实现;如果对 Agent 循环感兴趣,可以深入 packages/core/agent-loop,理解 claim、step、turn 的调度逻辑;如果对工具执行感兴趣,可以深入 packages/core/tools,理解流水线的实现;如果对持久化感兴趣,可以深入 packages/session 和 packages/session-persistence,理解事件溯源和崩溃恢复。每个方向都可以独立深入,不需要面面俱到。

7.2 关键文件与文档阅读顺序

对于希望系统阅读 dsh 的读者,建议按以下顺序阅读文档和源码。这个顺序遵循「从概念到实现、从整体到细节」的原则,能够帮助读者逐步建立对项目的理解。

顺序文件/文档阅读目的
1README.md了解项目定位、快速启动方式
2docs/cordis-primer.md理解 Cordis 的五大理念,这是 dsh 的基石
3docs/architecture.md理解整体架构:Profile、Bundle、能力接缝
4docs/glossary.md建立术语体系,熟悉核心概念
5docs/agent-lifecycle.md理解一次 Turn 的完整时序图
6docs/tool-execution-pipeline.md理解工具执行的流水线
7docs/subsystems/core.md深入核心子系统:session、agent、agent-loop
8docs/subsystems/session.md深入事件溯源的会话模型
9docs/subsystems/tools.md深入工具注册表和执行流水线
10docs/subsystems/llm-streaming.md深入 LLM 适配和流式响应
11docs/capability-seams.md理解所有能力接缝的全景图
12docs/persistence-catalog.md理解持久化机制和事件目录
13packages/core/*/README.md阅读各核心包的 README,了解 API 表面
14docs/cookbook/ 下的指南学习如何添加包、工具、LLM 适配器、对话节点


表 2:deepseek-harness 推荐阅读顺序


7.3 概念地图:用一张图理解 dsh


为了帮助初学者快速建立心智模型,这里用文字描述一张 dsh 的概念地图。想象一棵树:

  • 树根是 Cordis 框架(vendor/cordis),提供插件、上下文、服务、事件、可逆副作用五大原语。
  • 树干是 packages/core,包含 session(会话日志)、system-prompt(提示词组装)、tools(工具注册表)、agent(Agent 契约)、agent-loop(驱动循环)——这些是每次启动都会加载的产品级包。
  • 树枝是各个能力家族:packages/llm(模型适配)、packages/shell + packages/subprocess + packages/sandbox(执行环境)、packages/fs(文件系统)、packages/mcp(MCP 协议)、packages/compaction(上下文压缩)、packages/goal + packages/plan + packages/todo(任务管理)、packages/workflow + packages/subagent(编排)、packages/identity + packages/credentials(身份与凭证)、packages/feedback(反馈)、packages/skill(技能)。每根树枝上挂着若干叶子包(具体的提供者或消费者),可以按需挂载。
  • 树冠是 apps(web、headless),它们是面向用户的可运行应用,本质上是 Profile 的实例化——加载一组预定义的 Bundle,组合出完整的 Agent 运行时。Profile 和 Bundle 是「组合优于配置」的体现:用户通过声明式地选择 Bundle 和编写 patch 来定制 Agent,而非编写胶水代码。
  • 整棵树的生长由 Cordis Loader 编排——它解析依赖、应用补丁、实例化插件、注册服务和事件,最终让这棵树「活」起来。

理解这张概念地图后,阅读任何 dsh 的代码或文档时,你都能快速定位它在树中的位置——是根(Cordis 原语)、干(核心包)、枝(能力家族)、叶(具体实现)、还是冠(应用入口)?这种定位能力是高效阅读大型代码库的关键。


第八章 总结与展望


8.1 deepseek-harness 的核心价值


回顾全文,deepseek-harness 的核心价值可以归纳为四点。

  • 第一,它用「一切皆插件」的架构彻底解决了 Agent 框架的可扩展性问题——任何核心行为都可以通过挂载插件来替换或增强,无需 fork。
  • 第二,它通过「能力接缝」设计让各项能力独立演进、安全组合,打破了传统框架的能力耦合困境
  • 第三,它采用「事件溯源」架构,让会话状态天然可持久化、可恢复、可回放、可分叉,满足生产环境的长任务需求。
  • 第四,它通过 Profile 和 Bundle 机制实现了「组合优于配置」,让深度定制变得声明式、可追踪、可分享。

8.2 对 Agent 生态的影响


dsh 的出现反映了 Agent 框架正在走向成熟和分化。早期,Agent 工具主要是闭源的、模型绑定的(如 Claude Code 绑定 Anthropic、Codex 绑定 OpenAI)。dsh 代表了一种新趋势:开源的、模型无关的、工程成熟的 Agent 框架。这种趋势意味着,未来 Agent 框架的选择将不再受限于模型选择——你可以用 DeepSeek 模型配 dsh 框架,也可以用 OpenAI 模型配 dsh 框架,框架与模型解耦。
dsh 的「一切皆插件」理念也可能影响整个 Agent 生态的演进方向。如果插件化成为共识,那么社区的力量将集中在开发高质量插件上,而非重复造框架。一个团队开发的优秀沙箱插件,可以被所有 dsh 用户使用;另一个团队开发的 MCP 适配插件,同样如此。这种生态效应一旦形成正向循环,将大幅降低 Agent 应用的开发门槛。dsh 的 cordis 基础也为这种生态提供了形式化保证——插件可以安全组合、安全替换,不会产生意料之外的冲突。


8.3 未来展望


展望 dsh 的未来发展,有几个方向值得关注。

  • 第一是生态成熟——目前 dsh 处于 developer preview 阶段,迭代迅速且有兼容性破坏变更。随着首个正式 tag 发布,API 趋于稳定,社区插件将迎来爆发。
  • 第二是更多模型适配——虽然 dsh 已支持 DeepSeek 和若干提供商,但未来可能扩展到更多开源模型(如 Llama、Qwen)的本地部署适配。
  • 第三是 Agent 编排能力的深化——Ralph 循环、子 Agent、工作流等编排原语目前仍在演进,未来可能形成更丰富的编排模式库。

另一个值得关注的趋势是 dsh 与 MCP 生态的融合。MCP 作为开放协议正在获得广泛采纳,dsh 既能作为 MCP 客户端连接外部工具,也能作为 MCP 服务器被其他客户端连接。这种双向互操作性让 dsh 能够成为 Agent 生态的「连接器」——既消费生态中的工具,又向生态贡献能力。如果这种定位实现,dsh 将不仅是一个框架,而是一个 Agent 生态的枢纽。
对于希望参与 dsh 贡献的开发者,建议从 cookbook 指南入手——docs/cookbook/ 下有添加包、添加工具、添加 LLM 适配器、添加对话节点的详细指南。这些指南的接口清晰、独立性强,适合作为第一个贡献点。随着对框架理解的深入,可以逐步参与核心模块的优化。dsh 的文档极其详尽,AGENTS.md 为 AI 辅助开发提供了清晰指引,是参与贡献的良好起点。
最后,无论你是 dsh 的使用者还是贡献者,理解其背后的第一性原理——「Agent = Model + Harness,而 Harness 的一切皆插件」——都比记住具体 API 更重要。框架会迭代、API 会变化,但这个核心问题和解决它的插件化思维,是持久有效的。希望本文能够帮助你建立这种思维,在 dsh 的代码和文档中找到方向,在实际工作中构建出强大的 Agent 应用。

更多推荐