LESSON 10 · 进入运行

工具系统:模型怎样把“想做”变成“真的做”?

工具如何注册、展示、审批、执行,并把结果送回 Agent Loop?

模型会分析和生成文字,却不能直接读取你的磁盘、运行测试或访问网页。真正让 Agent 从“会说”变成“会做”的,是 DeepSeek Harness 的工具系统。

这一课不罗列每个工具,而是看所有工具共同遵守的路线:怎样加入列表、怎样让模型看懂、怎样接受权限检查,又怎样把结果送回下一轮思考。

1

工具不只是一个函数

假设你开发了一个“查询订单”工具。只写一个 queryOrder() 函数还不够,因为模型和系统还需要知道:

  • 它叫什么;
  • 什么时候应该使用;
  • 参数有哪些、哪些必填;
  • 成功后返回什么;
  • 具体怎样执行;
  • 在界面上怎样展示。

因此,一项 DSH 工具更像一份完整的岗位说明书:名字和参数给模型看,execute 是真正干活的人,输出声明负责验收结果,展示信息告诉 UI 怎样画卡片。

工具插件启动时,会把这份定义注册到 ctx.tools。多个插件可以各自注册工具,最终组成当前 Agent 可以看到的工具集合。

2

同一个 Host,为什么不同 Agent 能看到不同工具

工具注册表不是一张所有 Agent 完全共享的平面清单。它会结合 Cordis 作用域计算可见性:

  • Host 层注册公共工具;
  • Preset 层加入某类 Agent 专属的工具;
  • Agent 层还可以进一步限制或增加工具。

例如,代码 Agent 可以看到文件、终端与 LSP;客服 Agent 只看到订单查询和退款申请;审计 Agent 可能只保留只读工具。

这也是为什么“给 Agent 增加工具”通常应该放在 Preset 中装配,而不是修改 Agent Loop。Loop 只向 ctx.tools 索要“当前作用域最终可见的工具”。

流程图 · 手机端可横向滑动
正在绘制流程图…
3

DeepSeek Harness 内置工具全景表

下面这张表依据源码生成的 docs/tool-catalog.zh.md 整理,覆盖当前仓库中已发布产品工具包提供的全部模型可见名称,包括按需启用和实验性工具。它不包含示例项目里的演示工具、外部 MCP Server 带来的工具,也不包含用户通过插件动态注册的新工具。

类别工具名主要用途默认可见情况
用户交互ask_user_question暂停当前调用,向用户展示问题或选项并等待回答标准、PTC、创造模式
规划exit_plan_mode提交完整计划供用户评审,获批后退出 Plan Mode完整 Preset;仅在 Plan Mode 下执行有效
任务清单todo_write写入或整体更新当前 Session 的结构化待办列表标准、PTC、创造模式
Code Moderun_code运行模型编写的 TypeScript,通过 SDK 组合多个工具调用PTC 模式
Shellbash执行 Bash 命令;不同 Preset 可采用一次性进程或持久终端实现非 Windows 环境;具体实现由 Preset 决定
Shellpwsh执行 PowerShell 命令;是 Windows 环境下与 bash 对应的工具Windows 环境;具体实现由 Preset 决定
文件编辑str_replace_editor查看、创建文件,执行唯一文本替换或按行插入极简模式
文件系统read按行读取 UTF-8 文本文件完整 Preset
文件系统read_image读取 PNG、JPEG、WebP 或 GIF,作为图像交给支持视觉的模型完整 Preset;需要图像能力与附件服务
文件系统write创建文件或用完整内容覆盖文本文件完整 Preset
文件系统edit通过精确的字面量替换编辑已有文本文件完整 Preset
文件搜索glob按 Glob 模式搜索文件路径完整 Preset
文件搜索grep使用 ripgrep 正则表达式搜索文件内容完整 Preset
语言服务lsp查询定义、引用、实现和 Hover 等语言服务器信息按需启用,需要 LSP Provider
持久终端terminal_open创建一个可以跨多次调用保留状态的终端会话按需启用
持久终端terminal_list列出当前 Agent 拥有的持久终端按需启用
持久终端terminal_read读取持久终端自上次读取后的输出按需启用
持久终端terminal_send向持久终端发送命令或输入,也可转为后台任务按需启用
持久终端terminal_signal向终端中的进程发送中断等信号按需启用
持久终端terminal_close关闭持久终端并等待其进程树退出按需启用
网页web_search搜索 Web 上的最新信息并返回摘要与来源完整 Preset;需要 Web Provider
网页web_fetch获取 HTTP(S) 页面并解码为文本tool-web 配置决定,系统 Preset 默认可关闭
长期目标create_goal为需要跨多个自主 Round 推进的工作创建持久目标完整 Preset
长期目标get_goal读取当前目标、阶段、修订号和阻塞状态完整 Preset
长期目标update_goal编辑、暂停、恢复、完成目标,或将其标记为阻塞完整 Preset
定时任务schedule_create创建延时、定时或固定间隔的 Session 提醒按需启用 Schedule 插件
定时任务schedule_list查看当前 Session 的活动提醒及其状态按需启用 Schedule 插件
定时任务schedule_delete删除一条活动提醒按需启用 Schedule 插件
Skillsskill从当前目录中加载某项 Skill 的完整操作说明标准、PTC、创造模式
工作流workflow运行 JavaScript 编排脚本,批量组织多个子 Agent 完成复杂任务标准、PTC、创造模式
工作流ralph围绕固定目标启动多轮全新子 Agent,直到完成、阻塞或达到轮数上限标准、PTC、创造模式
后台任务job_list列出后台 Shell、终端或子 Agent 任务及其状态完整 Preset
后台任务job_output获取后台任务的新增输出或最终结果完整 Preset
后台任务job_kill请求停止指定后台任务完整 Preset
子 Agentsubagent把一项独立任务委派给新的子 Agent标准、PTC、创造模式
子 Agentsubagent_fork携带当前已完成对话上下文,派生一次性子 Agent标准、PTC、创造模式
子 Agentlist_agents查看已创建的后台子 Agent 及其当前状态完整 Preset;Agent Teams 也复用此名称
子 Agentsend_message向可继续工作的后台子 Agent 发送下一轮消息完整 Preset;Agent Teams 也复用此名称
子 Agentinterrupt_agent中断后台 Agent 当前正在执行的轮次完整 Preset;Agent Teams 也复用此名称
子 Agentreport子 Agent 主动向直接父 Agent 汇报进度或最终结果仅在对应子 Agent 内可见
Session 查询session_search在当前工作区的历史 Session 中搜索相关事件按需启用,只读
Session 查询session_trace查看一个 Session 的祖先、后代等谱系关系按需启用,只读
Session 查询session_event_search在指定 Session 的历史事件中搜索内容按需启用,只读
Session 查询session_event_read读取一个完整事件以及可选的相邻事件概述按需启用,只读
Session 查询session_event_trace查看事件的替换关系及其引用的来源事件按需启用,只读
Cordis 创作cordis_inspect_list列出当前 Host 与 Client 可用的只读 Inspect Provider 和方法创造模式
Cordis 创作cordis_inspect_query查询服务、事件、工具 Schema、UI Slot 或主题等精确信息创造模式
Cordis 创作cordis_inspect_self查看当前 Session 创建的动态 Plugin、版本源码和运行诊断创造模式
Cordis 创作cordis_define定义一个新的动态 Cordis Package,或为已有 Plugin 增加新版本创造模式
Cordis 创作cordis_run激活、更新或回退动态 Plugin 的某个 Package创造模式
Cordis 创作cordis_stop停止动态 Plugin,同时保留定义和版本以便再次运行创造模式
Cordis 创作cordis_undefine永久移除当前 Session 创建的动态 Plugin 及其 Package创造模式
Agent Teamsspawn_teammate创建一个具名、持久的团队成员 Agent实验性,默认禁用
Agent Teamsfollowup_task向团队成员发送后续任务,并在需要时启动新一轮工作实验性,默认禁用
Agent Teamsteam_task_create在共享团队任务板上创建任务实验性,默认禁用
Agent Teamsteam_task_get读取一项共享任务的最新完整内容实验性,默认禁用
Agent Teamsteam_task_list按状态、负责人或就绪情况列出共享任务实验性,默认禁用
Agent Teamsteam_task_update领取、编辑、完成、重开、转交或删除共享任务实验性,默认禁用
Agent Teamswait_agent等待团队成员状态、消息或共享任务发生变化实验性,默认禁用

需要特别注意,表里的“内置”只表示 DSH 仓库已经提供了相应工具插件,并不表示每个 Agent 会一次性看到它们。标准模式、极简模式和创造模式会装配不同的工具;某些工具还要求 Host 先提供 LSP、Web、Schedule 或 Terminal 等底层服务。这样既能保持核心 Loop 稳定,也避免把与当前任务无关的大量工具说明全部交给模型。

bashpwsh 还有一次性执行和持久执行两套插件实现,但它们对模型暴露的是同一个工具名。实验性的 Agent Teams 插件则会复用 list_agentssend_messageinterrupt_agent 三个名称,把目标从普通后台子 Agent 换成持久 teammate,因此表中不再重复列出。

4

第一步:把工具说明交给模型

每个 Step 的 preStep() 会向 ctx.tools 获取当前 Agent 的工具说明,然后放进模型请求。

普通 Native 模式下,模型看到的是工具名、说明和 JSON Schema。它并没有拿到 execute 函数,只得到一份“可以怎样申请调用”的菜单。

模型返回 Tool Call 时,也不是直接运行本地代码,而是返回类似下面的结构化意图:

tool = "query_order"
arguments = { "order_id": "A1024" }

Agent Loop 收到这个请求后,才把它交给工具注册表。

5

第二步:工具调用进入统一流水线

工具注册表不会找到函数以后立刻执行。每次调用都会经过一条统一路线:

流程图 · 手机端可横向滑动
正在绘制流程图…

可以把它想成公司采购:提交申请以后,先检查表单,再走权限审批,随后由采购员执行,最后验收并归档。所有部门都走同一套流程,安全规则就不需要复制到每个工具里。

6

第三步:权限插件可以在执行前介入

上一课介绍的四种工作模式,最直接的区别之一,就是当前 Agent 能看到哪些工具,以及这些工具以普通 Tool Call 还是 Code Mode SDK 的形式呈现。至于某一次工具调用能否真正执行,还要经过这一课介绍的审批与安全检查。

工具进入 pre-execute 后,审批插件可以返回三种决定:允许、拒绝或询问用户。随后,文件沙箱和其他 Guard 还会检查这项调用是否越过不可突破的限制。

这两层作用不同:

  • 审批解决“这一次要不要征求用户同意”;
  • Guard 与 Sandbox 解决“即使有人同意,也绝不能越过什么边界”。

业务插件同样可以参与。例如公司内部 Agent 可以在退款工具执行前检查金额,在发布工具执行前要求工单编号,在查询客户数据前验证当前租户。

这些策略都挂在工具流水线上,不必修改工具函数,也不必修改 Agent Loop。

7

第四步:执行结果必须经过统一验收

工具 execute 返回以后,系统会检查结果是否符合工具声明的输出结构。随后 post-execute 可以补充、替换或拒绝结果,工具自己的最终内容转换再生成模型真正看到的文字、图片或其他内容块。

为什么不把任意 JavaScript 对象直接扔给模型?因为工具结果还要被记录、重放、通过 API 传输,并在不同 UI 中展示。统一的 JSON 结果与内容格式,让后续环节不必猜测一个工具返回了什么。

最终的 tool/result 会写入 SessionEvent。下一次模型请求通过历史看到它,于是 Agent 才能根据真实执行结果继续思考。

8

Native、Code 与 Both 是三种“呈现方式”

DSH 还允许工具以三种形式呈现给模型。这不是上一课的权限模式,而是模型“怎样看见工具”的选择:

呈现方式模型看到什么适合场景
Native每个工具都是独立的函数调用调用简单、步骤清晰
Code只直接调用 run_code,在代码中使用生成的工具 SDK需要组合大量调用和处理中间数据
Both同时拥有 Native 与 Code 两种入口希望模型按任务自由选择

Code Mode 并不是绕过工具流水线。程序里的每次工具调用仍会重新进入参数校验、审批、Guard、执行和结果处理。变化的只是模型组织调用的方式,安全和日志主线没有消失。

9

多个工具能不能并行执行

可以,但必须由工具明确声明自己适合并行。

只读搜索、互不影响的查询通常可以组成并行调用;文件修改、终端命令和共享状态操作默认按独占方式执行。Agent Loop 会把连续的并行安全调用放进受限并发池,遇到独占工具就先排空前面的任务,再单独执行。

这不是单纯追求速度。并行工具必须保证相互交换顺序不会改变结果,否则日志顺序与真实副作用就可能对不上。

10

UI 为什么能为不同工具画不同卡片

工具定义还可以提供纯展示函数,根据调用参数和已经持久化的结果,告诉 UI 应该画通用卡片、终端输出、文件 Diff、搜索结果或网页结果。

展示函数不能依赖只存在于当时内存里的状态,因为页面刷新或 Session 重放时,UI 仍要画出同一张卡片。

因此 DSH 把三个责任分开:execute 负责做事,模型内容负责告诉模型结果,presentation 负责告诉人类怎样看。

11

开发业务工具时,应该把什么放在哪里

以“查询订单”为例:

  • Tool Definition:名称、参数、输出和执行逻辑;
  • Provider:真正连接订单数据库或远程 API;
  • pre-execute 插件:租户、权限和审批策略;
  • Preset:决定哪些 Agent 能看见这个工具;
  • UI presentation:把结果画成订单卡片;
  • SessionEvent:保存调用与结果事实。

这样划分以后,你可以换数据库 Provider、调整审批规则或把工具交给另一种 Agent,而不用重写整个工具调用流程。

下一课,我们把工具系统放回 Agent Loop:一条用户消息怎样触发模型请求、工具调用和下一次 Step,直到这一轮真正结束?

下一课 · 11

Agent Loop 是怎样循环工作的?

模型为什么会调用工具,又为什么会带着工具结果继续思考?

0 人点赞,0 人看过