开发者指南
注册模型工具
用 defineTool 定义工具 schema 与执行逻辑,并注册到 ctx.tools 供模型调用
面向模型的工具让 agent 能做具体的事——读文件、执行命令、检索网页。用 defineTool 定义工具的 schema 与执行逻辑,再注册到 ctx.tools。
最小形态
import { readFile } from 'node:fs/promises'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'my-tool'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'read_file',
description: 'Read a file from disk.', // 模型看到的内容
parameters: {
path: { type: 'string', required: true, description: 'Absolute path' },
limit: { type: 'number' }, // 默认可选
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute(args, exec) {
// args 由 schema 推导出类型:{ path: string; limit?: number }
return readFile(args.path, { encoding: 'utf8', signal: exec.signal })
},
}))
}注册基于副作用:dispose(资源释放)插件 fiber 即注销该工具;schema 会自动流入系统提示词的组装过程。
execute() 约定
- 参数已为你校验。
defineTool在execute运行前根据parameters校验模型生成的arguments,因此execute内的args已匹配推导类型。仍需手动检查 schema 无法表达的约束(非空字符串、正数、跨字段规则等)。 - 声明并返回一个规范 JSON 值。
output.schema声明规范值类型;execute只返回该值,注册表把它快照、校验、冻结后传给output.render(args, value)。不要在工具主体返回内容块,也不让调用方从自然语言里解析 id 与字段。 - 抛出异常或返回无效值意味着
isError。 基础设施故障请抛异常;成功的领域结果写入规范值,即使它表示非理想状态。 - 遵守
exec.signal。 信号触发时取消进行中的工作。 - 注册借用只读定义。 注册后不要修改 schema 或替换回调;要热替换工具,就 dispose 其所属 effect 再注册替代品。
长时间运行的工作
需要后台执行时,用 ctx.jobs.start(...) 注册任务,而不是让工具主体阻塞。成功的后台分支返回类型化的规范句柄(如 { kind: 'background', jobId });前台工作仍与 exec.signal 耦合。
执行策略与观测
不要把部署策略内建到工具里,改用流水线事件:
tools/pre-execute— 可扩展的允许/拒绝/询问策略。ctx.tools.guard()— 最终的单调拒绝,后续监听器无法撤销。tools/execute— 为分发加截止时间、重试或指标。tools/post-execute— 替换展示内容或返回值、阻止结果、附加模型可见上下文。tools/result— 观测不可变的归一化结果而不改变它。
工具的 UI 卡片
output.render 返回模型可见内容;UI 卡片是另一项关注点,通过纯展示投影与可选的 presentCall/presentResult 方法声明。两个方法都返回 card 标签的渲染意图:generic(默认)、terminal(shell 命令)、diff(文件变更)、search、web。
硬性规则:这些方法必须是 args(加结果)的纯函数——实时流式输出与会话回放都会运行它们,不能做 I/O、读会话状态或用时钟/随机数。