Appearance
2.3 工具执行流水线
本章概览:DSH 的工具(tool)是模型调用能力的唯一入口。本章拆解
ctx.tools的完整执行管线:注册与作用域、四种呈现模式、预执行把关、单调 guard、around 派发、后执行、结果规范化与观察。
注册与作用域
ctx.tools.register(definition) 注册一个受信任的类型化工具定义:
- 必备
output声明:规范output { schema, render, presentationMeta? }——工具体只返回声明 schema 的规范 JSON 值; - 作用域分层:普通插件上下文注册全局;通过
agent.ctx注册则只对该 agent 生效,遮蔽同名全局工具;同层重名抛错; ctx.tools.restrict(filter):agent 级 allow/deny 掩码(这是"可见性组合",不是权威边界——安全非目标见 scope Agent Note);- 注册即副作用,返回 disposer。
出处:
packages/core/tools/README.md(deepseek-harness-src/packages/core/tools/README.md)
呈现模式:native / code / both
tools.mode 配置决定工具如何呈现给模型:
| 模式 | 行为 |
|---|---|
native(默认) | 可见工具作为函数定义(function calling)贡献 |
code | 贡献保留的 run_code 传输 + 生成的 tools:sdk 提示片段 + "只有 run_code 可被直接调用"规则(执行器强制,模型直呼其他工具解析为 UNKNOWN_TOOL) |
both | 两种形式都贡献,且不设该规则(native 调用会执行) |
run_code 名称保留:不可注册、遮蔽、限制或移除。非 native 模式需要 ctx.codeRuntime(其 language 有已注册 SDK 渲染器;TypeScript 走 dsh-code-runtime-worker-thread)。单 agent 可用 ctx.tools.presentAs(mode) 遮蔽默认。
出处:
packages/core/tools/README.md(deepseek-harness-src/packages/core/tools/README.md)
执行管线(完整顺序)
官方顺序(可视化见 docs/tool-execution-pipeline.md):
text
tools/pre-execute(可重排的 allow/deny/ask 门)
→ ctx.tools.guard() 注册的单调 guard(返回字符串即最终拒绝理由)
→ tools/execute(around 派发:超时/重试/指标插件包裹)
→ tools/post-execute(可替换 content/value、附加上下文、block 反馈)
→ 定义拥有的 finalizeContent(快照于调用开始,只能替换最终 content)
→ tools/result(只读观察)各阶段要点
tools/pre-execute:可重排的 allow/deny/ask 门,返回PreToolDecision。ask由ctx.approval服务(挂载时),否则退化为 deny;故意不提供输入改写;- 单调 guard:
ctx.tools.guard()在 pre-execute 之后、派发之前运行;返回 reason 即拒绝,且后面的 waterfall 监听器不能把拒绝变回允许(单调性); tools/execute:around 包裹规范化派发。包裹器只能替换 signal(注册表在调用体前重新融合原始调用者 signal);包裹器生成的 success 会按解析出的输出声明重新规范化;tools/post-execute:接受可替换content或value(二选一)、附加additionalContexts;block 把反馈变成无值失败;content 替换不是机密边界(程序化消费方要防泄露应替换 value);finalizeContent:同步且全函数,每个规范化结果恰好运行一次(包括绕过 post-policy 的失败),只能替换content;tools/result:只读观察不可变的最终结果。同名tool/result是 loop 之后追加的持久会话事件——一个是实时,一个是持久。
结果形态
ToolExecutionResult 是判别联合:成功 { isError:false, value, content, meta?, additionalContexts? };失败 { isError:true, error:{ message, info? }, content, ... }。注册表在渲染前快照、验证、冻结规范值,再物化持久呈现字段。
并行执行策略
ctx.tools.executionMode(exec) 返回 parallel 仅当可见定义的 isConcurrencySafe(args) 分类器恰好返回 true;未知/隐藏/未声明/无效/抛出分类一律 exclusive(串行)。loop 维护有界滚动池并在启动前重新分类。
出处:
packages/core/agent-loop/README.md(maxParallelToolCalls配置,默认 10;1 为串行)
取消语义
协作式且安静:每个类型化调用都带调用者拥有的 AbortSignal;工具体接收只读 exec.signal。调用体前取消 = ABORTED_BEFORE_DISPATCH;调用后取消只能把成功结果替换为 ABORTED;deny、包裹器失败、工具失败、post 策略失败、超时拥有的 TOOL_TIMEOUT 更具体。每个异步工具必须观察或转发 signal,且只在自有工作停止后 settle。
出处:
packages/core/tools/README.md(deepseek-harness-src/packages/core/tools/README.md)与 cooperative-tool-cancellation Agent Note
UI 呈现意图
工具通过 presentCall / presentResult 返回 provider 中立的 card 标签渲染意图(generic / terminal / diff / locations),让 UI 呈现该工具自己的调用卡片。官方约定:"一个工具的 UI 渲染意图是其设计的一部分,事先决定;呈现方法是 args 的纯函数"(AGENTS.md)。
如何添加一个工具
官方 cookbook:docs/cookbook/adding-a-tool.md 提供分步指南;本站 4.1 添加一个工具 有中文讲解。
小结
工具流水线是"策略即插件"的样板:允许/拒绝、超时/重试、内容替换、UI 呈现各自是流水线上的独立阶段,可被任意插件监听/包裹,且注册表保证每个结果都规范化、冻结、可观察。全量工具目录(schema 与包归属)见 docs/tool-catalog.md。
参考资料
- packages/core/tools/README.md — 工具注册表与执行管线(
deepseek-harness-src/packages/core/tools/README.md) - docs/tool-execution-pipeline.md — 管线可视化(
deepseek-harness-src/docs/tool-execution-pipeline.md) - docs/tool-catalog.md — 工具目录(生成)(
deepseek-harness-src/docs/tool-catalog.md) - docs/cookbook/adding-a-tool.md — 添加工具指南(
deepseek-harness-src/docs/cookbook/adding-a-tool.md)