尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
HoRain云--DeepSeek Harness 工具执行流水线与权限门禁
但现在有个疑问模型发出一条工具调用之后到工具真正执行、结果回到模型中间到底走了哪些环节本章节我们将讲清楚 dsh 的「工具执行流水线」以及如何用钩子插件实现权限门禁。一句话一次工具调用会按固定顺序经过多个环节每个环节负责一类策略钩子插件可以在其中允许、拒绝或询问。流水线的整体顺序工具执行不是「调用一下函数」那么简单而是一条有固定顺序的流水线。官方文档把顺序概括为tools/pre-execute → 单调守卫 → tools/execute → tools/post-execute → finalizeContent → tools/result。其中前三个 waterfall 可以改写一次调用而由定义自身控制的 finalizeContent 与 tools/result 在其后运行。先看两个容易混淆的概念waterfall瀑布式事件是一种事件分发模式监听器可以调用next()把决定权委托下去也可以直接返回一个决策短路。单调守卫monotonic guard是一道只允许缩减、不允许撤销的最终防线。下面逐个环节拆开讲。tools/pre-execute可重排的策略层tools/pre-execute是流水线中第一个 waterfall负责承载「钩子、权限、沙箱」这一类可重排的策略。它之所以叫「可重排」是因为监听器可以通过next()把决定权传给下一个监听器多个策略插件的先后顺序可以在配置里调整。这个 waterfall 返回一个类型化决策 PreToolDecision有三种取值决策含义后续行为{ kind: allow }放行这次调用继续走单调守卫与之后的环节{ kind: deny; reason: string }拒绝这次调用物化成一个错误结果工具主体被跳过{ kind: ask; reason?: string }询问用户只有审批服务返回allowed-once才继续否则拒绝注意ask分支它会触发ctx.approval的一次性询问这一块留到下一篇展开。参数不可被改写因为历史记录、审计、UI 与执行必须保持一致。什么时候用 pre-execute当策略需要「允许、拒绝或询问」三类动作之一且希望策略之间可以自由排序时用它。沙箱、权限、plan-mode 等插件都用这个扩展点。单调守卫不可撤销的最终拒绝waterfall 的缺点是后注册的监听器可以推翻前面监听器的决策。当某个不变式invariant需要「最终拒绝、且任何人都不能撤销」时就要用ctx.tools.guard()。守卫的类型是 ToolGuard它故意没有 allow 结果返回字符串表示拒绝返回undefined表示维持现状。// ToolGuard感知作用域的最终预分派策略 type ToolGuard (execution: ReadonlyToolExecution) string | undefined因为守卫没有 allow 结果所以监听器的顺序永远无法把一次拒绝变回允许。这就是「单调」的含义只减不增只收权限不给权限。实践原则可重排的策略放tools/pre-execute必须「最终生效、不可撤销」的不变式放ctx.tools.guard()。tools/execute 与 tools/post-executetools/execute负责「环绕分派」也就是把真正调用工具主体这件事包起来。超时、重试、指标收集都在这一层做它包装的是实际分发生命周期。它拿到的视图是 ToolDispatchExecution只有这一个视图可以替换必需的exec.signal用来施加截止时间。替换规则是可以替换但不能移除注册表会在调用工具主体前重新融合调用方的 signal。tools/post-execute负责在工具执行完、结果归一化之前做检查或改写它返回 PostToolDecision决策含义{ kind: accept; content? }接受结果可替换展示内容保留规范值与元数据{ kind: accept; value }接受结果可替换规范值会重新校验并重算内容{ kind: block; feedback }阻止结果把纠正反馈变成错误结果内容替换是展示策略不是保密策略。要隐藏程序化值必须替换该值或阻止结果。finalizeContent 与 tools/resultfinalizeContent是工具定义ToolDefinition自己拥有的回调注册表恰好调用它一次。它是「最后的仅内容不变式」同步执行只允许做内容层面的最后修正。在这之后注册表会物化并冻结已接受的结果然后触发tools/result。tools/result是同步通知用来观测冻结的、不可变的权威结果。观测者无法变换结果观测者的失败也会被隔离不会影响主流程。需要「审计、指标、捕获最终结果」时用它需要「变换结果或附加上下文」时才用tools/post-execute。选型记忆法pre-execute 决定「能不能做」execute 决定「怎么做」post-execute 决定「结果怎么呈现」result 只负责「看一眼最终结果」。动手示例写一个权限门禁插件官方文档以「权限门禁」为例展示钩子插件如何使用tools/pre-execute。钩子插件就是普通的 Cordis 插件并不需要外部协议。实例// 文件路径my-plugins/permission-gate/src/index.ts// 一个基于 tools/pre-execute 的权限门禁插件。// 它返回类型化的决策命中黑名单就 deny否则调用 next() 委托下去。import type { Context } from deepseek-ai/cordisimport type { PreToolDecision, ToolExecution } from deepseek-ai/dsh-tools// 黑名单runoob 项目里禁止直接写文件系统的工具。// 这里用最简单的集合演示真实项目里可以查数据库、问审批服务。const DENY_TOOLS new Set([fs_write, fs_edit])// 策略判定函数返回这次调用是否被允许。// exec 携带不可变的调用身份callId、name、arguments、agent、token、signal。async function isAllowed(exec: ToolExecution): Promiseboolean {if (DENY_TOOLS.has(exec.name)) return false// 额外示例runoob 演示里禁止修改 .env 文件参数在进入策略前已被冻结。const raw exec.arguments as { path?: string }if (typeof raw.path string raw.path.includes(.env)) return falsereturn true}export const name permission-gateexport function apply(ctx: Context) {// tools/pre-execute 是 waterfall监听器可以返回决策或调用 next() 委托。ctx.on(tools/pre-execute, async (exec, next): PromisePreToolDecision {if (!(await isAllowed(exec))) {// 返回 deny 会立即终止这次调用后续监听器不再执行。return { kind: deny, reason: Denied by policy: this tool is not allowed in the runoob workspace. }}// 放行把决定权交给流水线中后续的监听器。return next()})}这个插件加载后模型每次调用工具都会先经过它。命中黑名单的工具会得到一个带 reason 的错误结果工具主体被跳过。因为它返回的是类型化决策其它策略插件仍然可以在它之后继续参与决策。动手示例用 tools/execute 加超时超时属于「环绕分发」关注点应该用tools/execute包裹而不是写进工具主体。实例// 文件路径my-plugins/tool-guard/src/index.ts// 用 tools/execute 包装实际分发生命周期给每次工具调用加 30 秒超时。import type { Context } from deepseek-ai/cordisexport const name tool-guardexport function apply(ctx: Context) {// tools/execute 是 waterfall必须调用 next() 才会执行真正的工具主体。ctx.on(tools/execute, async (exec, next) {// 注意只有 tools/execute 视图可以替换 exec.signal。// 这里把调用方信号与一个 30 秒截止时间融合覆盖掉原来的 signal。const originalSignal exec.signalconst deadline AbortSignal.timeout(30_000)exec.signal AbortSignal.any([originalSignal, deadline])try {// 委托给真正的工具 execute()超时或调用方取消都会触发 abort。return await next()} finally {// 用完后恢复原信号避免污染后续调用。exec.signal originalSignal}})}规则可以替换 exec.signal但不能移除它。注册表会在调用工具函数体前重新融合调用方的 signal因此包装层替换掉 signal 是安全的。动手示例用 ctx.tools.guard() 做单调拒绝当不变式需要「最终拒绝、不可撤销」时用ctx.tools.guard()。注意守卫返回类型是string | undefined没有 allow 分支。实例// 文件路径my-plugins/invariant-guard/src/index.ts// 一个不可撤销的最终拒绝禁止在 runoob 演示环境执行 run_code。import type { Context } from deepseek-ai/cordisexport const name invariant-guardexport function apply(ctx: Context) {// 注册一个单调守卫。返回字符串即拒绝返回 undefined 表示维持现状。const disposer ctx.tools.guard((execution) {if (execution.name run_code) {return run_code is disabled in the runoob demo profile.}return undefined // 放行让 pre-execute 的决策保持不变})// guard() 返回精确的卸载函数插件卸载时框架会自动调用它。ctx.effect(() disposer)}因为守卫没有 allow 结果即使后面有监听器想放行run_code也无法把这次拒绝变回允许。小结自测工具执行流水线把「策略」与「工具主体」解耦让钩子可以跨越不同工具系列而无需让工具耦合某个策略服务。自测题问题参考想让某个工具「永远无法被任何人放行」应该用 pre-execute 还是 guardguard因为守卫没有 allow 结果不可撤销要给所有工具加统一的超时应该监听哪个事件tools/execute它环绕分派可替换 signal只想记录最终结果做审计、不改任何东西应该用哪个环节tools/result它观测冻结的权威结果
RELATED

相关推荐

如何用 XunziALLM 翻译与注释古籍文本?古文语言模型完整指南

如何用 XunziALLM 翻译与注释古籍文本?古文语言模型完整指南

如何用 XunziALLM 翻译与注释古籍文本?古文语言模型完整指南 【免费下载链接】XunziALLM 项目地址: https://gitcode.com/gh_mirrors/xu/XunziALLM 校对《荀子》无标点原本、整理古籍语料时,最耗时的往往不是"读",而是翻译…

📅 2026/10/19 21:04:31
WindowTabs 完整指南:用浏览器式标签管理桌面窗口,如何快速告别任务栏堆叠

WindowTabs 完整指南:用浏览器式标签管理桌面窗口,如何快速告别任务栏堆叠

WindowTabs 完整指南:用浏览器式标签管理桌面窗口,如何快速告别任务栏堆叠 【免费下载链接】WindowTabs 项目地址: https://gitcode.com/gh_mirrors/wi/WindowTabs WindowTabs 是一款把浏览器式标签页引入桌面的窗口管理工具:它把一个…

📅 2026/10/19 21:04:49
探索min函数的强大功能

探索min函数的强大功能

min函数的作用有一种常用函数叫min函数, 它的作用是返回一组数据里的最小值, min()函数的输入能够是一个列表, 也能够是一个元组, 还能够是一个由数字所组成的序列。min() 函数语法:min(args)args为要比较的参数,可以是数字、列表、元组等。1. 计算列表、…

📅 2026/10/12 10:09:16
MORE NEWS

更多资讯

📰

Python+大模型+微博舆情分析:从数据采集到可视化全链路实战指南

每年到毕业设计季,“微博舆情分析”这个方向都会被大量同学翻牌,尤其是加上Python和大模型之后,听起来既有技术含量又紧跟热点。但真正动手之后很多人会发现:微博数据怎么拿、情感分析怎么做准、大模型怎么接、预测结果怎么才能不…

📰

浅层模型与深度神经网络的选型之道:从特征工程到工程成本的全面对比

做算法这些年,我参加过的技术选型会里,争论最热烈的永远是同一个话题:传统机器学习(浅层模型)和深度学习(深度神经网络)到底该选哪个。上周项目评审,我提的方案是先上XGBoost搭基线&…

📰

Qt通过COM操作Word生成文档:完整实战指南

1. 为什么项目里总会冒出"Qt输出Word"的需求做了几年Qt桌面端开发,你会发现一个规律:凡是涉及业务系统、办公自动化的项目,十有八九会碰到"在程序里生成Word文档"这种需求。比如项目里要定期输出月度报告、按模板生成合同…

📰

Spring Boot四层XSS防御实战:过滤器+包装器+CSP+输出编码

我处理项目里那个"搜索框变成按钮"的Bug,才真正理解XSS不是文档里的一句名词,而是能在几分钟内把Cookie、页面内容、用户操作全部劫走的入口。当时用Spring Boot做的后台管理系统,前端同学随手往标题栏输入了一段带尖括号的内容&am…

📰

U2-Flash 1M上下文实测:从能塞到能用的工程实践

1. 当"1M上下文"不再是PPT上的数字第一次看到"1M上下文"这个说法,我的反应是:又一个拿理论值说事的营销话术。做过大模型应用的人都知道,上下文窗口标称值和实际可用值之间,往往隔着一道叫"注意力衰减&q…

📰

双麦克风语音分离:基于GCC-PHAT与IVA的轻量级实时声源解耦方案

简介:本资源是一套基于MATLAB实现的双麦克风语音分离完整源码工程,面向音频信号处理初学者、语音算法研究者及高校相关课程实践者,聚焦于利用TDOA与空间滤波技术从混合语音中分离目标声源,适用于噪声抑制、会议系统增强与语音识别…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬