菜单
积墨AI

积墨AI

DeepSeek Harness 的核心引擎:Cordis 插件框架深度解析

引言

在 AI Agent 的落地实践中,框架的灵活性与可扩展性往往决定了系统的上限。DeepSeek Harness(以下简称 DSH)之所以能够实现「一切皆插件」的架构设计,很大程度上归功于其底层运行的 Cordis 框架。

Cordis 最初诞生于第三方聊天机器人领域,随后被 DeepSeek 引入作为整个 Agent 运行时的基础设施。本文将深入剖析 Cordis 的设计哲学、核心机制,以及它在 DSH 中的实际应用。

插件系统为何需要框架

四个核心问题

当我们构建一个可扩展的系统时,模块化只能解决「代码如何组织」的问题,却无法应对以下挑战:

安装:新功能如何被安全地「接」入现有系统?

配置:同一功能在不同部署环境下需要不同参数,这些配置应当写在哪里?

卸载:功能下线时,它创建的定时器、事件监听器、网络连接等资源由谁负责清理?清理不干净就会导致内存泄漏。

协作:功能 A 依赖功能 B 的能力,但 B 可能尚未启动或后续会被替换,A 应当如何优雅应对?

Cordis 的设计者将「卸载」与「协作」这两件事从「插件作者的自觉」提升为「框架级保证」,从根本上消除了插件开发的隐患。

元框架的定位

Cordis 并不是一个面向终端的框架,而是一个元框架(meta-framework)。它规定了「副作用如何组合、依赖如何解析」,但不预设任何业务领域。这种设计使其既可以支撑聊天机器人,也能够驱动 Agent 运行时。

论文《A Programming Paradigm for Spatiotemporal Composability》将 Cordis 的机制形式化,提供了完整的定义、定理与证明,使其从「好用的工具」升格为「被理论验证的范式」。

Cordis 的五大核心机制

1. 插件:三种形态

Cordis 插件支持三种实现形态:

// 函数形态(最常见)
export function apply(ctx: Context) {}

// 对象形态
export const objectPlugin = {
  name: 'object-plugin',
  apply(ctx: Context) {},
}

// 类形态(需要对外提供服务时使用)
export class MyService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'myService')
  }
}

这三种形态在 DSH 中都有广泛应用:工具插件、适配器插件、面板插件无一例外。

2. 上下文(Context):插件树与层级管理

在 Cordis 中,ctx(上下文)是开发者打交道的主要对象。它既是操作入口,也是服务容器。

export function apply(ctx: Context) {
  ctx.on('some/event', handler)       // 监听事件(卸载时自动移除)
  ctx.effect(() => { /* ... */ })     // 注册副作用(卸载时自动回滚)
  ctx.plugin(childPlugin)             // 挂载子插件(随父插件卸载)
  ctx.get('someService')               // 读取服务
  ctx.provide('someValue', 42)        // 提供服务
}

ctx.plugin(child) 并不是简单的注册操作,而是派生出一个子上下文。由此,插件不再平铺排列,而形成一棵层级树:

  • 子上下文继承父上下文的所有能力
  • 父插件卸载时,所有子插件递归卸载
  • 子插件卸载时,不影响兄弟和父级

这种树形结构是 Cordis 生命周期语义的骨架。

3. Fiber:插件生命周期管理

Cordis 为每个已加载的插件实例维护一个 fiber(纤维),这是一个状态机:

  • PENDING:已声明,但依赖服务尚未就绪
  • LOADING / ACTIVE:加载中或已激活
  • FAILED:加载异常或配置校验失败
  • UNLOADING / DISPOSED:清理中或已拆除

无论插件因配置修改、热重载还是显式调用而卸载,清理工作都是自动完成的。在 DSH 中,cordis_inspect 工具巡检的就是每个 fiber 的状态。

4. Effect:可逆副作用

这是 Cordis 与传统依赖注入容器最本质的区别。

ctx.effect(() => {
  const conn = createConnection()
  return () => conn.close()  // 清理函数
})

Effect 的主体在插件加载时执行,返回的清理函数在卸载时执行。无论插件因何种原因被卸载,Cordis 都会自动回滚所有注册的副作用——定时器取消、监听器移除、连接关闭,开发者无需手动处理。

这带来了几个关键特性:

  • 热重载(HMR):插件可以在运行时安全替换
  • 故障自动恢复:出错的插件被卸载后,相关资源自动清理
  • 测试隔离:每个测试用例拥有独立的插件实例

在 DSH 中,「改配置不重启」正是基于这一机制:修改配置 → 旧插件卸载(所有 effect 回滚)→ 新插件加载,整个过程进程无需重启。

5. 服务与注入:响应式依赖

将能力挂载到 ctx 上供其他插件使用,这就是 Service(服务)

export class GreeterService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'greeter')  // 注册服务
  }
  greet(who: string) {
    return `Hello, ${who}!`
  }
}

消费方通过 inject 声明依赖:

export const inject = ['greeter']

export function apply(ctx: Context) {
  console.log(ctx.greeter.greet('world'))
}

inject 的语义是:插件保持 PENDING 状态,直到所列服务全部就绪。配置文件的顺序无关紧要,启动顺序由依赖关系决定。

与传统 DI 容器的核心差异在于:

  • 传统 DI 假设「服务一旦绑定就会一直存在」
  • Cordis 的假设是「服务可以随时出现,也可以随时消失」

在 Agent 场景中,这是常态——LLM 被限流、MCP 服务器崩溃、文件 watcher 被系统杀死。Cordis 的处理是:提供方卸载时,所有依赖它的插件自动卸载;新提供方就绪后,依赖方自动重载。依赖方无需编写任何重连代码。

事件系统:解耦的通信

事件系统适合「喊一嗓子」而不关心谁在听的场景:

ctx.on('stats/report', (name, count) => {
  // 监听,卸载时自动移除
})
ctx.emit('stats/report', 'tool_call', 42)

Cordis 支持多种分发模式,其中 DSH 最常用的是 waterfall(瀑布流)模式,本质是将 Koa/Express 的中间件机制搬进事件系统:

ctx.on('some/decision', async (input, next) => {
  if (!hasPermission(input)) {
    return { denied: true }  // 不调 next() = 否决
  }
  return next()  // 调 next() = 放行
})

多个互不相识的插件就这样组成一条决策链。在 DSH 中,工具执行管道(tools/pre-execute → tools/execute → tools/post-execute)就是一条 waterfall 链。

声明式配置:配置即程序

cordis.yml 体现了「配置即组合」的思想:

- id: greeter
  name: './greeter.ts'
- id: consumer
  name: './consumer.ts'
  disabled: true  # 保留但暂不挂载

其中 id 字段至关重要:

  • 不带 id:每次配置读取都获得新 id,编辑配置会被视为「先删后加」
  • 带 id:支持精准增量更新,改一行配置只会影响对应插件

此外,支持 Schema 校验确保插件在配置不完整时不会半启动,还支持 !!js 表达式在依赖就绪后求值。

在 DeepSeek Harness 中的实践

启动架构

DSH 的启动仅需约二十行代码:

async function boot(configPath, patches) {
  const ctx = new Context()
  ctx.provide('dshHomePath', dshHomePath)
  await ctx.plugin(Loader)
  await mountRootInclude(ctx, configPath, patches)
  await ctx.get('loader')?.await()
  return ctx
}

根 Context 只做引导工作,其余一切来自配置树。

Profile 与 Bundle 机制

DSH 引入了 Profile 概念,允许将应用拆分成可叠加的层。每个 Profile 包含 manifest 和用户自定义的 cordis.patch.yml

Bundle(组合包) 是一个 npm 包,声明了要一次插入的多个插件。核心组合包 @deepseek-ai/dsh-base 正是通过这种方式,将数十个插件一次性注入空根。

这种设计使得部署方可以无需修改源码,只需在自己的 patch 层覆盖配置即可改变默认行为。

工具流水线

在 DSH 中,Agent 的每项能力本质上都是一个 Cordis 插件:

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet the named person.',
    parameters: {
      name: { type: 'string', required: true }
    },
    async execute(args) {
      return `Hello, ${args.name}!`
    }
  }))
}

ctx.tools.register() 注册即为 effect,插件卸载时工具自动注销,无需手动处理。

自指工具集

DSH 最具特色的包是 @deepseek-ai/dsh-tool-cordis,它提供五个让 Agent 检查并改装自己运行时的工具:

  • cordis_inspect:巡检服务状态、fiber 状态、工具注册表
  • cordis_define:现场定义小插件包
  • cordis_run:在沙箱中执行动态包
  • cordis_stop / cordis_undefine:卸载动态包

这使得 Agent 可以检查自己的运行环境、现场编写并运行动态插件、用完再卸载,全程不动配置文件、不装 npm 包、不重启进程。这正是「可进化 Agent」的雏形。

扩展槽位一览

DSH 的扩展点不是固定的 API 列表,而是一张服务注册表。以下为主要槽位类别:

类别 槽位 用途 可替换提供方
执行 shell Bash / 沙箱 / PowerShell bash-local, bash-sandbox, pwsh-local
执行 codeRuntime 代码执行 code-runtime-worker
模型 llm LLM 适配器 llm-deepseek, llm-pi-ai
智能 agents / agentLoop Agent 注册与循环 agent-loop
数据 sessions / storage 会话与存储 session-persistence-jsonl, storage-sqlite
环境 fs / web 文件系统与网络 fs-local, fs-sandbox, web-fetch-http
治理 tools / approval 工具注册与审批管道 -
前端 slots / theme UI 槽位 dsh-client-ui-* 系列

这种「Service Definition - Provider - Consumer」三层分离的设计,使得每项能力都是一条「接缝」,两侧可以独立演进。

插件生态的想象空间

基于 Cordis 的设计理念,DSH 插件生态已展现出丰富的可能性:

能力扩展:数据库查询、浏览器自动化、Docker 控制、MCP 客户端、Git 操作等工具插件

记忆系统:有界分层跨会话记忆、带审批的可审计记忆

多智能体协作:Agent 团队、跨会话消息、聊天记录导入

自进化能力:会话内热挂载/卸载持久化插件,从轨迹沉淀可回滚的运行时状态

更令人期待的是「会写插件的插件」——利用 ctx.loader.create() 在运行时动态挂载、更新、移除其他配置条目,Agent 可以生成自己的工具并形成闭环:生成 → 沙箱运行 → 观测结果 → 保留或卸载。

结语

Cordis 通过可逆副作用解决时间维度的组合问题,通过响应式依赖解决空间维度的组合问题,两个维度相互协同:coeffect 操作本身就是 effect,而 effect 可逆。

这种设计将「卸载」与「协作」从开发者的责任变为框架的结构保证,使得运行时动态增删组件不再是危险的冒险,而是安全可控的默认行为。对于构建可进化、可扩展的 AI Agent 系统而言,这无疑是一条值得深入探索的技术路径。

#Cordis#插件框架#DeepSeek Harness#可逆副作用#Agent运行时#effect/coeffect
分享文章

相关文章推荐

试用咨询
企业微信二维码

扫码添加企业微信