从 DeepSeek Harness 看:Tool 注册成功,为什么还不等于安全可用

从 DeepSeek Harness 看:Tool 注册成功,为什么还不等于安全可用

一个工具出现在模型的 Tool 列表里,只能证明一件事:模型可能知道它叫什么、接收什么参数。

它不能证明 Provider 已经装载,不能证明参数经过审批,不能证明 Sandbox 覆盖网络和进程,更不能证明工具执行到一半失败时,外部文件、数据库或云资源已经回滚。

这正是 Agent 工具系统最危险的错觉:把"模型能发出 Tool Call"误当成"系统安全完成了副作用"。

DeepSeek Harness 的固定源码把这条链拆得很细:模型 Schema、参数解析、pre-execute 决策、审批、monotonic guard、execute wrapper、工具 body、post policy、结果规范化、finalize 与 Session tool/result。这些位置为治理提供了抓手,但不会自动替团队完成安全设计。

本文只回答一个问题:从 Tool 注册到真实副作用,中间究竟要经过哪些门,哪些边界仍在 Harness 之外?

核心结论是:安全可用不是一个 ToolDefinition 属性,而是一条从模型协议到执行世界的证据链。任何一段只"存在"而没有行为验证,都不能替代整条链。

第一层错觉:Schema 对上了,工具就可用

固定 Tools 文档把一个注册工具拆成两部分:模型可见 ToolSchema,以及宿主内部的输出声明、execute、超时、并发分类、finalize 和 UI Presenter。

模型请求只收到白名单字段,例如名称、描述和参数 Schema;execute、输出渲染、超时、并发安全分类与 UI 回调不会泄露到 Wire。

因此,Schema 只是一份模型协议。它没有回答:

  • 参数是否真的能映射到 Provider;
  • Provider 缺失时返回什么稳定错误;
  • Tool body 是否遵守取消;
  • 输出是否满足声明的 JSON Schema;
  • 真实副作用属于谁,失败后怎样补偿;
  • 结果中是否泄露路径、凭据或内部元数据。

固定工具目录就提供了多个反例。LSP Schema 可以始终存在,但没有 Provider 时返回 LSP_UNAVAILABLEread_image 的注册依赖附件服务,执行时还要求当前精确模型路由支持图像输入;Web Tool Schema 稳定,具体搜索和抓取后端则在 ctx.web 后面替换。

"模型看得见"和"运行时做得到"必须分别验证。

第二层错觉:pre-execute 可以随意修正参数

旧式中间件经常在执行前偷偷改写请求,例如把相对路径变成绝对路径,或删除危险选项。固定 DeepSeek Harness 源码刻意不允许 tools/pre-execute 改写参数。

原因是参数已经用于日志、UI 与审计。若策略看到的是 A、工具实际执行的是 B,Tool Call 与真实副作用就失去一致性。

固定 PreToolDecision 只有三种:

  • allow
  • deny(reason)
  • ask(reason?)

需要参数规范化的工具,应在明确的 Schema 和工具实现合同里完成,而不是让任意策略插件在审计之后悄悄换值。

这条限制很重要:安全系统首先要保证"记录的调用"和"实际执行的调用"是同一个身份,再讨论是否放行。

第三层错觉:审批通过后,后续策略就不能拒绝

固定管线先运行 tools/pre-execute。当决策为 ask 时,ctx.approval 只对本次调用返回 allowed-once 才继续;拒绝、取消、缺少服务、没有可回答通道或无 Agent 身份都会变成 deny。

但 allowed-once 不是最终无条件授权。审批之后,monotonic guards 仍会运行。

Guard 的返回类型没有 allow

text 复制代码
undefined  -> 不增加限制
reason     -> 拒绝

正因为没有 allow,后加载的 Guard 无法把前面的拒绝翻转成允许。它只会维持当前状态或进一步收紧。

这解决的是策略组合顺序问题,而不是所有授权问题。团队仍要决定哪些规则必须进入 Guard,哪些仅是可重排的 pre policy,审批者看到了什么参数,批准范围是单次调用、某个路径还是某段会话。

如果关键安全策略被错误地写成普通 waterfall listener,单调性保证并不会自动覆盖它。

一次工具调用的完整执行链

固定源码中的主路径可以整理为:

text 复制代码
model tool call
  -> tool/call 记录
  -> 参数 JSON 物化、冻结与身份分配
  -> tools/pre-execute: allow / deny / ask
  -> approval(如需要)
  -> monotonic guards
  -> tools/execute wrappers
  -> ToolDefinition.execute body
  -> tools/post-execute
  -> 结果规范化
  -> ToolDefinition.finalizeContent
  -> tools/result 不可变观察
  -> Session tool/result

tools/execute 适合围绕 body 增加超时、重试和指标;tools/post-execute 可以接受、替换结果投影或阻断;finalizeContent 是工具拥有的最后内容约束;tools/result 看到的是已经冻结的权威 outcome,观察者不能再变换它。

未知工具、参数错误、body 抛错、输出 Schema 不匹配、Renderer 失败或策略拒绝都会被规范化成结构化错误。固定文档明确:未知和抛错工具会失败,但不必因此结束整个 Turn,模型仍可能看到错误并采取下一步。

"错误能进入模型"不等于"外部副作用已经回滚"。

canonical value、模型内容与持久结果也不是一回事

工具 body 返回 canonical JSON value。注册表验证它、冻结它,再由输出 Renderer 生成模型可见 ContentBlock;可选 Presenter 生成 UI 元数据。

固定源码只把 content、结构化错误与 meta 写入持久 tool/result,canonical value 留在本次执行内。回放可以重现展示,却不保证重建当时的中间 value。

这意味着,真正需要恢复或审计的业务事实不能只藏在内存 canonical value 里。工具应把必要的稳定结果放进可持久投影,或者由自己的领域事件记录。

同时,Post Policy 只替换 content 并不是保密机制:执行内 canonical value 仍然存在。必须隐藏程序值时,应 block 或替换 value,而不是只把显示文字改成"已处理"。

Capability Seam:工具与 Provider 必须分别验收

很多 DeepSeek Harness 工具是 Consumer:文件工具消费 ctx.fs,Web 工具消费 ctx.web,LSP 工具消费 ctx.lsp,Bash 工具消费 Shell/Subprocess/Sandbox 等能力。

这种分层的好处是模型 Schema 可以稳定,Provider 可以按部署替换。代价是验收不能停在 Tool package:

  1. Service Definition 是否覆盖所需能力;
  2. Provider 是否真实存在并正确报告不可用;
  3. Consumer 是否处理 Provider 的错误、取消与边界;
  4. 多个 Provider 是否保持路径、流、权限和结果语义;
  5. 最终组合是否真的装载了目标 Provider。

一个"工具注册成功"的测试只覆盖 Consumer 与 Registry 的局部关系。它没有覆盖执行世界。

Sandbox 的准确边界:文件效果,不是所有安全问题

固定 Process Sandbox 文档把模式写得非常明确:

  • read-only
  • workspace-write
  • danger-full-access

这套词汇治理的是文件效果。网络和进程可见性明确在其范围之外。read-only 不代表命令不能联网,workspace-write 也不代表子进程、系统调用和凭据已经隔离。

本地 Provider 可以使用 Linux bwrap/Landlock、macOS Seatbelt 或 Windows ACL Restricted Token,但执行完整性会报告为 fullpartial。旧 Landlock ABI 与 Windows 某些 ACL/硬链接边界属于 partial,要求绝对边界的消费者不能把 partial 当 full。

若要求 confined 模式而没有可用 Provider,ctx.sandbox 必须 fail closed,不能静默裸跑。相反,danger-full-access 本来就绕过 confinement,不会调用 Sandbox Provider。

容器、microVM 与远程执行在官方架构里是完整执行能力 seam 的其他实现,不是把 ctx.sandbox 换个 Provider 就自动获得的同一种保障。

因此,生产环境至少还要单独治理:网络出口、进程/系统调用、密钥最小权限、外部 API 授权、宿主文件、审计与资源配额。

文件观察策略降低覆盖风险,但不替代事务

文件工具可以在执行路径中产生 fs/observedfs/write-intentfs/edit-intent 等事件。配套观察策略要求修改前先读到目标状态,避免模型基于过期内容直接覆盖文件。

这是一层 Harness 并发门槛,不是底层事务。读取之后文件仍可能被其他进程修改;符号链接、原子重命名、版本控制冲突、权限变化和远端文件系统一致性仍需 Provider 与存储层处理。

"先观察再编辑"证明的是意图链更清楚,不证明文件操作天然原子或无竞态。

Code Mode 不应成为绕过工具管线的后门

工具数量增多时,把全部 Schema 直接放入模型请求会增加 token 与选择噪声。Code Mode 可以只向模型提供保留传输工具 run_code 和 SDK 能力描述,由程序通过 binding 发起子调用。

固定工具目录和 Tools 文档明确,这些 sub-call 会携带父执行身份,重新进入完整的受保护管线,并产生 tool/code-dispatch 记录。并发安全的 body 可以在上限内重叠,但策略和提交顺序仍由 Runtime 管理。

因此,Code Mode 缩小的是模型协议表面,不是安全门禁。若某个实现让 run_code 直接调用本地函数、跳过审批与 Guard,它已经破坏了固定契约。

从注册到副作用的安全验收表

层级 必须验证 不能用什么替代
Model Schema 名称、描述、参数与部署能力一致 工具出现在目录里
Registration 重复注册、卸载、Scope 与 Provider 缺失 TypeScript 编译通过
Arguments JSON 物化、冻结、Schema 校验与审计一致 pre hook 偷偷改参数
Approval 谁批准、看到什么、范围与时效 UI 出现过确认框
Guard 安全拒绝单调、顺序不可翻转 普通 middleware 返回 allow
Provider 错误、取消、路径、流式与平台差异 稳定 Tool Schema
Sandbox 文件模式、full/partial、fail closed read-only 等于无网络/无进程
Side effect 幂等键、超时、部分成功、补偿与重试 结构化 isError
Result value/content/meta、泄密、截断与持久事实 UI 卡片显示成功
Replay tool/call/result 配对及必要领域事实 单次本地 smoke
Code Mode 子调用回到完整管线并关联父执行 run_code 本身被审批一次

这张表是本文的主要产物。它要求每一层提供自己的证据,而不是用最上层的 Schema 或最下层的一次成功执行替代整条链。

结论

DeepSeek Harness 的工具系统把模型协议、策略决策、单调拒绝、执行包装、Provider、结果规范化和持久事实分开。它为安全组合提供了明确位置,也暴露了"工具注册成功"到底有多局部。

真正的安全可用必须一直追到副作用:参数是否与审计一致,审批和 Guard 是否覆盖正确范围,Provider 是否可用,Sandbox 究竟约束什么,部分失败能否补偿,结果是否成为稳定事实。

尤其要记住两个边界:固定 SandboxMode 只描述文件效果;结构化错误只描述 outcome,不自动回滚已经发生的外部动作。

所以,最合理的验收问题不是"模型能不能调用这个工具",而是"这条调用在每个阶段由谁拥有、能被谁拒绝、留下什么事实、失败后还有哪些副作用"。

参考资料

  1. 固定 Commit Tools Subsystem:github.com/deepseek-ai...
  2. 固定 Commit Tool Execution Pipeline:github.com/deepseek-ai...
  3. 固定 Commit Tool Catalog:github.com/deepseek-ai...
  4. 固定 Commit Process Sandbox:github.com/deepseek-ai...
  5. 固定 Commit Architecture:github.com/deepseek-ai...

证据与推导边界

  • ToolDefinition、Schema、管线、Guard、结果字段:固定 Commit 官方文档事实。
  • Sandbox 文件效果、full/partial 与 fail closed:固定 Commit 官方文档事实。
  • 安全验收表与外部副作用治理:作者工程建议。
  • 研究包示例代码:NOT-RUN 模板,未作为独立扩展编译或联网运行。
  • 真实模型 Tool Call、跨平台 Sandbox、外部系统幂等与生产恢复:未验证,不作结论。
相关推荐
Uncommon.1 小时前
使用Pytorch操作张量(多维数组)
人工智能·pytorch·python
CTA量化套保1 小时前
量化脚本准备实盘了吗?TqSdk 上线前工程检查
人工智能·python
暂时先用这个名字1 小时前
安装deepseek harness及插件
人工智能·ai·npm·pnpm·deepseek·深度求索·harness
水如烟1 小时前
孤能子视角:EIS认识论分册总纲——同一认知呼吸的四次显影
人工智能
海兰1 小时前
mcporter — 安装部署及使用完全指南(一)
人工智能·agent·mcp
skywalk81631 小时前
用WorkBuddy成功把Deepseek Harness移植到FreeBSD
人工智能·deepseek·harness
JavaPub-rodert1 小时前
我把 OpenAI 协议塞进了 Go 工具库:go-commons 开始支持 AI 了
开发语言·人工智能·golang
HZZD_HZZD1 小时前
非侵入式负荷监测选`Seq2Point`还是`LSTM`?合众致达实测:洗衣机分解F1达0.87、`NDE`误差降27%,附PyTorch完整实现
人工智能·pytorch·lstm