Pi 与 DeepSeek Harness:Agent-Friendly 的两种组合方式
Pi Coding Agent 和 DeepSeek Harness(下文简称 DSH)都在回答同一个问题:怎样的软件更适合 Agent 使用和修改?
它们给出了近乎相反的答案。
Pi 保持一个很小的核心,把组合交给文件、Shell、CLI、进程和可选扩展。DSH 则建立在 Cordis 之上,把模型、工具、会话、沙箱乃至 Agent Loop 都组织成 Plugin,再由统一的 Service、Event 和生命周期机制连接起来。
两者都是 composable 的。真正的区别不在于是否组合,而在于:组合由谁负责,复杂性放在哪里。
DSH 是一个有趣而有野心的尝试,但我更看好 Pi。它对 Agent 和人类的心智负担都更低,更容易使用、理解和修改。长期记忆与任务状态可以放到进程之外,运行时本身则可以被停止、替换和重建。更重要的是,简单并不意味着不可组合。
一场延续至今的设计分歧
Richard Gabriel 在 The Rise of Worse is Better 中比较了两种软件设计取向。
第一种是 New Jersey Approach,也就是 Worse is Better。它把实现简单放在最高位置,接受一部分少见场景由用户和外围工具处理。第二种是 MIT Approach,也被称为 the right thing。它更重视接口的正确性、一致性和完整性,愿意用更复杂的实现换取统一的系统语义。
两者关注的设计指标相同,只是优先级不同:
| Worse is Better | MIT Approach | |
|---|---|---|
| 简单性 | 实现简单优先 | 接口简单优先 |
| 正确性 | 核心必须基本正确,少见边界可以为简单让步 | 所有可观察行为都应正确 |
| 一致性 | 必要时可以牺牲 | 与正确性同样重要 |
| 完整性 | 最容易被牺牲 | 应覆盖所有合理场景 |
Gabriel 把早期 Unix 和 C 视为 New Jersey Approach 的代表。它们没有一次提供完整世界,而是先提供容易实现、移植和组合的基本机制,缺少的能力由用户空间程序逐渐补足。这种不完整反而形成了 Unix 的组合传统。
Common Lisp、CLOS 和 Scheme 是他列举的 MIT Approach 代表。它们追求更完整和一致的语言语义,不愿把系统边界中的复杂情况推给使用者。代价是实现通常更困难,系统也更难快速传播。
Pi 和 DSH 不是这些项目的直接后继,但它们重现了相似的取舍。Pi 接近 New Jersey,不是因为它缺少 extension,而是因为它优先保持默认核心简单,把少见能力交给外围。DSH 接近 MIT,也不是因为它使用 Plugin,而是因为 Cordis 愿意增加框架复杂度,为所有组件提供统一的依赖、卸载、失败恢复和生命周期语义。
Pi:把组合交给环境
Pi 默认只给模型四个工具:read、write、edit 和 bash。它没有试图把每一种 Agent 工作流都建模成 Harness 内部的一等概念,而是尽量复用模型和用户已经熟悉的环境:
文件和知识 → 普通文件、AGENTS.md
命令和工具 → CLI、bash
后台任务 → tmux 或独立进程
工作流 → 脚本
额外能力 → TypeScript extension
持久化状态 → 文件、数据库、事件日志
Pi 不是不能扩展。恰恰相反,它可以通过 extension 增加工具、命令、UI、权限控制和其他工作流。它只是拒绝把这些能力全部塞进默认核心。
Pi 延续了 New Jersey Approach 的取舍:先把少数基础机制做好,其余能力留给外围组合。如果普通文件已经能保存计划,就不急着发明 Plan Object;如果 Shell 已经能启动另一个进程,就不急着把所有编排都内建进 Agent Loop。
这种设计对 Agent 和人都有一个直接好处:真实执行路径很短。
模型决定调用工具 → 工具执行 → 结果返回模型
当行为不符合预期时,我们通常可以直接查看 prompt、工具参数、脚本和输出,而不必先理解一套额外的运行时语义。
DSH:把组合变成运行时的一等概念
DSH 面对同一个问题,却选择把组合正式纳入 Harness。
它的核心口号是 Everything is a Plugin。模型适配器、工具、技能、会话、文件系统、沙箱、调度、UI 和 Agent Loop 都通过 Cordis 组合。Cordis 不只负责从一个 Registry 找到实现,还试图统一回答:
- Plugin 如何声明和获得依赖;
- Service 如何被提供和替换;
- Event 如何连接组件;
- Plugin 初始化失败时如何清理;
- 卸载时如何撤销 listener、timer 和注册项;
- Provider 消失后,依赖它的 Consumer 应该怎么办;
- 配置变化和热更新如何避免遗留旧状态。
DSH 的 MIT 气质来自它对统一生命周期语义的追求,而不是 Plugin 机制本身。
这套设计不是没有价值。当一个 Harness 需要支持很多 Provider、多种产品形态和独立开发的第三方组件时,直接 import 和条件分支也会逐渐形成一套隐式框架。DSH 至少把这张组件图正式表达出来,使能力、依赖和替换边界可以被枚举和查询。
问题在于,统一机制不会消灭复杂性,只会重新安排复杂性。一个工具调用不再只是调用一个函数,它可能涉及 Consumer、Service、Provider、Event 和 Plugin lifecycle。增加一个 Provider 也许更容易了,但理解一次完整执行、修改全局语义和排查框架错误可能更难。
两种组合方式
Pi 与 DSH 都可组合,只是组合单位不同:
Pi 组合程序、文件和进程;DSH 组合 Plugin、Service 和 Event。
| Pi | DeepSeek Harness | |
|---|---|---|
| 默认核心 | 小型 Agent Loop 和少量工具 | 统一 Plugin Runtime |
| 组合发生在哪里 | 文件、Shell、CLI、进程和扩展 | Cordis Context 内部 |
| 能力扩展 | 外部工具或可选 extension | Plugin、Service 和 Event |
| 状态持久化 | 倾向放到运行时之外 | 更多状态与生命周期进入统一运行时 |
| 改变能力 | 修改环境,必要时重启 | 重新组合或替换 Plugin |
| 理解系统 | 跟随直接代码和命令 | 理解契约与 Plugin Graph |
| 失败恢复 | 重启进程,从外部状态恢复 | 在运行时中卸载、回滚和恢复组件 |
| 复杂性承担者 | 用户、操作系统和外围工具 | Framework |
| 主要风险 | 外围约定逐渐散乱 | Framework 成为新的心智负担 |
这个区别不只影响 Agent,也影响人。人类维护者同样需要知道真实执行路径在哪里、状态由谁拥有、失败后如何恢复。Agent 只是让问题更加突出:它没有团队长期积累的隐性记忆,每次进入代码库都要重新构造系统模型,而每一层动态间接都会消耗上下文和推理。
为什么我更看好 Pi
我的默认选择是 Pi,不是因为小就一定更美,而是因为大多数 Agent 并不需要一个长期存活、可以原地改变自身组成的运行时。
更低的共同心智负担
Pi 复用的是 Agent 和人类都已经理解的对象:文件、命令、进程和代码。这些机制并不完美,却有成熟的查看、调试和组合方式。一个复杂的 Meta-framework 即使为 Agent 生成了完整目录,人类和 Agent 仍然需要先学习它的概念,才能判断真实行为。
架构抽象只有在减少的复杂性大于自身引入的复杂性时才值得存在。对于多数个人工作流和 Coding Agent,Pi 更容易达到这个条件。
让记忆长寿,让进程短命
Long-running Agent 不等于 long-running process。对话历史、计划、任务状态和外部操作记录可以持久化到文件、数据库或事件日志;运行时则应当可以在明确边界上停止、升级并从 checkpoint 恢复。
这样做改变了恢复问题:系统不再需要在一个已经部分变化的运行时中正确卸载和替换组件,只需要从已提交的状态构造一个干净的新运行时。
后者通常更容易推理、测试和回放。进程退出还会自然清理内存对象、listener、timer 和文件描述符,不必要求应用框架为每种资源重新实现一套完美的撤销语义。
当然,外部副作用仍然需要幂等、日志和补偿机制。但 Cordis 式进程内生命周期同样不能自动撤销已经发出的消息、删除的文件或调用过的外部 API。无论选择哪条路线,真正长期的状态都必须在运行时之外得到管理。
Agent 让外围 Glue 更便宜
过去引入通用框架,部分原因是人不愿意反复编写脚本、Adapter 和 Wiring。Agent 很擅长生成和维护这些机械代码,也可以在修改后重建、测试并重新启动系统。
这降低了显式代码和局部专用化的成本,却没有消除动态框架的理解成本。既然两边的经济性发生了变化,为了减少少量重复而提前引入复杂的运行时,未必仍然划算。
简单仍然可以 Composable
Pi 没有放弃组合,而是使用更低层、更通用的协议组合:
标准输入输出
文件
命令行参数
退出码
环境变量
独立进程
Unix 早已证明,Worse is Better 和 composability 并不矛盾。DSH 通过统一框架获得组合性;Pi 通过操作系统和公开协议获得组合性。后者不够完整,却通常更透明,也更容易替换其中任何一部分。
DSH 的价值与举证责任
我并不认为 DSH 选错了方向。它要构建的是一个开放的 Harness 平台,而不只是固定功能的 Coding Agent。多种模型、工具、沙箱、会话实现和产品形态,确实需要比 Pi 更强的装配能力。对于必须不停机、组件需要独立发布、运行中经常替换能力的系统,完整生命周期也可能值得支付成本。
但动态性不应该因为未来可能需要就成为默认。DSH 需要用真实使用证明:
- 动态替换是常见需求,而不只是演示;
- Agent 增加和修改能力的总成本确实下降;
- Plugin Graph 比直接代码更容易发现和理解;
- 多次加载、卸载和失败恢复后没有残留状态;
- Framework 引入的调试成本小于它消除的组合成本。
在这些问题得到回答之前,我会把 DSH 看作一个值得关注的实验,而不是 Agent Harness 必然的终局。
默认简单,按需求增加结构
Pi 用外部组合保护核心的简单;DSH 用统一运行时保护组合世界的完整。两种设计都成立,但不应该拥有相同的默认优先级。
我更看好 Pi:保持核心小,把长期记忆放到运行时之外,依靠文件、CLI、Shell、独立进程和可选扩展完成组合。这让 Agent 和人类面对同一套更直接的系统,也让运行时更容易停止、理解、修改和重建。
DSH 最值得肯定的地方,是它认真处理了动态组合、依赖和生命周期这些困难问题。但复杂性应该由已经发生的需求买单,而不是由一个完整世界的想象提前买单。
在动态运行时被证明不可缺少之前,简单应该是默认选择。