DeepSeek Harness—— 编程 AI Agent 的三代进化:从"大而全"到"小而美",再到"一切皆插件"
2026 年 8 月 13 日,DeepSeek 开源了 DeepSeek Harness(
dsh)——不是新模型,而是一套 Agent 的运行时底座。发布 24 小时内收获约 4.6 万星。很多人把它当成"又一个对标 Claude Code 的 CLI",但把三代编程 AI Agent 放在一起看,你会发现它站在一条清晰的进化线上。这篇文章想站在架构师视角,讲清楚三件事:编程 AI Agent 是怎么一步步进化的,dsh 凭什么敢说"一切皆插件",以及这对所有用过 Claude Code、Pi 的开发者意味着什么。
一、模型的竞争已经结束,框架的竞争才刚刚开始
先退一步看背景。
过去两年,AI 编程助手之间的竞争焦点是"谁的模型更聪明"。但越来越多的人意识到一件事:模型能力正在趋同,真正拉开差距的是框架层——上下文怎么管理、工具怎么接入、能力怎么扩展、跑了半天怎么恢复。
而"框架竞争"不是一个静态的概念,它已经在三代产品里演进了三轮:
- 第一代,以 Claude Code 为代表:大而全。一个厂商给你一个完整的 Agent,扩展是它的附属品。
- 第二代,以 Pi 为代表:小而美。一个极薄的通用内核,让你自己拼装出属于你的 Agent。
- 第三代,以 dsh 为代表:一切皆插件。连内核本身都可以替换,组合成为一门有理论支撑的学科。
三代产品回答的是同一个问题——"一个编程 Agent 应该怎么被构建、怎么被扩展"——但答案一代比一代激进。本文就沿着这条线走:先看前两代解决了什么、留下了什么,再看 dsh 凭什么敢做第三代。
二、第一代:Claude Code——大而全的 Agent,扩展是厂商的恩赐
Claude Code 是"AI 编程 Agent"这个品类的定义者,这一点没有争议。
它赢在大而全:开箱即用就是一套完整的 Agent——文件读写、差分编辑、终端执行、网页检索、内置子代理、上下文工程、会话管理,全部配齐。你不需要组装任何东西,装好就能干活。对绝大多数人来说,这恰恰是对的:他们要的是一个能用的产品,不是一堆要自己拼的零件。
它也不是封闭的。Claude Code 开放了一套扩展体系,载体是 Plugin,聚合四类能力:
- Skill(技能):本质是带 frontmatter 的提示模板,把某个领域的知识、工作流、约束打包成可复用的能力,按需渐进式披露给模型。
- MCP(Model Context Protocol):外部工具服务器,通过标准协议把任意能力接进来——数据库、浏览器、内部 API。它最大的价值是可移植:写一个 MCP 服务器,Claude Code、Cursor、任何 MCP 客户端都能用。
- Hooks(生命周期钩子):在工具执行前后、会话开始结束等时机拦截事件,用来加确认、改输入输出、记日志。
- Plugin 市场:把上面的能力打包、分发、一键安装。
听起来很开放,但第一代的本质没有变:内核是闭源的、厂商定义的。 你可以在它周围加东西——加技能、加工具、加钩子——但核心逻辑你碰不到:模型怎么被调用、循环怎么转、上下文怎么组装、出了事怎么审计,全是黑盒。
"大而全"还有第二个代价:扩展之间没有组合纪律。Hook 注册了要靠你自己记得清理,插件依赖要靠人工编排,卸载不干净就是状态污染。在这个体系里,"扩展"永远是"往上叠加",而不是"替换"。
这不只是 Claude Code 的问题。Cursor、Codex 都属第一代——功能完整、内核私有、扩展是产品的附属品。它们的边界就是"产品"划定的边界,你始终在租借一个别人的 Agent。
第一代的局限,催生了第二代。
三、第二代:Pi——小而美,把 Agent 交还给你
Pi 是 libGDX 作者所在的 earendil-works 组织开发的、MIT 许可的开源 AI Agent 工具集,在 GitHub 上积累了近万 stars。它的出现代表一次方向反转:不要大而全,要小而美。
它的定位非常鲜明:不把"功能"内置成死特性,而是提供"原语"(Primitives, Not Features),让你自己拼装出属于你的 Agent。官方金句是 Adapt Pi to your workflows, not the other way around——让 Pi 适应你的工作流,而不是反过来。
这个哲学落到产品上,体现为几个"自主":
- 模型自主:不捆绑任何模型供应商。OpenAI、Anthropic、Gemini、Mistral、Bedrock、vLLM、Ollama 等 15+ 家任选,API Key 归你管、账单归你控,想换就换。
- 数据自主:会话历史、配置、凭证全部落在本地(
~/.pi/agent/),不上传任何遥测或使用数据,源码开源可审计。 - 行为自主:通过 Extensions(扩展)和 Skills(技能),你可以拦截、修改、替换 Agent 的任何行为——工具调用、上下文注入、快捷键、UI 面板,全部可编程。
最值得注意的是它的极简内核:定义"Agent 到底能做什么"的核心抽象,只有三个文件、约 1,370 行代码。其余的一切——会话管理、模型解析、扩展加载——都被设计成"可替换的能力",在运行时挂上去。
更极端的是,Pi 会故意不内置很多同类工具默认携带的功能,然后给出替代方案:
| 不内置的功能 | Pi 的替代方案 |
|---|---|
| MCP 协议集成 | 把工具写成带 README 的 CLI,或安装 MCP 扩展 |
| 子 Agent | tmux 开多会话,或自己写扩展 |
| 权限确认弹窗 | 放进容器跑,或自己写确认流程扩展 |
| 计划模式 | 把计划写文件,或写扩展 |
| 内置待办事项 | 用 TODO.md,或装扩展 |
| 后台 bash | tmux 获得完整可观测性 |
它的扩展体系分三层:Extensions(TypeScript 模块,可以注册工具、注册斜杠命令、拦截事件)、Skills(实现 Agent Skills 标准,兼容 Claude Code / Codex 的技能格式)、Pi Packages(pi install 从 npm / git / 本地安装,分发像 npm 包一样简单)。会话管理上,它有被社区高频称赞的树形会话——历史任意分叉不丢分支,配合上下文压缩让超长会话能继续下去。
在权限这件事上,Pi 非常诚实:README 里明确不内置权限系统,默认以启动用户的权限运行,推荐用容器、微 VM 或策略沙箱隔离。
把二代和一代并排看,进化很清楚:
- 内核从"重"到"薄"——Claude Code 的内核是一个庞大的闭源产品;Pi 的内核是 1,370 行代码。
- 扩展从"厂商的恩赐"到"产品的存在方式"——Claude Code 的扩展是绕着一个黑盒打补丁;Pi 的扩展就是它的一切。
- 掌控权从"租借"到"拥有"——全本地、全开源、全可编程。
但 Pi 也留下了两个天花板,第三代正是从这里起步:
第一个天花板:加法,不能替换。 Pi 的扩展是事件总线 + TS 模块,本质是"往上加"——注册一个工具、挂一个监听、装一个技能包。你可以加,但几乎换不掉核心、卸不净副作用。内核再薄,也还是一块不可动的骨头。
第二个天花板:可靠性自理。 会话事件是喂给界面的瞬时信号,UI 刷完就没了,不可重放、不可审计;权限要自己容器化;没有一条运行时不变式来保证"模型看到的,一定有据可查"。
四、第三代:dsh——没有特权核心,组合成为一门学科
4.1 从"薄内核"到"没有内核"
二代把内核做到了极薄,三代的问题是:能不能更进一步,让内核不存在?
在回答之前,先看一个所有做插件系统的人都绕不过去的坑:
装上容易,卸干净难;组合起来容易,拆开还原难。
插件 A 注册了一个事件监听,插件 B 往配置表里加了一行,插件 C 起了个后台定时器。现在你要卸载 A——得记得把它注册的监听、定时器、配置全部手动清掉。漏一个,就是内存泄漏、幽灵监听、状态错乱。
更麻烦的是依赖。插件 B 依赖插件 A 的能力,如果 A 还没加载完 B 就启动,程序直接崩。于是你得手写"启动顺序编排"——而顺序一旦写死,系统就僵了,动态加载和热更新基本没戏。
一代的 Hook、二代的扩展,都靠开发者自觉维护这些清理和顺序。dsh 的底层框架 Cordis,把这套问题背后的两个维度分别形式化了,合起来叫——时空可组合性(Spatiotemporal Composability)。这来自一篇论文:A Programming Paradigm for Spatiotemporal Composability。
- 时间可组合性(temporal composability):一个组件被移除时,它的所有副作用都能被完整撤销。论文把它形式化为 revertible effects(可逆副作用)——每一次对上下文的变换都携带一个逆操作,运行时替你追踪。用程序员的话说:一个永远不会漏掉的撤销栈。
- 空间可组合性(spatial composability):组件之间能声明依赖并响应式地管理。论文把它形式化为 reactive coeffects(响应式协效应)——上下文每次变化,都按组件的规格去通知它。用程序员的话说:一个声明式的依赖注入 + 响应式刷新。
Cordis 把这两件事做成了运行时机制,统一成"组件"的编程范式。而 dsh,整个就是建立在这套机制之上。
这句话值得重复一遍,因为它太容易被当成营销词了:dsh 的"一切皆插件"不是一句口号,它背后有一篇论文、一套形式化理论、和一个把理论变成运行时机制的框架。
4.2 没有特权核心
理解了时空可组合性,就能看懂 dsh 最反直觉的设计——它没有特权核心。
传统架构里,再插件化的系统,也有一块"所有功能都必须围着它改"的超级核心。但在 dsh 里:
- 模型适配器是插件
- 工具注册表是插件
- 会话日志是插件
- 沙箱和权限策略是插件
- 甚至驱动 Agent 一步步工作的 agent loop 本身,也是插件
这意味着两件很实际的事:
第一,扩展产品 = 把插件挂到别的插件旁边。 想换模型?挂一个新的 provider 插件。想换沙箱?挂一个新的 sandbox 插件。想调整 Agent 的循环逻辑?挂一个新的 loop 插件。没有任何一块需要 fork 仓库去打补丁。
第二,注册是可逆的。 插件卸载时,它注册的一切——监听、工具、配置——自动撤销。这在其他系统里要靠开发者自觉维护清理逻辑,在 dsh 里是框架保证的。一代的 Hook 靠人记得清理,三代把它变成了运行时义务。
dsh 甚至把这种"可组合"延伸到了部署配置。运行中的 dsh 不是固定模块的集合,而是一棵插件树,由启动时按序叠加的各层组成:profile(具名组合)→ bundle(可分发组合包)→ 用户自己的 patch 文件。你随时可以运行 dsh --profile web --dump-config 打印出这台机器实际启动的配置树,树里的任何一条,都能被你的 patch 替换。
想换掉内置的沙箱、换掉提示词组装逻辑、甚至换掉 agent loop——都不用改一行产品代码,写一个 patch overlay 上去就行。
这就是 dsh 相比第一代产品最本质的区别:它是一个白标、可嵌入的产品内核,不是一个开箱即用的应用。 一代让你用 Agent,二代让你拼 Agent,三代让你换 Agent 的每一块骨头。
4.3 最硬核的设计:模型看到的,必须能被日志重建
如果说"一切皆插件"是 dsh 最显眼的设计,那下面这个就是它最被低估、也最硬核的设计——它直接回答了二代留下的"可靠性自理"天花板。
一个 Agent 跑起来,会产生海量东西:用户说了什么、模型回了什么、调了哪些工具、工具返回了什么、上下文是怎么注入的……这些东西散落在各处,最后喂给模型。
一代和二代对这件事的态度是:够用就行。一代的会话格式私有,产品自管;二代的树形会话已经比"聊天记录"强了,但它回放的是给界面看的瞬时事件,不是经过校验的完整真相。
dsh 的态度截然不同。它把会话日志定义为唯一事实源,并立了一条运行时不变量:
模型可见即已记录(Model-visible means logged)。 任何抵达模型请求的东西,都必须能从事件日志重建出来。
这句话不是道德宣言,而是机器保证。dsh 用一个状态机 + 序列号在线校验整个事件流:turn/start 和 turn/end 必须配对,step 必须嵌套在打开的 turn 里,tool/result 必须有对应的 tool/call。任何违反,当场报错。所以如果你要给模型新增一种"能看到的新输入",就必须先新增一个会话事件类型——这不是建议,是强制。
为什么这么较真?因为 dsh 的 fork、恢复、回放、遥测、UI 渲染,全部派生自这条事件流。deriveMessages() 从日志投影出模型历史,原始的事件 chunk 保留着回放保真度。一旦日志不完备,所有这些派生功能全错。
这套机制带来了前两代都没有的能力:
- 审计:Agent 在哪个时刻、基于什么上下文、做了什么决定,可精确回溯。
- 断点续跑:崩溃了,从日志恢复,接着上次继续——上下文不丢。
- fork 会话:把一次会话从某个边界 fork 出去继续跑。
- 跨进程协作:多个进程共享同一份"真相",因为它们读的是同一份可重放的日志。
这条不变式是 dsh 全部架构里"最不性感、但最值钱"的设计。它不产生任何炫酷的演示效果,但它决定了这个 Agent 值不值得被信任——尤其是当它要跑长任务、跑不可信代码、或者在合规场景里被审计的时候。
顺带说一句工程纪律:为了让这套机制可信,dsh 把正确性从"口头规范"变成了"运行时硬断言"。它还做了一件事——文档是自动生成的。docs/subsystems/*.md 那些几万字的规格、模块依赖图、事件消费关系图,都是从代码和类型声明里抽出来的,CI 里有新鲜度门禁,文档和代码脱节直接挂。对一个想深入研究它的人来说,这一点太重要了。
4.4 能力 seam:换一个提供方,换一整块能力
"一切皆插件"要真正好用,光有理论还不够,还得有一个清晰的扩展模型。dsh 把它叫作 seam(接缝),固定三个角色:
- Service Definition:声明接口
- Service Provider:实现接口
- Consumer:使用它(通常是面向模型的工具)
这三个角色各自独立演化,是 dsh 的纪律:加一个能力,意味着设计完整的三个角色,而不是只写一个实现。一代的 Hook、二代的扩展都在强调"可扩展",但 seam 把"扩展"的形式定死了——不是往上叠加,而是定义接口、替换实现。
这个设计有一个精妙的效果。看这个例子:文件系统与子进程的提供方共享同一个"执行世界"。所以你把它们指向一个远程沙箱,Bash、PTY、LSP 会一并被搬过去——不需要为每种能力写专门的远程分支。你换 Provider,所有消费方自动跟着变,因为它们只依赖接口,不依赖具体实现。
这个模型还回答了一个很多人会问的问题:dsh 和 Claude Code / Codex 到底是什么关系?
答案是:在 dsh 的抽象里,它们不是竞品,而是可替换的零件。dsh 的 subagent 能力提供了一组 provider——subagent-claude-code、subagent-codex、进程内 fork、SDK 直连……你的 dsh Agent 跑着跑着,可以把一个轮次委派给 Claude Code 去干;反过来,Claude Code 也可以把 dsh 当成一个可调用的子 Agent。
在第一代的世界里,Claude Code 是终点;在第三代的视角里,Claude Code 和 Codex 只是"实现同一个 subagent 接口的不同提供方"。这个格局,比"谁更智能"的竞争高出整整一层。
有人给这个定位起了个名字:dsh 想当"Agent 世界的 Kubernetes"——不跟你抢上层应用,而是定义底层的组合与运行规范。
五、三代对照:进化到底在解决什么
把三代放在一张表里看,进化逻辑一目了然:
| 维度 | 第一代 Claude Code | 第二代 Pi | 第三代 dsh |
|---|---|---|---|
| 内核 | 大而全,闭源黑盒 | 极薄,约 1,370 行 | 没有特权核心,每一块都可替换 |
| 扩展 | Plugin 聚合 Skill / MCP / Hooks,叠加在闭源内核上 | 事件总线 + TS 模块,加法式 | 能力 seam,替换式 |
| 会话 | 私有格式,产品自管 | 树形会话,喂 UI 的瞬时事件 | 唯一事实源日志,可审计、可续跑、可回放 |
| 安全 | 产品自带确认弹窗,不可定制 | 不内置,用户自己容器化 | 沙箱、文件策略、审批做成内建 seam |
| 掌控权 | 只能扩展,不能拥有 | 全开源,可拼装 | 全开源,可换一切 |
三代各自的答案,也可以浓缩成三句话:
- 一代:给你一个完整的 Agent。开箱即用,但它是别人的——你只能围着它加东西。
- 二代:给你一台可拼装的 Agent。内核薄到极限,但内核仍是不可动的骨头,可靠性要自理。
- 三代:给你一块地基。没有特权核心,组合有理论兜底,每一次行为都有日志可查。
进化不是单纯的功能竞赛,它一直在解决两件事:把"扩展"从厂商的恩赐变成系统的地基,把"可靠性"从用户自理变成运行时保证。一代把前者做成了产品功能,二代把前者做到了极致、但留下了后者的空白,三代同时补上。
进化的结果甚至写进了账单。第三方实测:在同一个 DeepSeek 模型上,Claude Code 的 harness 每次任务成本接近最便宜 harness 的 7 倍(约 $0.195 vs $0.028),因为它的请求形态不是为 DeepSeek 的前缀缓存设计的。换句话说——你选的架构,会左右你的账单。第一代的"大而全"在体验上无可挑剔,但它的骨架决定了它对某些模型并不经济。
还有一个信号值得注意:dsh 发布当天,插件生态就自发成型——dsh-web-ui、dsh-cc-tui、dsh-vision-toolkit 等一批 dsh-plugin 话题下的项目冒了出来,现在社区目录收录的插件已达上千个。一个开源项目的插件生态在发布当天就自发组织起来,这本身就是"开放范式"最有力的注脚——它和第一代"厂商定义生态"、第二代"社区小生态"形成了鲜明对照。
六、什么时候该碰,什么时候别碰
写到这里,给一个不绕弯的判断。它不只是"要不要用 dsh",更是"你处在三代中的哪一代需求"。
第三代真正适合的场景:
- 你想要一个高度可插拔、可白标、能塞进自己产品的 Agent 内核,而不是一个开箱即用的 CLI。
- 你认同"换一个 provider 就能换一整块能力"的 seam 哲学,并且愿意付 Cordis 的学习成本。
- 你在做多模型、多沙箱、需要严格会话回放和审计的系统——金融、合规场景会特别喜欢那条"日志即真相"的不变量。
现在还不适合的:
- 它是开发者预览版,今天的插件下个版本 API 可能就变了。
- 主入口是 Web UI,不是纯终端体验。想要今天就能当生产力 CLI 用的,Claude Code 更稳。
- Cordis 的学习曲线不低,小项目是杀鸡用牛刀。
如果你是第一代用户,追求开箱即用和成熟生态,Claude Code 依然是低风险选择;如果你享受"完全拥有"的感觉,Pi 已经把第二条路走到了极致。三代不是互相取代,而是按需求分层。
七、对普通开发者,这到底意味着什么
最后回到开头的判断。
你未必需要今天就迁移到 dsh。但理解这条进化线,对每个用过 AI Agent 的人都有价值,因为它回答了一个所有 Agent 项目迟早要面对的问题:
当 Agent 从"个人玩具"走向"生产工具"时,什么样的架构才能让它可信、可维护、可演进?
一代证明了 Agent 可以成为产品,二代证明了 Agent 可以属于个人,三代给出了生产工具的答案:可逆副作用让你敢装敢卸;会话日志唯一事实源让你敢让它跑长任务、敢审计它;能力 seam 让你敢把它嵌进更大的系统;运行时不变式把"正确性"从口号变成了机器保证。
历史上有过相似的剧本:浏览器靠开放扩展生态爆发,编辑器靠插件市场繁荣。编程 AI Agent 的三代进化,走的是同一条路——让 Agent 的每一块都能被替换,让组合本身成为一门有理论支撑的学科。
你可以不用它,但你很难忽视它代表的趋势:Agent 正在从一个"产品",变成一个"可插拔的操作系统"。
附:延伸阅读
- DeepSeek Harness 官方仓库:github.com/deepseek-ai/deepseek-harness(MIT,
npx @deepseek-ai/dsh web即可体验) - 架构文档:
docs/architecture.md——官方说改packages/之前必读 - Cordis 论文:《A Programming Paradigm for Spatiotemporal Composability》——"一切皆插件"的理论根基
- Claude Code 插件文档:Plugin / Skill / MCP / Hooks——第一代扩展体系的全貌
- Pi 项目:github.com/earendil-works/pi——第二代的"小而美"样板
- 插件生态:GitHub 上
dsh-plugin话题、awesome-deepseek-harness 精选清单

浙公网安备 33010602011771号