Cordis 在 DeepSeek Harness 里:一切皆插件如何落地
从 dsh-base、Context 服务、事件域和工具流水线出发,理解 Cordis 如何组织一个可替换的 Agent 运行时。
最终落点:DeepSeek Harness 不是在一个巨型 agent loop 旁边挂几个扩展,而是把模型、工具、会话、Agent 和运行入口都作为 Cordis 插件组合起来。
读懂这件事之后,cordis.patch.yml 不再是一串包名,而是一份可以解释产品能力如何进入运行时的拓扑。
01 / profile 从配置树启动产品
一个运行中的 dsh 是由多层配置组合出来的插件树:bundle 先插入基础行,profile patch 和用户 overlay 再按 id 修改它们。
dsh-base 是每个 profile 的第一层,包含模型适配器、工具、持久化、sandbox、审批策略、设置、凭据和 telemetry 等基础能力。Web 或 headless 运行方式在它之上继续添加自己的组合。
可以先把机器将要启动的树打印出来:
dsh --profile web --dump-config02 / 服务把能力连接成 seam
Harness 中常见的 Context 服务包括:
| 服务 | 负责的能力 | 常见扩展方式 |
|---|---|---|
ctx.tools | 工具注册和执行流水线 | 注册工具、监听 tools/* |
ctx.llm | 消息、流与模型适配器 | 替换 provider、监听 llm/* |
ctx.agents | live Agent 与 agent 事件 | 创建 Agent、接入 agent/* |
ctx.sessions | 持久 session event log | 观察 session/event、派生 UI |
ctx.agentLoop | 默认 Agent driver | 作为可替换插件被组合 |
每个 capability seam 都需要 Service Definition、Provider 和 Consumer 三个角色。只有把三者分开,替换一个 provider 才不会迫使产品整体分叉。
03 / 一个工具插件如何进入真实流水线
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
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 },
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: String(value) }],
},
async execute(args) {
return 'Hello, ' + args.name + '!'
},
}))
}这个插件沿用前面所有概念:inject 等待工具服务,register 的 disposer 绑定到 Fiber,工具结果通过事件流水线可被其他插件观察。
工具不是被 agent loop 特殊调用的旁路代码,而是通过 ctx.tools 进入同一个注册和执行服务。
04 / 事件让运行过程可扩展
Harness 把事件按运行域组织:
session/event记录持久事实,并让 UI、投影和 telemetry 从同一条日志派生。agent/*承载运行中的 Agent 协调和请求拦截。tools/*连接工具执行前、执行中和结果阶段。
需要改变模型请求或工具策略时,优先挂到对应事件;不要为了一个扩展点修改 agent loop。waterfall 监听器必须调用 next() 才会委托下游。
05 / 没有特权内核意味着什么
Agent loop 本身也由配置挂载。模型 provider 可以替换,工具可以新增,会话存储可以由另一个 provider 提供,HMR 可以在运行中重新装载插件。
这不是“任何东西都随便改”的承诺。每个扩展仍然要遵守所属服务的类型、事件模式、配置 schema 和生命周期;可替换来自明确的连接点,而不是隐式全局状态。
06 / 写一个 DSH 插件的最短路径
- 选择要贡献的服务或事件,不先修改 loop。
- 写一个函数插件,导出
name、必要的inject、可选的Config和apply。 - 把注册和监听放在当前 Fiber 的 effect 体系内。
- 在 profile 的
cordis.patch.yml插入一行或 patch 一个稳定id。 - 通过 loader 组合运行,并观察真实服务输出和 teardown。
结语
Cordis 让 DSH 的结构可以用四个动词概括:组合、连接、拥有、回卷。profile 选择插件,Context 连接能力,Fiber 拥有实例,Effect 撤销副作用。
所以“一切皆插件”不是宣传语,而是一种可以沿着配置、服务、事件和生命周期逐层验证的运行时组织方式。
继续阅读:组合与热重载(HMR)、事件、waterfall。
更多文章
cordis.yml:把插件列表变成可修改的应用组合
理解 Cordis 配置项、稳定 id、group、isolate 与 patch 层,读懂配置文件如何定义一次运行。
生命周期与 effect:让 Cordis 注册可以回卷
跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。
动手:从 hello.ts 写出你的第一个 Cordis 插件
用一个函数插件和一份 cordis.yml,跑通 Loader、Context 与 Fiber 的最短路径。
邮件列表
加入我们的社区
订阅邮件列表,及时获取最新消息和更新