工具系统概览
本教程共 32 篇 · 第 14 篇 · 更新于 2026-08-15 · 约 6 分钟阅读
本节目标:搞清楚 dsh 里「工具」是什么、注册表怎么工作,认识一批开箱即用的内置工具,并学会工具的开与关。
工具是模型的手和脚
模型只会生成文字,干不了实事。工具(tool)就是让模型能「动手」的通道:读文件、跑命令、搜网页、开终端。dsh 的口号是「一切皆插件」,工具也全是插件注册出来的。
一个工具由两部分组成:
- 模型侧:
name、description和 JSON Schema 格式的parameters,它们被组装进系统提示词,模型据此决定「调不调、怎么调」; - 宿主侧:
execute函数,真正执行这次调用并返回结果。
工具执行的具体管线(审批、超时、结果改写那些环节)在第 15 章展开,本章先看「有哪些工具、怎么管」。
工具注册表
所有工具都挂在 ctx.tools 这个服务上,官方叫 工具注册表(Tool Registry)。它提供四个关键能力:
register():注册工具,返回精确的卸载函数,插件卸载时工具自动消失;schemas():把当前可见工具投影成发给模型的 schema 白名单——只有 name/description/parameters 会出去,execute等宿主侧实现绝不会泄漏到模型请求里;get():按名字查某个作用域视角下的工具定义;restrict():给作用域加工具过滤器(下文讲)。
工具集变化时,注册表会发出 tools/change 事件,任何监听它的插件都能感知。模型看到的工具目录在下一次请求组装时更新,不需要重启。
作用域化工具
工具不是只有「全局/不全局」两档。每个 Agent 有自己的作用域(scope),注册表支持两层注册:
- 全局注册:所有 Agent 都可见;
- 作用域注册:在某个 Agent 的作用域里注册,只对这个 Agent 可见,并且遮蔽(shadow)同名的全局工具。
作用域还支持 restrict() 过滤器,用 allow(只保留)或 deny(移除)裁剪继承来的全局工具,多个限制取交集:
// 在某个 agent 作用域内:只保留 bash 和 read,其余全局工具全部隐藏
const disposer = ctx.tools.restrict({ allow: ['bash', 'read'] })
// 用完调用 disposer() 恢复
Note限制只作用于继承来的全局工具,不影响作用域自身的注册。被委派的子 Agent 会保留它回报结果所依赖的工具,不会因为父级过滤而残废。
内置工具目录(精选)
官方工具目录 tool-catalog 列出了所有随产品发布的工具。这里挑最常用的讲,按用途分五组。
执行命令
bash:执行 bash 命令,每次调用都在新 shell 里跑,状态不保留(cwd、变量、函数),所以要传workdir而不是用cd。长命令可设run_in_background: true立即返回 job id。pwsh:Windows 组合里的 PowerShell 方言,路径用C:\...原生形式,变量用$env:NAME。terminal_open/terminal_send/terminal_read/terminal_list/terminal_close/terminal_signal:6 个持久终端工具,需要显式选择启用。要跨多次调用保留 shell 状态(REPL、gdb 之类)时用它。
文件操作
read/write/edit/read_image:fs 四件套。read带行号和窗口(offset/limit);edit是字面量替换;read_image读图片,要求当前模型接受图片输入,且没有附件存储时不会注册。str_replace_editor:独立的查看/创建/唯一字面量替换/按行插入工具,状态在调用之间持久保留。str_replace要求old_str完全匹配且唯一,不唯一就不执行。glob/grep:搜索工具。内置了 ripgrep 二进制(@vscode/ripgrep),宿主机不需要装rg,也不经过 shell 层。
网络
web_search/web_fetch:搜索和抓取网页,后端选择通过ctx.web缝解耦。
委派与后台
subagent(及 fork 变体subagent_fork):把自包含任务委派给子 Agent。subagent可后台运行,subagent_fork是一次性前台。job_list/job_output/job_kill:与任务种类无关的后台任务控制器。后台 bash、PTY 发送、subagent 都通过这 3 个工具读取、列出、终止。interrupt_agent/list_agents/send_message:控制可继续的后台子 Agent。
辅助
ask_user_question:暂停工具调用,向当前 UI 提问并等人类回答。skill:加载技能(skill)的完整说明。todo_write:维护结构化任务清单,每次调用发送完整列表整体替换。exit_plan_mode:规划模式下提交计划供用户评审。session_event_read/session_event_search/session_event_trace/session_search/session_trace:5 个只读会话查询工具,需要选择启用(第 18 章详述)。create_goal/get_goal/update_goal:同会话目标管理。run_code:Code Mode 下执行 TypeScript 程序的保留传输机制。
Tip记不住全部没关系。日常用得最多的是
bash、read、write、edit、glob、grep、web_search这几个。其余工具等你需要时再查目录。
工具开关与发现
「模型能看到哪些工具」不是写死的,有四个机制在管:
- 默认加载 vs 选择启用:
bash、fs 四件套、glob/grep等随产品组合默认加载;terminal_*、会话查询工具、cordis_*动态插件工具集要显式选择启用。 - 作用域过滤器:
restrict({ allow | deny }),按 Agent 裁剪。 - 配置决定名称:部分工具名可在加载时配置,比如
tool-subagent的toolName,部署方可以给它换名字或加别名。 - 依赖决定注册:
read_image没有附件存储就不注册;lsp工具没有已注册的 LSP 提供方时,查询返回结构化LSP_UNAVAILABLE错误,但 schema 保持稳定。
模型侧还有一个「先看目录再调用」的纪律:模型通过系统提示词拿到工具目录,调用前按 skill 等目录工具加载细节。目录随时可能变,所以模型每次请求都要重新组装 schema——这也是 tools/change 事件存在的意义。
Warning工具执行失败不会让模型「蒙在鼓里」。未知工具调用会变成结构化错误
UNKNOWN_TOOL返回给模型,而不是静默吞掉。这保证模型能根据错误调整策略。
小结
- 工具 = 模型侧 schema + 宿主侧
execute,全部由插件注册。 - 注册表
ctx.tools负责注册、投影、查询、过滤;作用域注册遮蔽全局注册。 - 内置工具分五类:命令执行、文件操作、网络、委派后台、辅助。
- 工具开关靠默认加载、选择启用、
restrict过滤和配置化命名四层机制。