从工具声明到执行,Agent 如何使用工具?

举报
yd_229544978 发表于 2026/11/09 00:06:44 2026/11/09
【摘要】 DeepSeek Harness 20 天实战(04):从工具声明到执行,Agent 如何使用工具?本文是「DeepSeek Harness 20 天实战」的第 4 篇。上一篇介绍了模型请求的上下文;这一次,我们拆解工具从声明、暴露给模型,到执行和返回结果的完整过程。本文基于截至 2026 年 11 月的公开资料。DeepSeek Harness 仍处于开发者预览阶段,具体接口和行为可能随...

DeepSeek Harness 20 天实战(04):从工具声明到执行,Agent 如何使用工具?

本文是「DeepSeek Harness 20 天实战」的第 4 篇。上一篇介绍了模型请求的上下文;这一次,我们拆解工具从声明、暴露给模型,到执行和返回结果的完整过程。

本文基于截至 2026 年 11 月的公开资料。DeepSeek Harness 仍处于开发者预览阶段,具体接口和行为可能随版本变化。

当我们要求 Agent 分析一个项目时,它可能会搜索文件、读取代码,甚至运行测试。

模型本身并不能直接读取你的硬盘。它需要先知道有哪些工具可以使用,再生成符合工具要求的调用请求,由 Harness 负责后续处理。

那么,一个工具是怎样进入模型视野的?调用过程中又会经过哪些检查?今天我们通过一个文本统计工具,把这条链路串起来。

一、一个工具包含哪些部分?

一个可供 Agent 使用的工具,通常需要回答以下问题:

部分 回答的问题
名称 这个工具叫什么?
描述 这个工具能做什么,适合什么场景?
参数 调用时需要提供什么,类型是什么?
执行逻辑 参数准备好后,实际执行什么操作?
输出 执行结束后,向调用方和模型返回什么?

在 DeepSeek Harness 中,工具插件可以使用 defineTool 创建定义,再通过 ctx.tools.register() 注册到工具服务。

其中,模型通常看到的是当前可用工具的名称、描述和参数 Schema。执行函数以及工具内部实现留在运行环境中,不会作为模型可调用的源码直接发给模型。

二、从工具注册到模型调用

一个典型过程可以分成四步:

  1. 注册工具:插件将工具定义注册到 ctx.tools。
  2. 准备工具说明:当前 Step 解析可用工具集合,并把对应 Schema 纳入模型请求。
  3. 模型提出调用:模型根据任务选择工具,生成工具名称和参数。
  4. Harness 处理调用:运行时检查并执行允许的调用,再将结果纳入会话。

需要注意:工具已经注册,不代表当前 Agent 一定能看到它。 Agent 作用域、工具限制和运行时条件都可能影响本次请求可用的工具集合。

下面是一个便于理解的调用意图示例,不是某个模型接口的实际报文:

{
  "tool": "count_codepoints",
  "input": {
    "text": "Agent 工具"
  }
}

这里的模型只是在请求统计文本。具体如何验证参数、运行代码和返回结果,由工具及 Harness 的执行流程决定。

三、工具调用会经过哪些环节?

在 DeepSeek Harness 的默认工具执行流程中,工具调用并不是拿到参数后就直接执行。一个简化的处理过程如下:

环节 主要作用
tools/pre-execute 插件可以参与允许、拒绝或申请审批等决策
已注册的 guard 对调用施加进一步的拒绝约束
tools/execute 包装实际执行过程,可用于超时、指标等能力
工具函数 验证工具参数并执行具体操作
tools/post-execute 检查或处理执行后的结果
tools/result 观察最终结果,不负责修改该结果

具体哪些策略生效,取决于当前加载的插件和配置。例如,如果调用被拒绝或审批未通过,工具函数可能根本不会运行。

上一篇我们还提到过 tool/call 和 tool/result。它们是会话事件类型;上表中的 tools/result 则是运行时的结果观察事件。名称相近,但用途不同。

四、工具返回值和模型看到的内容

使用 defineTool 时,可以通过 output.schema 声明工具返回值的类型。execute 返回符合该声明的规范值,output.render 再把它转换为面向模型的内容。

例如,一个统计工具的规范值可以是整数 8,而模型看到的文本可以是:

Unicode 码点数:8

两者有不同用途:规范值方便程序按类型使用;渲染内容方便模型理解结果。在会话记录中,工具结果通常保存的是面向模型的内容以及可选的展示元数据。

如果工具执行抛出异常,或输出不符合声明,调用会进入错误处理流程,而不是把错误包装成成功结果继续使用。

五、实践:编写一个文本统计工具

接下来实现 count_codepoints:接收一段非空文本,返回它的 Unicode 码点数。

先约定统计规则:

  • 空字符串或只包含空白的字符串会被拒绝。
  • 输入最多允许 10000 个 UTF-16 代码单元。
  • 统计时包含空格和换行。
  • Unicode 码点数不一定等于用户感知到的字符数;某些组合字符和表情可能由多个码点组成。

假设你已经准备好 DeepSeek Harness 源码,并在仓库根目录完成 pnpm install 和 pnpm run build。

首先创建目录:

mkdir -p scratch-plugin/src

创建 scratch-plugin/src/day04-text-tool.ts:

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'day04-text-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'count_codepoints',
    description:
      'Count Unicode code points in non-blank text of at most 10000 UTF-16 code units.',
    parameters: {
      text: {
        type: 'string',
        required: true,
        description: 'The text to count, including its whitespace.',
      },
    },
    output: {
      schema: { type: 'integer' },
      render: (_args, value) => [
        { type: 'text', text: 'Unicode 码点数:' + value },
      ],
    },
    async execute(args) {
      if (args.text.trim().length === 0) {
        throw new Error('text must not be blank')
      }

      if (args.text.length > 10000) {
        throw new Error('text exceeds 10000 UTF-16 code units')
      }

      return Array.from(args.text).length
    },
  }))
}

这段代码里有几个重点:

  • inject = ['tools'] 声明插件依赖工具服务。
  • parameters 声明 text 必须是字符串;defineTool 会在执行主体前校验声明支持的参数约束。
  • execute 补充检查“不能全为空白”和长度上限等业务规则。
  • output.schema 声明返回整数,render 将该整数转换成模型可读的文本。

仅依靠参数类型并不能表达所有业务规则。对于文件路径、资源范围或多个字段之间的关系,仍需要在合适的执行和权限层补充验证。

六、加载工具并验证

创建独立的补丁文件 scratch-plugin/day04.patch.yml,把路径替换为插件文件的实际绝对路径:

- insert:
    - id: day04-text-tool
      name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/day04-text-tool.ts'

在仓库根目录启动:

pnpm dsh web --patch ./scratch-plugin/day04.patch.yml

配置模型并选择测试工作区后,发送以下任务:

请调用 count_codepoints 工具,统计下面这段文本的 Unicode 码点数:
Agent 工具

如果模型调用工具并且传入的内容正好是 Agent 工具,工具应返回 8。你可以在执行轨迹中检查工具名称、实际参数和结果。

模型并不保证每次都按要求调用工具。如果回答中出现了数字,却没有相应的工具调用记录,就不能据此认定工具已经执行。

还可以尝试传入空白内容,观察错误结果。若工具没有出现在当前 Agent 的可用集合中,先检查插件是否加载,以及当前作用域和权限限制。

七、编写真实工具时还要考虑什么?

文本统计工具没有文件写入或网络请求,但真实工具可能涉及更复杂的执行边界。

  1. 输入校验:检查路径、大小、数值范围和跨字段约束,不能只依赖模型生成正确参数。
  2. 权限与沙箱:工具可见不代表所有操作都被允许;是否需要审批取决于实际策略。
  3. 取消与超时:涉及网络或长时间任务时,应响应执行上下文中的取消信号。当前版本中,工具定义里的 timeoutMs 本身只是声明,实际超时限制还需要相应策略插件。
  4. 错误处理:保留足够的信息帮助定位失败,但避免在错误消息中泄露密钥或敏感数据。
  5. 副作用与重试:写文件、发送请求等操作被中断后,要先确认是否已经执行,再决定能否重试。

工具的描述也很重要:它应当清楚说明能力和参数边界,帮助模型选择工具;真正的执行限制仍应由代码和运行时策略落实。

八、这一篇需要记住什么?

DeepSeek Harness 的工具链路可以从四个问题入手:

  • 工具如何声明并注册?
  • 当前模型能看到哪些工具和参数?
  • 调用执行前后会经过哪些策略和扩展点?
  • 返回给程序的规范值与返回给模型的内容是什么?

把这些环节分开,就更容易排查“工具没有被调用”“调用被拒绝”或“模型拿到了错误结果”等问题。

**下一篇预告:**我们将深入 Cordis 插件机制,理解插件如何声明依赖、注册能力,以及卸载时如何清理资源。

参考资料

  1. DeepSeek Harness Build a Tool 开发文档
  2. DeepSeek Harness Tool Authoring Reference
  3. DeepSeek Harness Tool Execution Pipeline
  4. DeepSeek Harness Tools 子系统文档
  5. DeepSeek Harness Tools 包说明
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。