DeepSeek Harness 开发第一个工具:defineTool 完全入门
在 DeepSeek Harness 中,所有智能体能力的最小单元是 Tool(工具)。无论是文件读写、终端执行、代码运行、网络请求,全部基于 defineTool 标准化定义。
defineTool 是 Harness 官方提供的工具定义原语:它统一描述工具名称、用途、参数结构、执行逻辑、输出规范,让大模型可以「读懂工具、自动决策调用、自动入参校验」。
本文带你从零手写第一个可被AI自动调用的自定义工具,完整覆盖工程结构、字段释义、参数规范、编译加载、Web 调试、常见报错,是所有高级插件开发的基础。
一、为什么必须用 defineTool
普通 Agent 框架中,工具只是一段函数;但在 Harness 架构中,工具是可被模型理解、可被内核托管、可生命周期回收、可配置校验的标准化能力。
使用 defineTool 拥有四大核心能力:
- 模型自调度:通过 description 让 LLM 自主判断何时调用该工具
- 自动参数校验:内核校验参数类型、必填项,非法参数直接拦截
- 生命周期托管:随插件加载注册、随插件卸载销毁,无残留
- 标准化协议:兼容 Function Call、PTC 代码模式、多模态串联任务
结论:所有自定义工具,必须通过 defineTool 注册,才能被 Harness 智能体识别和调用。
二、前置环境准备
沿用标准插件工程结构(前文统一规范):
- Node.js 20+ / 22+
- 已安装最新版 dsh:
npm install -g @deepseek-ai/dsh@latest - 工程具备 tsconfig.json + cordis.yml
三、最简完整工程:第一个自定义工具
我们开发一个实用工具:时间时区查询工具,支持自定义时区获取系统时间,全程可直接复刻。
1. 工程目录
dsh-plugin-first-tool/ ├── src/index.ts # 工具主逻辑 ├── cordis.yml # 插件清单 ├── package.json └── tsconfig.json
2. 核心代码:defineTool 完整写法
src/index.ts
import { Context, defineTool } from "@deepseek-ai/dsh-core";// 插件标准入口
export function apply(ctx: Context) {
// 注册自定义工具
ctx.tools.register(defineTool({
// 工具唯一标识(全局唯一,小写+下划线)
name: "query_current_time", // 【最重要】模型调用依据,必须清晰、场景明确 description: "用于查询当前系统时间,支持指定时区。用户询问现在时间、北京时间、海外时区时间时调用。", // 入参结构定义(JSON Schema) parameters: { timezone: { type: "string", required: false, description: "目标时区,默认 Asia/Shanghai,例如:America/New_York、Europe/London" } }, // 工具执行逻辑 async execute(args) { const { timezone = "Asia/Shanghai" } = args; const now = new Date().toLocaleString("zh-CN", { timeZone: timezone, hour12: false }); return { timezone, datetime: now, timestamp: Date.now() }; } }));
}
3. cordis.yml 插件清单
name: dsh-plugin-first-tool version: 0.1.0 description: 我的第一个 defineTool 自定义工具插件 main: dist/index.js dependencies: "@deepseek-ai/dsh-core": ">=0.20.0"
4. 编译命令
tsc
四、defineTool 字段逐字详解(必背)
掌握以下字段,即可开发 99% 的自定义工具。
1. name(工具名)
- 全局唯一,不可重复
- 规范:小写、下划线分隔、语义清晰
- 禁止中文、大写、特殊符号
- 示例:query_current_time、file_batch_rename
2. description(工具描述,核心)
决定模型会不会调用你的工具。
书写公式:能力是什么 + 什么时候调用 + 适用场景
❌ 错误写法:获取时间(太简短,模型无法决策)
✅ 正确写法:用户询问当前时间、各时区时间时调用,可返回指定时区标准时间戳
3. parameters(参数结构)
标准 JSON Schema,内核自动校验:
- type:string / number / boolean / object
- required:是否必填
- description:参数用途说明,辅助模型填参
4. execute(执行函数)
- 必须 async 异步函数
- args 为模型自动填充的参数对象
- 返回结构化数据,便于模型总结输出
- 支持文件操作、网络请求、计算逻辑
五、本地加载与实测调用
1. 加载本地插件
dsh plugin --profile web add ./当前插件目录
2. 查看是否加载成功
dsh plugin --profile web list
3. Web 实测调用
启动服务:dsh web,新建会话,输入自然语言指令:
- 现在北京时间几点
- 查询纽约当前时间
- 获取当前时间戳
模型会自动识别、自动调用、自动传参你的自定义工具,无需手动触发。
六、工具生命周期与副作用规范
通过 ctx.tools.register 注册的工具,自动纳入插件生命周期管理:
- 插件加载 → 工具注册生效
- 插件卸载 → 工具自动注销,模型无法再调用
- 热重载 → 旧工具销毁、新工具替换
如果工具内部存在定时器、长连接、监听,必须用 ctx.effect 托管(参考前文生命周期文章)。
七、进阶:带必填参数 + 数值校验工具示例
再写一个更强的结构化工具:数字加法计算器,带必填校验。
ctx.tools.register(defineTool({ name: "math_add_calc", description: "高精度数字加法计算,用户需要计算两个数字相加时调用,支持小数运算", parameters: { a: { type: "number", required: true, description: "第一个加数" }, b: { type: "number", required: true, description: "第二个加数" } }, async execute(args) { const { a, b } = args; return { result: a + b, formula: `${a} + ${b} = ${a + b}` }; } }));
八、新手高频问题与排错
1. 插件加载成功,但模型不调用工具
99%原因:description 描述不清晰,模型不知道该在什么场景触发。
解决方案:补全场景、用途、触发条件,不要写极简描述。
2. 参数报错、参数类型不匹配
内核强校验 Schema,模型传参错误会直接拦截。优化参数 description,引导模型正确传参。
3. 旧会话不生效
工具注册仅对新建会话生效,测试必须新开对话。
4. 工具重复注册
name 全局唯一,修改重名工具名即可解决冲突。
九、defineTool 开发黄金规范
- 命名语义化:工具名见名知意,统一下划线小写风格
- 描述场景化:写清触发场景、用途、能力边界
- 参数精细化:必填/选填明确,每个参数带详细说明
- 返回结构化:不要返回纯文本,返回 JSON 便于模型二次推理
- 逻辑纯净化:单一工具只做一件事,职责单一
- 资源可回收:异步副作用全部 effect 托管
本篇小结
defineTool 是 DeepSeek Harness 插件开发的入门基石与核心原语。所有高级能力、工作流、智能体任务,底层都是无数标准化 Tool 的组合。
掌握 defineTool 的 命名规范、场景描述、参数 Schema、执行逻辑、生命周期托管,你就掌握了 Harness 自定义智能体能力的根本:让模型可控、可调度、可执行、可回收。
0 条笔记