AI 速览深度解析 DeepSeek Harness (DSH) 基于 Cordis 框架的插件化架构,适合 AI 开发者理解底层机制。 核心事实 - 架构原理:DSH 遵循“万物皆插件”原则,模型适配器、工具注册表等均为 Cordis 插件 - 分包策略:采用契约包(Definition)、实现包(Provider)、消费方包(Consumer)三段式结构 - 服务机制:通过 Context 注册表管理依赖,支持独占式和注册表式两种服务挂载方式 - 热重载能力:利用可逆 Effect 机制,实现服务提供方替换时的插件自动重载 价值点 帮助开发者掌握 DSH 生态构建逻辑,为开发自定义插件或集成第三方工具提供底层技术参考。
版本声明:本文引用的 DeepSeek Harness(下称 DSH)代码对应 deepseek-harness 的 master @ 47f943859b;Cordis 为 vendor/ 下的源码固定副本 @deepseek-ai/cordis@4.0.1(vendor/cordis/package.json)。 Cordis 本身的理论背景见论文《A Programming Paradigm for Spatiotemporal Composability》(引用格式「论文 §x.y」),本文不展开理论,只用机制描述回答一个问题:Cordis 提供的几个特性,在 deepseek harness 中是如何被使用的。 文中所有代码引用均给出 文件:行号 并附原文,可以点击跳转至 github 仓库源代码。

ctx.reflect.provide('loader', this, this[Service.check])程序化:ctx.plugin(X) 把 X 挂为调用处那个 ctx 的子节点,X 的 apply 收到的就是这个新子 ctx;X 若在自己的 apply 里再调 ctx.plugin(Y),Y 就是 X 的孩子——第四节的 agent-spine 连用二十来个 ctx.plugin,生成的就是一层二十几个孩子的子树。
plugin(plugin: Plugin, config?: any, getOuterStack = buildOuterStack()) { const callback = this.resolve(plugin) // 函数 / 类 / { apply } 对象统一成一个回调 if (!callback) throw new Error('invalid plugin, ...') this.ctx.fiber.assertActive() let runtime = this._internal.get(callback) // 同一插件的登记处,注意 fibers 是列表 if (!runtime) { // ... runtime = { name, callback, fibers: new DisposableList(), Config: plugin.Config } this._internal.set(callback, runtime) } const fiber = new Fiber(this.ctx, config, Inject.resolve(plugin.inject), runtime, getOuterStack)constructor( public parent: Context, config: any, public inject: Dict, public runtime: Plugin.Runtime | null, // ...) { this._config = config // ... this.ctx = this.context = parent.extend({ fiber: this }) // 派生子 ctx this._runner = { epoch: INACTIVE, execute: function () { if (isConstructor(runtime.callback)) { const instance = new runtime.callback(this.ctx, this.config) // ← 实现类对象在启动时才 new // ... } else { return runtime.callback(this.ctx, this.config) } }, collect, } this.dispose = parent.fiber.effect(() => { // 把自己登记为父 fiber 的 effect → 级联卸载 const remove = runtime.fibers.push(this) // ... })声明式:cordis.yml 里 group: true 的 entry,它的 config 是子 entry 列表(第七节 minimal preset 里 pty 就嵌在 persistent-shell 的 config 下),Loader 把 entry 的层级实例化成同样层级的树。「父卸载时子树跟着卸载」的机制只有一句:子实例把自己登记为父实例的一个 effect(vendor/cordis/src/fiber.ts:265),而 effect 在所属实例卸载时自动回收(第五节),卸载父节点于是级联回收整棵子树。
constructor(protected ctx: Context, name: string) { // ... self.ctx.reflect.provide(name, self, this[symbols.check]) return self}declare module '@deepseek-ai/cordis' { interface Context { shell: ShellExecutor }}export abstract class ShellExecutor extends Service { constructor(ctx: Context) { super(ctx, 'shell') } abstract resolve(request: ShellExecRequest): ShellExecSpec abstract run(spec: ShellExecSpec): Promise abstract start(spec: ShellExecSpec): ShellProcess}/** * Local bash executor over `ctx.subprocess`. ... a * still-running background process stays managed (killed and joined at * composition teardown) even across an executor reload. */export class LocalBashExecutor extends ShellExecutor { static inject = ['subprocess'] static Config: z = z.object({ cwd: z.string(), timeoutMs: z.number().default(120_000), maxTimeoutMs: z.number().default(600_000), maxOutputBytes: z.number().default(64_000), // ... }) // ... constructor(ctx: Context, config: Config) { super(ctx)export const name = 'web-search-exa'/** The web seam this provider registers into. */export const inject = ['web']/** Register the Exa search provider with `ctx.web`. */export function apply(ctx: Context, config: Config): void { ctx.web.registerSearchProvider(new ExaSearchProvider({ apiKey: config.apiKey ?? launchEnvironmentOf(ctx).get('EXA_API_KEY')?.value ?? '', // ... }))}/** Concrete agent factory and driver service. */export class AgentLoop extends Service implements AgentFactory { static inject = ['agents', 'sessions', 'llm', 'tools', 'systemPrompt']export function apply(ctx: Context, config: Config): void { // ... ctx.plugin(Timer) ctx.plugin(LlmRuntime) ctx.plugin(SessionStore) ctx.plugin(SystemPrompt, { /* ... */ }) ctx.plugin(ToolRuntime, config.tools ?? {}) // ... ctx.plugin(AgentLoop, { agents: config.agents ?? [], /* ... */ })}ctx.web.registerSearchProvider(new ExaSearchProvider({ /* ... */ }))/** * ... * if its id is already registered for search. Returns a disposer; disposed * with the calling fiber. */registerSearchProvider(provider: WebSearchProvider): () => void { return this.registerProvider(this.searchProviders, provider)}private registerProvider(store: Map, provider: P): () => void {
if (store.has(provider.id)) { throw new WebError(`a web provider with id "${provider.id}" is already registered`, 'WEB_DUPLICATE_PROVIDER') } const dispose = this.ctx.effect(function* () { store.set(provider.id, provider) yield () => store.delete(provider.id) }, 'web.registerProvider()') // ...}const effect: Effect = runner.execute.call(this) // 调生成器函数,拿到迭代器// ...(略:回调直接返回函数 / Promise / async 迭代器的分支)} else if (Symbol.iterator in effect) { const iter = effect[Symbol.iterator]() while (true) { const result = iter.next() // 当场驱动到底 safeCollect(result.value) // 每 yield 一条撤销,当场收走 if (result.done) return }}export function apply(ctx: Context, config: Config): void { ctx.web.registerSearchProvider(new ExaSearchProvider({ /* ... */ }))}public readonly _disposables = new DisposableList() // 每个实例的处置列表 // Fiber.effect 内:removeWrapper = this._disposables.push(wrapper) // 「登记」= push 进列表await Promise.all(this._disposables.clear().map(async (dispose) => {// announcing so a throwing `session/created` listener rolls the attach back// (the generator effect disposes already-yielded disposers on a throw)// instead of leaking the store entry and its publication hooks.this.ctx.effect(function* (this: SessionStore) { yield this.enter(session) // 第一步:入库,立刻交出「移除它」的撤销 this.announce(session) // 第二步:广播——监听器可能抛错}.bind(this), 'sessions.create()')provide(name: string, value?: any, check?: () => boolean) { return this.ctx.fiber.effect(() => { // ...(略:把 name 声明为 service 的簿记) this.ctx.root[symbols.isolate][name] ??= Symbol(name) const key = this.ctx[symbols.isolate][name] const impl: Impl = { name, value, fiber: this.ctx.fiber, check } if (this.store[key]) { throw new Error(`service "${name}" has been registered at <${this.store[key].fiber.name}>`) } this.store[key] = impl this.ctx.fiber.store![name] = impl if (this.ctx.fiber.state === FiberState.ACTIVE) { this.notify([name]) } return async () => { delete this.store[key] const fibers = this.notify([name]) await Promise.allSettled(fibers.map(fiber => fiber.await())) // ensure self access before dependencies cleanup delete this.ctx.fiber.store![name] } }, `ctx.provide(${JSON.stringify(name)})`)}import { Context } from '@deepseek-ai/cordis'import { LocalBashExecutor } from '@deepseek-ai/dsh-bash-local'export class SandboxBashExecutor extends LocalBashExecutor { static override inject = ['subprocess', 'sandbox', 'sandboxPolicy'] constructor(ctx: Context, config: Config) { super(ctx, config) this.mode = ctx.sandboxPolicy.defaultMode // inject 声明过的服务,直接用 } override resolve(request: ShellExecRequest): ShellExecSpec { /* ... */ } override async run(spec: ShellExecSpec): Promise { /* ... */ } override start(spec: ShellExecSpec): ShellProcess { /* ... */ } // ...(沙箱业务逻辑,Cordis 不关心)}export default SandboxBashExecutor- id: bash-sandbox name: '@deepseek-ai/dsh-bash-sandbox' disabled: !!js process.platform === 'win32' config: timeoutMs: 60000- id: settings name: '@deepseek-ai/dsh-settings-file'- id: llm-deepseek name: '@deepseek-ai/dsh-llm-deepseek' config: thinking: enabled reasoningEffort: max models: - id: deepseek-v4-pro contextWindow: 128000- id: agent-spine name: '@deepseek-ai/dsh-agent-spine-demo'- id: hmr name: '@deepseek-ai/cordis-plugin-hmr' config: root: ['.']# The shared module-reload HMR row stays off; the launcher's watch-only# fallback still keeps the user patch layers live until the run exits.- id: hmr disabled: true- id: persona name: '@deepseek-ai/dsh-persona' config: text: You are a helpful software engineer assistant. complete: true- id: persistent-shell name: cordis:group group: true isolate: terminals: true config: - id: pty name: '@deepseek-ai/dsh-terminal'- id: tool-bash name: '@deepseek-ai/dsh-tool-bash' disabled: !!js process.platform === 'win32'- id: tool-pwsh name: '@deepseek-ai/dsh-tool-pwsh' disabled: !!js process.platform !== 'win32'- id: tool-presentation name: '@deepseek-ai/dsh-agent-tool-presentation' config: mode: code- id: tool-cordis name: '@deepseek-ai/dsh-tool-cordis'- id: skill-filesystem name: '@deepseek-ai/dsh-skill-filesystem'Cordis 特性 | DSH 里的用法 |
|---|---|
Context 树 + 服务注册(provide) | everything is a plugin;ctx.shell / ctx.llm / ctx.web 全部由各包自行注册(第三节) |
inject 依赖声明 + 按可用性调度启动 | 组合插件不关心顺序;agent-spine 一次挂二十来个子插件(第四节) |
ctx.effect 可逆注册 | provider 注册、事件监听随插件卸载自动回收;配置热重载不留中间态(第五节) |
Loader 声明式组合 | cordis.yml + patch 层叠(进程级)、preset(session 级);四个模式是四份 YAML(第七节) |
isolate 隔离 | preset 里 per-session 服务放进 isolate group,同进程多 session 互不干扰(第七节) |
# 角色 你是一名经验丰富的程序员,擅长分析各种编程语言的报错信息并提供有效的调试方案。 # 任务 分析用户提供的报错信息,推测可能的原因并提供清晰的调试步骤。 # 处理规则 1. **错误识别**:准确识别报错类型(语法错误、运行时错误、逻辑错误、环境配置错误等) 2. **原因分析**:基于报错信息推测2-3个最可能的根本原因 3. **调试步骤**:提供具体、可操作的调试步骤,按优先级排序 4. **代码示例**:如适用,提供修复后的代码示例 5. **预防建议**:给出避免类似错误的最佳实践建议 # 输出格式 ## 错误类型 {错误类型分类} ## 可能原因 • {原因1} • {原因2} • {原因3} ## 调试步骤 1. {步骤1} 2. {步骤2} 3. {步骤3} ## 代码示例 ```{语言} {修复后的代码示例} ``` ## 预防建议 {具体的预防建议} # 注意事项 - 如果报错信息不完整,明确指出需要补充哪些信息 - 区分不同编程语言的特有错误模式 - 考虑环境因素(版本兼容性、依赖包等) - 对于模糊的报错,提供多种可能性分析 # 用户输入 【报错信息】