DeepSeek Harness 独特的地方,不是它能让模型写代码、跑命令、调工具,而是它几乎没有不能换的“内核”。模型可以换,工具可以换,沙箱可以换,会话存储可以换,甚至连驱动模型一轮轮思考和干活的 Agent Loop,也只是一个可以热替换的插件。这听起来有点抽象。可以把传统软件想成一张录好的 CD:所有乐器声轨在发布时就固定了,播放中途不能换小提琴手,也不能突然加一段吉他。DeepSeek Harness 更像一场永不落幕的现场演出:乐手可以在曲子进行中换人,新的声部可以中途加入,旧的声部可以悄悄退场,听众甚至不会感到中断。更彻底的是,连指挥本人也可以在演出中被替换。这不是普通的“支持插件”,而是把热插拔从一种开发者约定,变成了运行时机制:系统可以在不重启的情况下加载、卸载和替换任意部件,而且最终状态仍然可预测。发布没几天,为什么已经有人给它做宠物?
去 GitHub 的 dsh-plugin 话题页逛一圈,会看到一种很早期、很热闹的生态感。项目当然还谈不上整齐,有些是正经插件,有些是外壳、预设、技能包或实验作品,但这种“什么都有人往上接”的状态,恰恰说明大家已经把它当成一块可以改装的底座了。- 让 Agent 更好看、更好用:有人给 Web UI 加任务看板、Git 图、实时 token 统计、皮肤中心和桌面宠物,也有人专门做独特的 TUI 部件,让命令行里的 Agent 不再只是一个闪烁的光标。
- 把 Agent 接进更大的工作台:有人让 Agent 生成原型、幻灯片、架构图和视频,有人把提示词送到实时画布里生成 UI,还有人尝试把它接进设计工具和协作工具。
- 给 Agent 补长期能力:桌面端可以是插件,长期记忆可以是插件,启动 preset 可以是插件,甚至把某个人的经验、语气和工作方式沉淀成 Skill,也可以被包装成插件。
这里面当然有 DeepSeek 自身影响力的因素。关注度会带来第一批围观者,也会让项目在发布初期迅速被看见。但这种热度不会自动变成插件,真正让社区能立刻动手的,是 DeepSeek Harness 从第一天就把扩展点摆到了台面上:UI 可以加,工具可以加,记忆可以换,沙箱可以换,连桌面和 Agent Loop 都不是禁区。所以更准确地说,DeepSeek 的影响力负责把门打开,插件化负责让走进来的人不必都挤在同一条官方贡献路径上。有人补能力,有人改外观,有人做自己的工作台,也有人玩点怪东西。它们未必都会成功,但可以并行生长、快速试错。这种“大家一起往前跑”的速度,才是插件框架真正可怕的地方。插件系统为什么这么难?
插件系统听起来一点都不新鲜。IDE 有插件,浏览器有扩展,编辑器有包管理器,聊天机器人也有第三方适配器。可只要你真的做过插件生态,就会发现问题远不是“暴露几个 API”那么简单。插件加载时,通常不会只导入一个函数,它可能注册事件监听器、占用一个端口、修改配置、启动定时器、创建数据库表,也可能依赖另一个插件提供的数据库连接、消息队列或账号系统。于是麻烦来了:插件运行到一半被卸载时,它做过的这些事,谁来负责撤销?少删一个监听器,插件走了系统还在响应它的事件;定时器忘了关,它可能继续访问已经不存在的对象;如果另一个插件正在使用它提供的服务,直接把它拔走,就会留下悬空引用和难以复现的错误。VSCode 的插件生态已经很成功,但 Cordis 论文对 top 100 扩展的观察仍然说明传统方案的尴尬:大量扩展包含可执行代码,却仍需重启宿主;依赖声明用得很少;跨扩展拿到的对象甚至常常是 any,没什么类型安全。Cordis 把这个难题拆成两个维度:时间上,插件卸载时它造成的影响要能完整撤销;空间上,插件之间的依赖要被清楚表达出来,系统要知道谁在提供能力,谁在等待能力,谁会因为某个能力下线而受影响。对普通桌面软件来说,做不好也许只是让用户重启一下;但对 AI Agent 来说,重启可能意味着中断正在执行的工具、停止流式输出、丢失子 Agent 的交接状态。未来的 Agent 还可能在运行中安装、调整甚至生成自己的扩展,那时候“重启试试”不再是一个体面的答案。Cordis 到底提供了什么?
DeepSeek Harness 的底层不是直接从 Agent 功能开始写的,而是站在一个叫 Cordis 的元框架上。可以把 Cordis 理解成一套“插件操作系统”:它不决定模型说什么,也不直接实现 bash、文件系统或 Web UI,但它负责回答几个更基础的问题:插件怎么启动,怎么注册能力,怎么声明依赖,怎么卸载,怎么在依赖变化时自动休眠和重启,以及多次热替换后为什么不会把状态搞乱。- Context(上下文):一个带类型的服务容器。插件通过ctx.tools、ctx.llm、ctx.sessions这样的稳定名字找服务,而不是直接 import 某个具体实现。
- Plugin(插件):插件通常带一个inject依赖声明和一个apply(ctx)启动函数,也可以是 Service 子类。它需要什么、启动时做什么、卸载时怎么清理,都由框架接管。
- Effect(可逆效果):每次注册操作都要附带 disposer,也就是“将来怎么撤销自己”。
- Fiber(插件实例):每个被加载的插件都是一个 Fiber,有独立状态机,而不是导入后就永远存在的静态模块。
- Reactive Inject(响应式依赖):服务上线就唤醒依赖它的插件,服务下线就让它休眠,服务被替换时它自动重启。
- Typed Events(类型化事件):插件通过事件广播、拦截、并行协作或串行轮询,而不是互相硬调用。
- Confluence(汇合性):只要最终配置相同,不管中间怎么加载、卸载和替换,最终都会到达同一个静止状态。
1. 可逆效果:做了什么,就必须留好“退货小票”
传统插件最容易出问题的地方,是加载和卸载不对称。插件启动时可能注册监听器、启动定时器、添加菜单、占用端口;卸载时却要开发者凭记忆写 cleanup,漏掉一处就会留下幽灵监听器、野定时器或失效配置。Cordis 的思路很朴素:做一件事时,就把怎么撤销这件事一起交给框架。ctx.effect(() => { router.add('/api/hello', handler) return () => router.remove('/api/hello', handler)})
这个返回的函数就是 disposer。框架会像收小票一样把它存起来,插件卸载时按后进先出的顺序执行:后注册的先撤销,先注册的后撤销。这符合依赖关系,也像拆积木要从上面拆,而不是硬抽最下面那块。在 DeepSeek Harness 里,很多操作已经天然是可逆效果:ctx.on('session/event', listener) // 卸载时自动移除监听器ctx.tools.register(myTool) // 卸载时自动注销工具ctx.plugin(childPlugin) // 子插件随父插件一起卸载
这套机制让插件可以安全嵌套。一个大插件加载子插件,子插件再注册监听器和工具;父插件卸载时,框架会沿着注册树反向清理,不需要父插件手动记住“我下面还有谁”。这也是 DeepSeek Harness 能把能力拆成很多小包,却仍然能安全组合的原因。2. Fiber:插件不是文件,而是一个有生命周期的运行实例
Cordis 里的插件实例叫 Fiber。它更像一个正在上班的员工,而不是一个被 import 的文件:依赖没齐就等待,依赖齐了就入职,工作期间提供服务,离开时先交接再清理。- LOADING:依赖齐全,正在执行apply(ctx)。
- ACTIVE:插件正常工作,可以提供服务、监听事件、处理请求。
- UNLOADING:依赖消失或插件被卸载,开始停止服务并执行清理。
- FAILED / DISPOSED:启动失败进入失败状态,彻底清理完成后销毁。
重点在于,框架知道每个插件现在处于哪个阶段。如果插件启动到一半依赖突然消失,框架不会让它停在半初始化状态,而会把已经完成的注册撤销掉,等依赖恢复后再重新启动。卸载也不是直接拔电源。Cordis 会先把这个插件从“服务提供者列表”里移除,让依赖它的消费者先安全卸下,再执行它自己的 disposer。顺序对了,才不会出现“提供者已经消失,消费者还拿着旧引用调用”的错误。3. 响应式依赖:像智能公告板一样协作
可逆效果解决“怎么干净离开”,响应式依赖解决“怎么安全合作”。传统依赖注入通常发生在启动阶段:先创建数据库,再创建日志器,最后创建业务服务,启动顺序要靠人安排。如果业务服务启动时数据库还没好,它只能报错或自己重试;如果数据库运行中被替换,已经拿到旧连接的服务往往也不知道。Cordis 更像一块智能公告板。提供方把服务贴上去,消费方只声明自己需要什么。// 提供服务ctx.set('database', connection)// 声明依赖export default { inject: ['database'], apply(ctx) { // 到这里时,ctx.database 一定可用 }}
当公告板变化时,框架自动处理后续动作:依赖从无到有,就唤醒等待中的 Fiber;依赖从有到无,就让它卸载或休眠;旧服务被新服务替换,消费者先卸下,再用新服务重新激活。插件之间不需要知道彼此的启动顺序,只需要认稳定的服务名。DeepSeek Harness 把这个模式发展成能力 Seam。一个 Seam 就像标准插座:定义者规定插座形状,提供者负责接电,消费者只管用电器,不关心电来自哪里。以 Shell 为例,dsh-shell 定义 ctx.shell,dsh-bash-local、dsh-bash-sandbox 或远程执行器提供实现,dsh-tool-bash 只把 bash 能力暴露给模型。消费者只知道自己需要 shell,从不知道命令跑在本机、沙箱还是远程机器上。这也是它扩展性强的关键。文件系统和进程执行器共享同一个“执行世界”,只要把它们指向远程沙箱,Bash、终端、LSP 和文件读写就会一起搬过去,不需要为每个后端做一套分叉版本。Cordis 还支持服务隔离和拦截。隔离可以让同一个服务键在不同作用域里解析到不同值,比如某个 Agent 用测试数据库,另一个 Agent 用生产数据库;拦截可以在不修改提供者代码的情况下附加元数据或策略。这样插件既能共享同一套接口,又能按 Agent、会话或配置拥有不同行为。4. 类型化事件:插件之间怎么“打招呼”
插件之间如果总是直接互相调用,很快又会耦合死。Cordis 提供类型化事件,让插件通过固定事件名协作。DeepSeek Harness 里大量扩展点都建立在这套机制上。- emit(广播):事情发生了,通知所有关心者,不等待返回值。适合 Agent 状态变化这类通知。
- waterfall(瀑布式拦截):监听器按顺序执行,可以调用next()交给下游,也可以直接短路。适合权限检查、压缩策略、工具执行前后处理。
- parallel(并行):所有监听器同时执行,全部完成后再继续。适合多个存储后端同时写入会话日志。
- serial(串行轮询):监听器按顺序被询问,第一个能给出结果的胜出。适合终止策略、后端选择这类场景。
这也是 DeepSeek Harness 扩展起来自然的原因。想加审批策略,就挂到工具执行前的瀑布事件上;想观察会话,就监听会话事件;想加持久化后端,就参与 flush 事件。插件不需要改核心循环,只需要在正确的事件点注册行为。5. 汇合性(Confluence):热替换为什么仍然可预测
如果插件可以随时加载、卸载和替换,最大的疑问是:操作顺序不同,最终状态会不会不同?Cordis 的答案是汇合性:只要最终配置相同,任意合法步骤序列最终都会汇合到同一个静止状态。A 提供数据库,B 提供日志器,C 依赖 A 和 B。你可以按 A → B → C 的顺序启动;也可以先启动 C,让它等待,再启动 A 和旧版 B,最后把旧版 B 热替换成新版 B′。第二条路中间会经历等待、启动、休眠、重启,但只要最终配置是 A、B′、C,最终状态就和直接加载 A、B′、C 一样。这个保证对长期运行的 Agent 特别重要。它意味着热替换不是“先改坏再说”,而是一种可以被推理的系统变化:即使 Agent 在运行中安装新插件、替换模型适配器或升级策略,只要最终配置确定,系统应该长成什么样就是确定的。把这些能力合在一起,Cordis 给 DeepSeek Harness 的不是几个 API,而是一种承诺:插件可以来,也可以走;依赖可以暂时缺失,也可以被替换;事件可以被观察和拦截;但无论怎么变化,系统都有办法回到一个干净、可预测的静止状态。理解了这一点,再看“一切皆插件”,就不会觉得它只是一句口号了。插件化会怎样改变生态?
很多人理解插件化,只看到“功能可以后装”。这当然没错,但还不够。真正的变化是:软件的生产边界被重新划分了。在一个非插件化的单体系统里,几乎所有功能都要挤进同一条发布轨道。社区想到一个好点子,要等核心团队接受;企业想接内部系统,常常得维护自己的 fork;实验性功能怕影响主程序,可能迟迟合不进去。时间久了,核心项目越来越重,外部贡献者也越来越难参与。插件化把这条大轨道拆成了许多小轨道。核心框架负责稳定的事件、服务名和生命周期规则;插件作者在这些规则之上独立发布、独立升级、独立承担质量责任。做 Web UI 的人不必懂模型适配器内部怎么写,做记忆层的人不必重写 Agent Loop,做设计生成的人也不必 fork 整个会话系统。这会产生一种“乘法效应”。单独看,皮肤只是皮肤,记忆只是记忆,架构图插件只是多了一种文档输出;但它们通过同一套上下文、事件和 preset 机制组合起来,就会变成完全不同的产品。你可以把它装成一个带像素宠物的个人助手,也可以装成一个带 Git 面板、沙箱和设计插件的工程工作台,还可以装成一个接了私有知识库、审批策略和审计日志的企业 Agent 平台。对 AI Agent 来说,这一点尤其重要。Agent 的能力不是一排固定按钮,它会调用模型、执行代码、读写文件、派遣子任务,还会围绕一个目标持续工作。如果这些能力都必须由官方一次性写死,生态很快就会被限制在少数预设场景里。插件化之后,社区可以换模型供应商,接不同沙箱,加自己的压缩策略、审批策略、持久化后端和行业预设。框架提供的是“怎样接入”的契约,而不是“只能这样做”的剧本。当然,插件化不是银弹。生态越繁荣,供应链安全、权限边界、事件顺序和插件质量就越重要。一个能监听所有会话事件的插件,理论上可能泄露敏感数据;一个排在前面的策略插件,也可能改变后续所有模型请求。可逆效果和汇合性解决的是“能不能安全装卸”的问题,不能替代权限模型、审计机制和插件市场治理。但也正因为插件拥有真实能力,这些边界才更需要被认真设计。最后:“一切皆插件”到底意味着什么
DeepSeek Harness 的设计哲学,是把变化视为常态,而不是异常。插件不是系统启动后才挂上去的装饰品,而是产品本身的组成方式。所谓“一切皆插件”,不是说所有功能都放进一个叫 plugins 的目录,而是说系统的每一部分都遵守同一套规则:注册必须可逆,依赖必须声明,服务必须通过稳定的名字发现,配置叠加后的结果必须可预测。模型、工具、沙箱、会话、UI、记忆和 Agent Loop 都不是特权阶层,它们都是插件树上的节点。也正因为如此,社区才能在官方主轨道之外并行生长:有人补能力,有人改外观,有人做行业 preset,有人做怪趣实验。一个能长期演化的 Agent 系统,靠的往往不是第一版功能有多全,而是它给后来者留下了多少可靠的接缝。