QP内容库 Logo
首页
文章
文档
默认分类
关于
登录 →
QP内容库 Logo
首页 文章
文档
默认分类 关于
登录
  1. 首页
  2. 文档
  3. DeepSeek Harness
  4. Cordis 框架教程
  5. 3. 服务

3. 服务

  • Cordis 框架教程
  • 发布于 2026-09-30
  • 0 次阅读
目录
当前文章没有目录

English | 中文

服务是一个插件提供、其他插件通过 ctx 消费的具名能力。在 harness 中,ctx.tools、ctx.llm 和 ctx.agents 都是服务。消费方只指定 'tools' 之类的能力,而不导入其提供方,因此配置可以选择提供方,无需修改消费方。

提供服务

创建 greeter.ts,将它放在 tmp/cordis-tutorial 中:

import { Service, type Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
  interface Context {
    greeter: GreeterService
  }
}

export class GreeterService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'greeter')
  }

  greet(who: string) {
    return `Hello, ${who}!`
  }
}

export const name = 'greeter'

export function apply(ctx: Context) {
  ctx.plugin(GreeterService)
}

两部分协同工作:

  • 运行时:super(ctx, 'greeter') 以名称 greeter 注册该实例。此后,任何插件都可以通过 ctx.greeter 访问它。注册属于 effect,卸载提供方时会移除该服务。
  • 编译时:declare module '@deepseek-ai/cordis' 块使用 TypeScript 声明合并,把 greeter 加入 Context 接口,使 ctx.greeter 在各处都能通过类型检查。它不会生成代码;没有该声明时,服务在运行时仍能工作,但消费方会失去类型安全。

Service 子类本身就是插件(第 1 章介绍的类形态),因此 ctx.plugin(GreeterService) 会像挂载其他插件一样挂载它。

使用 inject 消费服务

创建 consumer.ts:

import type { Context } from '@deepseek-ai/cordis'

export const name = 'consumer'
export const inject = ['greeter']

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

inject 列出该插件需要的服务。Cordis 会让插件保持 PENDING,直到列出的每项服务都存在,因此在 apply 内可以保证 ctx.greeter 已经就绪。cordis.yml 中的加载顺序无关紧要:决定插件何时启动的是依赖关系,而不是文件顺序。

组合并运行:

- name: './greeter.ts'
- name: './consumer.ts'
Hello, world!

交换 cordis.yml 中两行的顺序后重新运行,输出仍然相同。尝试彻底移除 ./greeter.ts:消费方会保持 PENDING,不输出任何内容,既不崩溃,也不会只运行一部分。处于 PENDING 的 fiber 也不会让 Node 的事件循环保持活跃,因此如果组合中没有其他运行项,进程会静默地以状态码 0 退出。第 6 章介绍如何诊断这种状态。

加载后仍会跟踪依赖关系

inject 并非一次性的启动检查。如果应用运行期间所需服务消失,例如提供方被卸载或热替换,每个依赖插件也会随之卸载,并在服务恢复后再次加载。结合 effect(第 2 章),这能防止运行中的消费方保留对不可用服务的引用:依赖消失时,它自己的注册也会撤销。

这也是配置中可以替换服务的原因:卸载 Cordis 配置项 dsh-bash-local,挂载另一个 shell 提供方,所有注入 'shell' 的插件都会重新启动并使用新实现。

可选依赖

inject 用于硬性依赖。如果某项功能缺失时插件仍可运行,请跳过 inject,并在使用处探测:

export function apply(ctx: Context) {
  // undefined when no provider is loaded; the plugin still runs.
  const greeter = ctx.get('greeter')
  console.log(greeter?.greet('maybe') ?? 'no greeter available')
}

命名

每个应用中的服务名称共用一个扁平命名空间。请为自有服务添加有辨识度的前缀或命名空间(harness 已占用 tools 和 llm 等普通名称);子系统页面上生成的 cordis-surface 区块列出 harness 注册的每个名称。

下一章:事件:无需共享服务即可通信。

相关文章

Cordis 教程

English | 中文 Cordis 是 DeepSeek Harness 底层的插件框架:它是一个小型运行时,其中的每项能力,包括工具、LLM(大语言模型)适配器、文件访问乃至 agent loop(智能体循环)本身,都是挂载到共享上下文中的插件。本教程通过动手实践讲解 Cordis:每一章都是

7. 进入 harness

English | 中文 本章会向 harness 的 tools 服务注册一个可由模型调用的工具,通过 harness 工具流水线执行它,并观察结果事件。整个示例无需密钥,也不会调用模型。 工具插件 创建 greet-tool.ts,将它放在 tmp/cordis-tutorial 中: impo

6. 组合与 HMR(热模块替换)

English | 中文 到目前为止构建的每项能力都是插件,cordis.yml 则选择应用的插件树。本章会改变这种组合、热重载一个插件,并诊断始终无法加载的插件。 Cordis 配置项不只有名称 Cordis 配置项除了 name 和 config,还接受其他元数据: - id: greeter

5. 配置

English | 中文 cordis.yml 中的每个 Cordis 配置项都可以携带 config 块,插件则声明一个 schema,在运行 apply 前验证该块。错误配置会导致加载失败,并给出准确的错误:插件绝不会在配置不完整时启动。 可配置插件 创建 config-demo.ts,并将其放

4. 事件

English | 中文 服务支持直接调用;事件让插件无需知道有哪些插件正在监听,就能发出通知。harness 使用事件处理工具结果、模型请求和审批决定等交互。 声明、发出与监听 创建 stats.ts,将它放在 tmp/cordis-tutorial 中。它是一项负责计数并在每次变化时发出通知的服

3. 服务

English | 中文 服务是一个插件提供、其他插件通过 ctx 消费的具名能力。在 harness 中,ctx.tools、ctx.llm 和 ctx.agents 都是服务。消费方只指定 'tools' 之类的能力,而不导入其提供方,因此配置可以选择提供方,无需修改消费方。 提供服务 创建 g

目录
当前文章没有目录

星沉月落夜闻香,素手出锋芒。

Copyright © 2026 quping.com All Rights Reserved. Powered by Halo.
鲁ICP备09092435号