DeepSeek Harness 教程 · 第11讲 第一个自定义工具
第11讲 · 第一个自定义工具
《DeepSeek Harness 从上手到精通》系列 · 第四阶 工具开发篇
系列基于 deepseek-ai/deepseek-harness(0.1.0-rc.5,MIT)。前三阶你都在"用配置换脑",从这一讲起,你给模型长出新手脚——写一个它原本不会调用的工具。需要一点 TypeScript 基础(async/await 即可)。preview 阶段 API 可能微调,以官方 packages/core 为准。
一、工具在 dsh 里到底是什么
对模型而言,一个工具就是一段"带 schema 的能力":它有名字、有参数说明、有返回值。模型在 turn 中根据系统提示词里的工具 schema 决定"点名"哪一个,然后把参数填好交给框架执行。所以写工具 = 写三样东西:
- schema:参数定义(名字、类型、是否必填)与描述;
- 实现:真正干活的
execute函数; - 注册:把工具挂到
ctx.tools,模型才"看得见"。
二、最小工具组件:schema + 实现 + 注册
下面是一个概念示意(Cordis 插件骨架 + 注册到 ctx.tools)。真实 API 以你本机 packages/core 为准,但套路一致:
// plugins/local-weather.ts
import { definePlugin } from '@cordisjs/core'
export default definePlugin((ctx) => {
// 声明依赖:需要 tools 服务
ctx.inject(['tools'], (ctx) => {
const myTool = {
name: 'local_weather',
description: '查询指定城市的当前天气(温度、天气状况)。' +
'当用户询问某城市或本机所在地的天气时使用。',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '城市名,如 "北京"' }
},
required: ['city']
},
async execute({ city }: { city: string }) {
// 这里接你的数据源;下面用示意数据
return { city, temp: 23, condition: '晴' }
}
}
ctx.tools.register(myTool)
// 可逆副作用:插件卸载时自动摘除
ctx.on('dispose', () => ctx.tools.unregister('local_weather'))
})
})注意 ctx.on('dispose', ...)——这正是 Cordis 的可逆副作用:插件挂上时注册工具,卸下时自动反注册,系统回到原样。
三、通过 --patch 挂载 / 卸载
写好插件后,用一份补丁把它作为入口挂进去(回顾第 9 讲 --patch):
# my-tools.patch.yml
plugins:
- entry: ./plugins/local-weather.ts
# 挂载运行
dsh web --patch my-tools.patch.yml
# 卸载?直接去掉 --patch 重启即可(可逆副作用生效)插件构建(tsdown / 本地热重载 vendor/hmr)细节留到第 20 讲。本讲先用"能跑起来"为目标,构建报错就先确认入口路径与依赖是否装好。
四、工具描述写法:影响模型调用准确率
模型靠 description 决定是否调用你的工具。描述写得好不好,直接决定调用准确率。几条经验:
- 写清什么时候用("当用户问天气时"),而不只是"这是什么";
- 参数
description也要写清含义与格式,避免模型乱填; - 避免和已有工具"语义重叠",否则模型会在几个工具间犹豫;
- 返回结构稳定、字段命名清晰,模型后续才好组织答案。
五、动手练习:写一个"查本机天气/汇率"小工具
本讲产出:一个可挂载、模型可调用的实用小工具(天气或汇率任选)。
# 步骤
1) 按第二节模板写 plugins/local-weather.ts(execute 里接真实 API 或占位数据)
2) 写 my-tools.patch.yml 指向该入口
3) dsh web --patch my-tools.patch.yml
4) 在对话里问:"北京现在天气怎么样?"
5) 观察模型是否点名 local_weather、参数是否填对、返回是否回填成功标志:模型主动说出"我来查一下天气",并调用了你的 local_weather 工具。改错描述再试,体会"描述即接口"的含义。
六、常见坑
- 模型不调用工具:多半是 description 没说清触发场景,或和已有工具重叠;
- 参数类型对不上:schema 的
required/type要和 execute 实参一致; - 挂载没生效:检查
entry路径、插件是否构建/转译、依赖是否安装; - 忘记 dispose 反注册:热重载时残留旧工具,加上
unregister更干净; - execute 抛错未捕获:异常会中断 turn,记得 try/catch 并返回友好结构。
七、官方文档对应章节
docs/中 tools、tool-catalog、plugin 开发相关章节;packages/core的 tools 服务与工具类型定义(schema 字段以源码为准);- 衔接第 4 讲 Cordis(
inject/dispose)、第 9 讲--patch挂载;下一讲(第 12 讲)讲工具注册表与执行流水线。
本讲内容基于 DeepSeek Harness 官方文档与项目源码整理,仅供学习参考,具体命令与配置请以官方最新版本为准。系列文章配合源码仓库食用效果更佳:https://github.com/deepseek-ai/deepseek-harness
咨询 DeepSeek Harness 相关问题,请加微信:A0qingfengyuan_01
个人观点,仅供参考,如有不对之处,请多包涵,欢迎指出。本文由 AI 协助完成!
欢迎扫码关注公众号与作者微信,获取更多实用干货

