DeepSeek Harness:Cordis 如何让插件可卸载、可依赖、可重组

Cordis 如何让插件可卸载、可依赖、可重组

把一个工具塞进注册表并不难。真正麻烦的是它离开以后发生什么。

假设一个 Workspace 插件注册了文件服务、监听器、Prompt 片段和一个定时任务。用户切换项目时,插件被卸载:监听器有没有解除?Prompt 片段会不会重复?依赖文件服务的工具应该立即消失,还是继续拿着已经失效的引用?如果配置热更新再次装载同一个插件,系统里会不会留下两份副作用?

这才是 DeepSeek Harness 选择 Cordis 的关键。首篇文章讨论的是"为什么连 Agent Core 都进入插件图",本篇只回答下一层问题:当插件、服务和依赖会在运行期间出现与消失时,Cordis 用什么机制维持边界?

我的结论是:Cordis 的价值不在于再发明一套依赖注入,而在于把服务依赖和副作用回收都纳入 Context 生命周期。它让"装上能力"和"完整撤销能力"成为同一份插件合同的两面;代价是团队必须把依赖、事件模式、disposer 和最终组合图当作一等工程对象。

普通注册表只回答"有什么",生命周期还要回答"何时有效"

最简单的插件系统通常有一个 Map:插件启动时注册工具,主程序按名称查找,进程退出时操作系统回收全部资源。这种模式在静态、小规模应用里完全够用。

但 Agent Runtime 的能力边界经常不是静态的:

  • 某个 Agent 或 Workspace 只在自己的作用域里拥有一组工具;
  • 文件、Shell、模型或 Web Provider 可能随配置和部署环境变化;
  • Prompt 片段、工具 Schema 和事件监听器要随插件一起装卸;
  • 热更新或产品 Patch 会重建一部分组合,而不是重启整个宿主。

这时,registry.set() 只能说明某个对象现在存在,不能说明谁创建了它、谁依赖它、何时失效、销毁时需要撤销哪些动作。把这些问题散落在每个插件的启动和停止函数里,会让清理顺序与依赖顺序逐渐变成隐含知识。

Cordis 试图把这种隐含知识显式化。固定版本的 DeepSeek Harness Cordis Primer 将机制压缩成五个概念:Plugin、Context、inject、typed events 和 reversible effects。它们不是五个并列名词,而是一条生命周期链。

Context:服务仓库,也是插件作用域

Cordis 的 Context 首先是服务仓库。服务占用稳定的 ctx.<key>,例如 ctx.toolsctx.llmctx.sessions;消费者通过 key 使用能力,而不是直接导入某个具体实现。

但如果只看到"按 key 取服务",就会把 Context 误解成普通容器。它还限定插件运行的作用域:插件在这个 Context 中注册服务、事件和其他副作用,这些动作可以随着作用域销毁而回收。

这让一个能力至少有两个坐标:

  1. 空间坐标:它在哪个 Context 中可见,哪些消费者能访问;
  2. 时间坐标:它从何时开始有效,随哪个插件或子作用域一起结束。

DeepSeek Harness 的固定架构文档因此强调,模型适配器、工具注册表、Session Log、Agent Loop 都是共享 Context 中的插件贡献。所谓"没有特权核心",并不是核心不存在,而是核心能力也要遵守相同的作用域和生命周期规则。

inject:把启动顺序改写成依赖条件

普通启动脚本喜欢写成固定顺序:先数据库,再工具,再 Agent Loop。顺序一旦变化,消费者可能在 Provider 尚未就绪时启动;为了修补问题,代码里又会出现更多等待、重试和条件分支。

Cordis 让插件通过 inject 声明所需服务。固定 Primer 的表述很明确:声明了必需服务的插件要等这些服务存在后才激活。于是,装载条件来自服务需求,而不是开发者手工维护的一串启动序号。

可以把它理解为:

text 复制代码
Provider 出现
  -> 所需 service 可用
  -> 满足 inject 的 Consumer 激活
  -> Consumer 注册自己的 effects

Provider / 上层作用域消失
  -> Consumer 生命周期结束
  -> Consumer effects 回收

这个变化很重要。Provider/Consumer 不再只是静态架构图上的箭头,而是能影响插件何时存在的运行条件。

但"声明依赖"不等于"动态变化天然安全"。多个 Provider 同时变化时的顺序、消费者持有的外部资源、正在执行的请求以及失败恢复,都仍需要实现和测试。Cordis 提供的是协调语义,不是可靠性证明。

effect:注册动作必须带着撤销方法

插件最常见的泄漏不是内存本身,而是忘记撤销注册:事件监听器仍在接收消息,Prompt 片段被重复拼接,工具 Schema 留在目录里,定时任务继续运行。

Cordis Primer 的实践规则是:每个注册都应有 disposer。插件可以通过 ctx.effect() 返回清理函数,也可以使用已经处理清理的 Cordis helper。若清理顺序重要,相关工作应放在同一个 effect 中,让销毁按预期次序展开。

因此,effect 不是"执行一次函数"的花哨名字,而是一份双向合同:

text 复制代码
mount:   注册服务 / 监听事件 / 增加 Prompt / 启动资源
dispose: 撤销服务 / 解除监听 / 移除 Prompt / 释放资源

这也是"Everything is a Plugin"能够进入 Agent Core 的必要条件。如果 Agent Loop、Session 或工具目录只能装载、不能撤销,那么动态组合最终仍会退化为"一次启动、永久存在"的静态宿主。

这里同样不能过度推断。框架要求 disposer,不代表所有插件都写对了;本篇没有系统级反复装卸、故障注入或长时间资源监测,不能把可逆 effect 写成"已经验证无泄漏"。

typed events:事件模式本身也是接口合同

插件解耦以后,大量协调会通过事件完成。固定 Primer 区分 emitwaterfallparallelserial 四种 dispatch mode;它们是否等待、是否有返回值、按什么方式传播,都属于事件公开合同。

尤其容易误用的是 waterfall。它不是简单的"按顺序通知所有监听器",而是 around-middleware:监听器收到 next(),可以委托给后续监听器,也可以直接返回并短路。只想观察或补充信息的监听器必须继续委托;拥有单一决策权的策略监听器才适合截断。

这意味着,事件名相同远远不够。替换一个 Provider 或策略插件时,还要保证:

  • 监听器知道自己是观察、包装、并行处理还是顺序决策;
  • 应当委托的 waterfall 不会误短路;
  • 返回值、错误和副作用顺序与消费者预期一致;
  • 卸载时监听器会随 effect 一起解除。

所以事件模式不是实现细节,而是能力契约的一部分。

一条完整 seam 需要三个角色

DeepSeek Harness 的固定架构把可替换能力接缝拆成三个角色:

  1. Service Definition:声明稳定接口与 Context key;
  2. Provider:提供具体实现;
  3. Consumer:使用能力,常见形态是面向模型的 Tool 或上层 Runtime 组件。

例如,文件系统接缝不能只看 ctx.fs 的类型。还要看本地、远端或 Sandbox Provider 怎样实现它,以及文件工具、LSP、Shell 等消费者依赖哪些错误、安全和路径语义。

官方生成的 Capability Seams 图列出了大量服务与包之间的登记关系。这张图适合回答"谁声明、谁提供、谁直接消费",却不能单独回答"替换后是否兼容"。一个新 Provider 即使通过类型检查,也可能在流式事件、错误分类、权限策略或资源释放上破坏消费者假设。

因此,判断 seam 是否成立,至少要检查四层:接口能否对上、事件模式是否一致、生命周期能否回收、行为语义是否兼容。前三项是结构条件,第四项仍需要契约测试和真实运行证据。

Context、inject、effect 如何形成生命周期图

把前面的机制合在一起,可以得到一张比"插件列表"更有用的检查图:

text 复制代码
Context 创建作用域
  -> Provider 插件挂载
  -> service 出现在 ctx.<key>
  -> inject 条件满足
  -> Consumer 插件激活
  -> effect 注册事件 / Prompt / Tool / 子资源
  -> typed events 按合同协调运行
  -> 配置变化、Provider 消失或作用域销毁
  -> Consumer 停止并回收 effects
  -> Provider effects 回收
  -> Context 释放

这张图的关键不在箭头多,而在每个正向动作都应该找到反向路径:谁让它出现,什么条件让它有效,谁负责撤销,撤销后消费者如何停止。

如果团队无法回答这些问题,所谓动态插件化就只完成了"装上",没有完成"生命周期"。

什么时候值得做成 seam

不是每个函数都需要 Provider。把所有细节都抽象成 Context service,会把调用链变成庞大的组合图,增加调试、配置和迁移成本。

一个能力值得成为 seam,通常至少满足一项:

  • 不同部署需要替换实现,例如本地与远端文件系统;
  • 能力需要独立装卸或只在局部 Agent/Workspace 生效;
  • 多个消费者需要共享稳定边界,但不能依赖具体包;
  • 生命周期、权限或资源所有权需要由单独 Provider 管理;
  • 测试需要装配更小的能力图或故障 Provider。

反过来,如果实现固定、调用者单一、生命周期与宿主完全相同,普通函数、显式对象或构造器注入可能更清楚。抽象的价值来自真实变化,不来自"插件化"这个标签。

团队采用前的生命周期检查表

检查对象 必须回答的问题 当前公开证据能证明什么
Context 能力在哪个作用域可见,谁拥有它 固定文档给出服务仓库与作用域模型
inject Consumer 依赖哪些 service,缺失时何时停止 固定 Primer 给出声明依赖与等待激活语义
effect 每项注册的 disposer 在哪里,清理顺序怎样 固定 Primer 要求 disposer 与可逆注册
event dispatch mode、委托、短路和返回值是什么 固定文档给出四种事件模式及 waterfall 规则
seam 定义、Provider、Consumer 是否齐全 固定架构和生成能力图可以核对角色关系
行为兼容 错误、流式、安全与资源语义是否一致 不能靠能力图证明,需要契约测试
系统可靠性 反复装卸、并发变化、长时间运行是否稳定 当前未验证,需要故障注入和资源监测

这张表是本篇唯一主要产物。它刻意把"源码已经设计出来的机制"和"采用者还必须验证的行为"分开,避免从架构图直接跳到生产结论。

结论

Cordis 让 DeepSeek Harness 的插件不只是"可以注册",而是拥有明确的存在范围、依赖条件和回收路径。Context 提供作用域,inject 表达激活条件,effect 把注册与撤销绑定,typed events 规定协调方式,Service Definition、Provider、Consumer 则组成完整能力接缝。

这套机制确实让 Agent Core 更容易被拆开和重组,但没有消灭复杂度。复杂度从手写启动顺序和核心分支,转移到了依赖图、事件合同、disposer、配置与诊断。对于多产品、多部署、局部能力和动态生命周期,这种转移可能值得;对于固定、简单的应用,普通依赖注入仍可能更便宜。

现阶段最准确的评价不是"Cordis 已经证明了动态 Agent Runtime 更可靠",而是:它给出了一套可以被源码检查、也必须被故障测试的生命周期合同。

参考资料

  1. DeepSeek Harness 固定 Commit Cordis Primer:github.com/deepseek-ai...
  2. DeepSeek Harness 固定 Commit 架构文档:github.com/deepseek-ai...
  3. DeepSeek Harness 固定 Commit Capability Seams:github.com/deepseek-ai...
  4. Cordis 官方仓库:github.com/cordiverse/...
  5. DeepSeek Harness Python SDK(动态版本边界):pypi.org/project/dee...

证据与推导边界

  • Context、inject、typed events、effect/disposer:固定 Commit 官方文档事实。
  • Service Definition、Provider、Consumer:固定架构与生成能力图事实。
  • "复杂度转移到组合、契约和诊断":基于上述机制的作者工程分析。
  • seam 适用条件与生命周期检查表:作者建议,不是 DeepSeek 官方采用承诺。
  • 反复装卸、并发变化、资源泄漏、真实模型 E2E 与生产稳定性:尚未验证,不作结论。
相关推荐
叠层归一研究院1 小时前
如何用程序搭建一个 AGI 种子系统(三):生长如何对接物理与数学宇宙
人工智能·python·算法·机器学习·transformer·agi
兴趣使然黄小黄1 小时前
【AI-agent】让 AI 输出可依赖:LLM 工程化的四道防线
大数据·人工智能
2501_926978331 小时前
AGI封锁的物理边界:发现模式决定封锁可行性
人工智能·经验分享·笔记·ai写作·agi
tech讯息1 小时前
企业 AI Agent 对接外部服务如何安全集成?—— 多租户业务场景优先选用 WebSocket 方案
人工智能·websocket·安全
过去式的美好1 小时前
阿里云 2 核 2G 服务器搭建 AI 知识库:从 0 到可用(附踩坑实录)
服务器·人工智能·阿里云
阿弱1 小时前
graph-core 的边与命令模式设计
java·后端·agent
薛定谔的悦1 小时前
储能系统CAN通信抽象层解读
人工智能·能源·储能
江畔柳前堤1 小时前
AgentScope 设计与原理全解:从消息原语到分布式智能体工程底座
大数据·人工智能·分布式·目标检测·机器学习·语言模型·架构
leeyi1 小时前
Callback 源码:aspect_inject 切面注入(第87篇-E73)
aigc·agent·ai编程