DeepSeek Harness101 组合与诊断 返回首页 官方教程 ↗

从 Cordis 模式到真实工具流水线

注册、执行、观察,一个无需密钥的完整回路。

工具服务负责注册与执行,结果事件连接独立观察者,依赖图保证每个插件在正确时机启动。

greet-tool.ts
const result = await ctx.tools.execute({
  callId: CallId('demo-1'),
  name: 'greet',
  arguments: { name: 'Cordis' },
  signal: new AbortController().signal,
})

console.log(
  'tool replied:',
  JSON.stringify(result.content),
)

同一条链路复用了前面所有框架机制

服务等待、effect 清理、类型声明和事件解耦在真实 Harness 接口上同时工作。

等待注册表inject: ['tools']
注册工具ctx.tools.register()
执行调用ctx.tools.execute()
发出结果tools/result
为什么无需密钥

示例代码直接调用工具执行管线,相当于模型已经决定调用 greet。CallId 只为调用提供关联 id,没有模型请求。

defineTool 同时定义模型契约与结果契约

parameters 会转成展示给模型的 JSON Schema,并在 execute 前校验参数;output.schema 声明规范值,render 另行生成原生且可持久化的内容。

greet-tool.ts
import { defineTool } from '@deepseek-ai/dsh-tools'
import { CallId } from '@deepseek-ai/dsh-llm'

ctx.tools.register(defineTool({
  name: 'greet',
  description: 'Greet the named person.',
  parameters: {
    name: {
      type: 'string',
      required: true,
      description: 'Who to greet',
    },
  },
  output: {
    schema: { type: 'string' },
    render: (_args, value) => [
      { type: 'text', text: value },
    ],
  },
  async execute(args) {
    return `Hello, ${args.name}!`
  },
}))
parameters模型可见 schema、类型推导、运行时校验
execute返回 output.schema 声明的规范值
output.render生成 Native 与持久化结果内容
registration effect插件卸载时自动注销工具

ctx.tools.execute() 走的是实际 Harness 工具管线

调用需要关联 id、工具名、已结构化参数和取消信号。返回值包含渲染后的 content,而不只是 execute 的原始字符串。

CallId('demo-1')关联调用与结果
arguments: { name: 'Cordis' }由工具 schema 校验
AbortController().signal传递取消能力
result.content[{ "type": "text", "text": "Hello, Cordis!" }]

观察者只依赖事件,不依赖工具插件

包级 type-only import 引入 dsh-tools 的声明合并,让 tools/result 及 payload 获得类型,不产生运行时导入。

tool-logger.ts
import type {} from '@deepseek-ai/dsh-tools'

export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.on('tools/result', (exec, result) => {
    const text = result.content
      .map(block => block.type === 'text' ? block.text : '')
      .join('')
    console.log(`[tool-logger] ${exec.name} -> ${text}`)
  })
}
工具执行完成
物化结果 content
发出 tools/resultlogger 在这里输出
execute Promise 兑现调用方随后输出
两个插件互不认识

greet-tool 只使用工具注册表,tool-logger 只监听结果事件。tools 服务与事件系统把它们连接起来。

工具服务自己也有依赖

dsh-tools 会向系统提示词贡献工具 schema,因此它注入 systemPrompt。缺少提供方时,工具服务保持 PENDING,后面的两个插件也会等待。

cordis.yml
- name: '@deepseek-ai/dsh-system-prompt'
- name: '@deepseek-ai/dsh-tools'
- name: './tool-logger.ts'
- name: './greet-tool.ts'
systemPromptdsh-system-prompt
toolsdsh-tools
greet-tooltool-logger
node --import tsx ../../vendor/cordis/bin.js
[tool-logger] greet -> Hello, Cordis!
tool replied: [{"type":"text","text":"Hello, Cordis!"}]

完整 Agent 只是继续扩展这棵插件树

在当前工具回路上加入模型适配器、Agent loop、持久化和运行入口,就得到完整 Agent。每一层仍然是可替换插件。

运行入口CLI、Web 或 SDK
Agent loop回合、步骤与工具调用
LLM 适配器可替换模型提供方
工具与持久化能力、事件与会话记录
Cordis生命周期、依赖与组合

下一步,学习 Harness 的三层能力设计