Cordis:一颗被 DeepSeek Harness 选中的“插件心脏“,让 Agent 能“自己改完,还能收拾干净“| SSP Github Daily
每日开源 · 早间篇
让 Agent 能"自己改完,还能收拾干净"
Cordis:一颗被 DeepSeek Harness 选中的"插件心脏"
第 116 期 · 2026-08-17 · 周一
**免责声明:**本工具依赖境外公开数据源(GitHub、DeepSeek 文档站等),部分平台在中国大陆需合规网络环境。
前天我们写过 DeepSeek Harness(第 113 期)——那个号称"一切皆插件"的 AI Agent 运行时。当时很多人问:这套"插件可热替换"的底座,到底是怎么搭的?
答案就在今天 GitHub 趋势榜第二的 cordiverse/cordis:一个叫 Shigma 的中国开发者维护了四年的 TypeScript 元框架。它最早是聊天机器人 Koishi 的内核,如今被 DeepSeek Harness 直接 vendor 进了 monorepo——同时一篇北大+DeepSeek 联合发表的论文,刚刚给它的设计做了形式化证明。
📇 项目速览
**项目名称:**Cordis
**所属组织:**cordiverse
**作者:**Shigma(Koishi 创始人,现任职 DeepSeek-AI)
**Stars:**4,999+(今日 +720,Trending [#2](javascript:😉)
**技术栈:**TypeScript · ~2000 行核心代码 · Monorepo
**协议:**MIT 开源
**首次提交:**2022-05(v4.0.0-rc.7 与 DeepSeek Harness 同步)
**协效:**DeepSeek Harness 选择 vendor(vendor/cordis)而非另起炉灶
**仓库:**github.com/cordiverse/cordis
🎯 它能解决什么问题?
做插件系统的开发者都有一个共同的噩梦:“能装不能卸”。
你给一个框架装了个日志插件,它注册了全局事件监听、打开了文件句柄、订阅了数据库连接——你想卸的时候发现:事件还在监听、句柄漏了、全局状态被改了。唯一的解决办法?重启整个进程。
这个问题在 AI Agent 时代被放大了无数倍。一个会"自我演化"的 Agent,需要具备三件事:
① 动态加载——能装上新的工具、技能、模型适配器
② 安全卸载——改坏了能回滚,不留垃圾
③ 状态无关性——不管先装 A 还是先装 B,最终系统状态一致
大多数框架做到了第一点。后两点几乎没人做到——直到 Cordis 把它们做到了数学层面。这就是为什么 DeepSeek Harness 选了它,而非自己造一套。
✨ 核心亮点
2000核心行数4年生产验证4000+Koishi 插件2正交维度
① 一句话讲透:时空可组合性(Spatiotemporal Composability)
Cordis 是 2026 年 8 月 13 日和 DeepSeek Harness 一起发布的论文主角。论文把它的核心设计哲学总结为两个正交维度:
· 时间可组合性(Temporal Composability):一个组件被卸载时,它产生的所有副作用能被完整逆转。事件监听、文件句柄、内存分配,全部干净消失。
· 空间可组合性(Spatial Composability):组件之间的依赖关系能声明式表达,运行时响应式管理。B 依赖 A 时,系统会自动保证:B 在 A 后加载、A 停止前卸载。
两者结合产出一个工程奇迹——路径无关性(path independence):系统的最终状态,只取决于"开了哪些插件",跟加载顺序无关。这意味着热重载、热更新完全安全,Agent 想怎么改自己都不会留下烂摊子。
② ctx.effect:可逆副作用的运行时保证
Cordis 最核心的 API 只有一个:ctx.effect()。
它要求所有副作用操作返回一个"disposer"(清理函数)。运行时把这个清理函数存进栈里,插件卸载时按注册的逆序全部执行。这跟 C++ 的 RAII、Rust 的 Drop trait 是同一种思想,但被提升到了运行时层面——意味着不同团队写的第三方插件,也能干干净净地卸载。
// 自定义资源:网络连接export functionapply(ctx) {ctx.effect(() => {const conn = createConnection(‘wss://api.example.com’) conn.connect()// 返回 disposer —— 卸载时框架自动调用return () => conn.close() })}// 不需要手动 removeListener / clearInterval / unregister
对比一下传统 Node.js 插件,光"清理"这件事就要写一坨 finally 块和 removeListener——Cordis 把这一切变成了一个声明。
③ inject:声明式依赖,告别编排噩梦
你写一个工具插件,需要先用数据库服务,再调用 LLM。Cordis 不让你手写初始化顺序——你在插件头上声明:
// 声明:我需要 llm 和 tools 两个服务export constinject = [‘llm’, ‘tools’]export functionapply(ctx) {// 进入这里时,ctx.llm 和 ctx.tools 已保证就绪 ctx.tools.register(‘myTool’, async (input) => {const result = await ctx.llm.chat(input)return result })}
这种"声明意图,框架兜底"的模式,跟 Spring 的依赖注入是同一脉相承的设计哲学——只不过 Cordis 把这件事做到了 TypeScript 元编程级别,体积只有它的几百分之一。
④ 四种事件分发模式,精确表达通信意图
Cordis 的事件系统不是普通的 pub/sub,而是按语义分了四种:
· emit——广播,不等待回调。适用于"观察者"场景。
· waterfall——瀑布式传递,每个监听器可改参数。适用于"拦截 + 包装"。
· parallel——并行扇出。适用于"并发收集结果"。
· serial——串行执行。适用于"必须按序的处理链"。
所有通过 ctx.on() 注册的事件监听,都自动享受"卸载即清除"的待遇——无需手动 removeListener。
判断该用事件还是服务方法有一条原则:拦截与策略用事件,调用稳定能力用服务方法。这条原则让 Agent 在添加新"技能"时,能精确控制它的副作用边界。
⑤ HMR + 事务化配置:插件更新像前端开发一样丝滑
Cordis 附带声明式组件加载器,支持热模块替换(HMR)和配置协调。
Koishi 作者分享过一个真实数据:基于 Cordis 构建的 Koishi 服务三年间经历了无数次插件更新,进程从未重启过。开发体验跟写前端一样——改完代码保存,旧版本自动卸载连带所有副作用一起清理,然后加载新版。
更狠的是事务化加载:配置更新时,Cordis 会尝试原子加载新配置。任何一步失败,整个事务回滚——系统状态保持一致,绝不出现"装了一半"的残局。
对 Agent 而言这意味着:Agent 自我修改的每一步变更,要么全部生效,要么什么也不动。这是把"自演化 Agent 从研究风险变成可工程化"的关键保证。
⑥ 为什么 DeepSeek Harness 非它不可?
DeepSeek Harness 实现"一切皆插件"的关键不是"插件系统",而是插件系统能不能在运行时安全卸载 + 重新组合。他们把 Cordis 直接 vendor 进了 monorepo(vendor/cordis 4.0.0-rc.7),所有包都把它声明为 peerDependency。
Harness 内部的核心子系统,每一个都是 Cordis 插件:
· Session(ctx.sessions)——只追加的日志 + 内存存储
· System Prompt(ctx.systemPrompt)——prompt-section + tool-schema 组装
· Tools(ctx.tools)——作用域工具注册表
· Agent(ctx.agents / ctx.agentLoop)——Agent 接口 + 实时注册表
· LLM(ctx.llm)——消息词法 + 适配器接缝
Harness 自己只剩一个"瘦内核":挂载、卸载、追踪依赖;Agent 实际能力全在上面的插件里。在 Creator 模式下,Agent 甚至能在跑着的时候动态检查插件树、加载或卸载临时插件——这相当于"汽车在高速上给自己换发动机",但通过 ctx.effect 的清理路径,跑完不会有"一地鸡毛"。
⑦ 跟单子式效应系统的本质差异
很多人会把它跟 ZIO、Effect-TS、fp-ts 这类"单子式效应系统"对比。论文作者明确指出:
· ZIO/Effect-TS/fp-ts:要求把程序写进 effect 类型里才能获得追踪
· Effekt/Granule:走编译期静态路线,只覆盖词法固定的作用域
· Cordis:把 effect/coeffect 做成运行时机制,专门处理组件在运行时来来去去的情形
翻译成人话:Cordis 是给"装插件、卸插件"这件事定制的——它不试图取代你写业务代码的范式,只在框架与插件的边界上做文章。
🛠️ 实战场景:从 Chatbot 到 AI Agent,一个内核两种用法
场景一:聊天机器人 Koishi(4,000+ 插件实战验证)
Cordis 的原产地。Koishi 上 4,000+ 社区插件在不同作者手里独立开发,没有任何"主程序协调它们"——唯一的协调就是 Cordis 的运行时机制:依赖图 + 可逆副作用。三年间无数次插件更新,从未重启主进程。这是 Cordis 最重要的实战背书。
场景二:DeepSeek Harness(vendor 进 monorepo)
由崔添翼团队(创始人来自 Jane Street 量化,9 年量化经验)主导的 AI Agent 框架。Cordis 被直接 vendor 进去后,Harness 实现了一个其他框架做不到的事:连 Agent 循环都能换。四种配置 Standard / Code / Minimal / Creator,后者让 Agent 跑着的时候检查自己的插件树。
场景三:自托管 Agent 服务的可热更新部署
你想在生产环境给 Agent 加一个新工具,又不希望停机?用 Cordis 写的服务天然支持热加载。你甚至可以做一个"插件市场",让运营同学通过后台直接挂载/卸载能力。
场景四:多租户 SaaS 的能力切片
Cordis 的"服务隔离"机制可以为特定服务创建隔离上下文。让不同租户的插件互不感知——这是给 B 端 SaaS 写"能力按租户分发"的天然解法。
🚀 上手指南
① 安装(Node.js ≥ 18)
# 核心包npm install cordis# 可选:声明式 loader(支持 HMR)npm install @cordisjs/loader
② 第一个插件(函数式)
// my-plugin.tsimport { Context } from’cordis’exportconstname = 'my-plugin’exportconstinject = [‘tools’]exportfunctionapply(ctx: Context) {// 注册定时器心跳 —— 卸载时自动 clear ctx.effect(() => {const timer = setInterval(() => console.log(‘heartbeat’), 5000)return () =>clearInterval(timer) })}
③ 用类形式提供服务(给其他插件用)
// tools-service.tsimport { Service, type Context } from’cordis’export default classToolServiceextends Service {staticinject = [‘database’]private registry = new Map<string, Function>()constructor(ctx: Context) {super(ctx, ‘tools’)// 同步初始化 }register(name: string, fn: Function) {this.registry.set(name, fn)// 返回 disposer,卸载时自动清理return () =>this.registry.delete(name) }}
④ 启动与插件挂载
// main.tsimport { Context } from’cordis’importToolServicefrom’./tools-service’importmyPluginfrom’./my-plugin’const root = new Context()root.plugin(ToolService) // 先挂服务root.plugin(myPlugin) // 依赖满足后自动挂插件// 之后随时热替换:await root.registry.remove(myPlugin)root.plugin(myPluginV2) // 干净替换,无副作用残留
⑤ 进阶:加载配置文件(cordis.yml)
如果你想用声明式配置管理插件(支持 HMR),用 @cordisjs/loader 即可:
# cordis.ymlinsert: - id: tools-servicename: ./tools-service.ts - id: my-pluginname: ./my-plugin.ts
// loader.tsimport { Loader } from’@cordisjs/loader’const ctx = await Loader.load(‘./cordis.yml’)// 监听文件变化自动 HMRLoader.watch(‘./cordis.yml’, ‘./plugins/*.ts’)
**📚 文档入口:**DeepSeek Harness 文档站专门为 Cordis 开设了 primer 章节(虽然作者独立,但被 DeepSeek 托管),地址:deepseek-harness.github.io/deepseek-harness/reference/cordis-primer
📌 今日总结
Cordis 是个被严重低估的项目。它不做任何炫技的事——只管理插件生命周期、依赖排序、清理函数。但恰恰是这"三件事",是 Agent 在尝试自我演化时失败的地方。
一个不争的事实:DeepSeek 这个级别的公司做 Agent 框架,选了一个 4 年前从聊天机器人里长出来的 2,000 行内核——这件事本身就是对"Agent 生态系统走向"的一次投票。
赢的 harness 不会是工具最多的那个,而是插件生态最易组合的那一个。
💬 **互动话题:**你写过插件系统吗?遇到过"能装不能卸"的痛点吗?聊聊你见过哪些"经典副作用残留"现场?
👇 评论区见 · 我会逐条看
📎 本期 GitHub 仓库:github.com/cordiverse/cordis
📜 MIT 协议开源 · 作者 Shigma · 与 Koishi、DeepSeek Harness 同源
📚 论文:A Programming Paradigm for Spatiotemporal Composability
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)