LAYER 06 · 动手扩展并交付

实战:添加一个工具

从参数 schema、执行与输出 schema,到作用域注册、展示和测试

20 min3 处源码锚点upstream@47f9438
defineTool → ctx.tools.register → prompt schema
本章要解决的问题

一个合格工具定义除了 name、description 和 execute,还必须考虑什么?

先建立直觉

工具定义是一份带质检的产品合同:输入规格、产出规格、最长交期、展示方式和出错类别都要与实际生产线一致。

MECHANISM

机制拆解

defineTool 把参数推导、JSON Schema 编译、运行时校验、output 校验和 presentation 绑定在同一份定义上;不支持的 schema 关键字会被拒绝。

注册到 agent.ctx 可提供局部能力,注册到根 ctx 提供部署能力;schemas() 只投影当前可见工具,执行仍走完整流水线。

第 1 步 / 共 5 步

定义参数与输出

参数、output 和错误保持 JSON 可表示。

INVARIANTS

无论怎么扩展,都不能破坏

  • 参数与输出都经过运行时校验
  • 工具 meta 必须 JSON 可序列化
  • 工具业务逻辑不拥有跨工具安全策略
FAILURE MODES

最容易踩中的坑

  • ×只写 TypeScript 类型而无运行时 schema
  • ×handler 返回 class/Date/循环引用
  • ×注册后忘记让插件生命周期拥有 disposer
● ● ●h25-build-tool.ts TypeScript
export const apply = (ctx: Context) => {
  ctx.tools.register(defineTool({
    name: "weather_lookup",
    description: "Return a normalized weather snapshot.",
    parameters: { city: { type: "string" } },
    output: { summary: { type: "string" } },
    async execute({ city }, runtime) {
      runtime.signal.throwIfAborted()
      return { summary: await lookup(city, runtime.signal) }
    },
  }))
}
VERIFY IN SOURCE

不要相信结论,去源码里复核

以下链接固定到官方 deepseek-harness@47f9438;查看当前上游时请留意后续 breaking changes。

KNOWLEDGE CHECK

先停十秒,再揭晓答案

为什么工具 output 也要有 schema?

为什么下一章紧接在这里

工具是 capability consumer;下一章从另一侧设计一个可替换 Provider 和完整 seam。

Learn DeepSeek Harness

独立教学项目。解释力来自源码,判断边界以官方仓库为准。