🐎 第8章 器以载道:Agent SDK 智能体开发套件
📄 一句话概括

SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。 它们是串联的,前面拦住后面就不看了。 实测六个动作拦住四个,分布在后三道。而「改 .env」四道全过——四道管的是越界,不管敏感。

📝 本章和前面几章的关系

上一节是你自己写的拦截,这一节是它自带的那几道。 这一节的结论有点扎心:四道防线里有一道要你自己写,而且那道恰好管得最细。

一、四道各管什么

一 权限模式:这次是只读还是能动手。粗粒度,也最可靠。 二 工具白名单:哪几个工具能用。给了 Read,就等于能读所有能读的路径。 三 路径限制:工具能碰哪些路径。这一道选项里没有,得自己写。

四 成本上限:最多跑几轮、花多少。前三个都过了,它可能是第两百轮才出问题。 四道各管一个维度:态度、工具、目标、时长。缺一个就有一类事没人管。

二、真跑:六个动作逐个过四道

演示里六个动作:读项目内文件、写 /etc/passwd、跑 rm -rf、改 .env、读上级目录、第 16 次调用。 结果拦住四个:两个路径越界、一个工具不在白名单、一个轮数超上限。 第一道一个都没拦——因为这次用的是能动手的模式。它像总闸:切成只读,后面三道大部分都用不上。

还有一条要看清:「改 .env」四道全过了。它在项目内、Edit 也在白名单里。 所以四道防线管的是「越界」,不管「敏感」——敏感文件得靠 8.7 节那种钩子单独拦。

三、为什么是四道

权限模式管「整体态度」。它最粗,但最不容易被绕过:只读就是只读。 白名单管「用什么」。它挡的是「能力过宽」:不需要跑命令,就别给 Bash。 路径限制管「对谁」。这是白名单管不到的:给了 Edit 不等于该给所有文件。

成本上限管「多久」。它挡的是「跑不完还一直跑」,这是最贵的一种失败。 四个维度正交:任意一个失效,另外三个还在。这就是「纵深」的意思。

四、顺序为什么不能换

如果成本上限放最前面,你会先看到「轮数超了」,而真正的原因是它一直在试一个被拦的路径。 所以顺序该按「谁最能说明问题」排:粗的先、细的后。 这也解释了为什么第一道是模式而不是白名单:模式决定的事更大。

反过来说,看到「轮数超了」这种错误,先别急着调大上限——先看看它在刷什么。

五、自己补第三道

现实写法:把项目根算成绝对路径,判断目标路径是不是它的子路径。 别用「字符串以项目根开头」判断——那条会被 ../ 绕过,也会把 myproject2 当成 myproject 的子目录。 要先把路径规范化(消掉 ../ 和符号链接)再比,这是这一道最容易写错的地方。

补完这一道,四道才齐。而补它的成本,比事后处理一次越界写盘小得多。

六、动手 Demo:六个动作,四道防线各拦下几个

SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。 它们是串联的:前面拦住,后面就不看了。六个动作逐个过一遍。

if turns > 15:                              gate = 4   # 成本上限
elif path.startswith(u"/") or path.startswith(u".."):  gate = 3   # 路径越界
elif tool not in ALLOW:                     gate = 2   # 工具白名单
else:                                       gate = 0   # 全过

实跑输出:

--------------------------------------------------------------------
六个动作,四道防线各拦下几个
--------------------------------------------------------------------

  SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。
  它们是串联的:前面拦住,后面就不看了。所以顺序决定了你会看到哪条错误。

  ① 四道防线各管什么
  --------------------------------------------------------------------
| 防线 | 管什么 | 落在哪 |
|---|---|---|
| 一 权限模式 | 它整体是只读还是能动手 | plan、default、acceptEdits |
| 二 工具白名单 | 哪几个工具能用 | allowed_tools |
| 三 路径限制 | 工具能碰哪些路径 | 在工具实现或钩子里判断 |
| 四 成本上限 | 最多跑几轮、花多少 | max_turns、预算 |

  注意第三道不在选项里——它得自己写。这是四道里最容易漏的一道。

  ② 真跑:六个动作逐个过四道
  --------------------------------------------------------------------
| 动作 | 被哪道拦 | 原因 |
|---|:---:|---|
| 读 src/app.py | 通过 | 全过 |
| 写 /etc/passwd | 第 3 道 | 路径在项目外 |
| 跑 rm -rf build | 第 2 道 | 工具不在白名单 |
| 改 .env | 通过 | 全过 |
| 读 ../other/x.py | 第 3 道 | 路径在项目外 |
| 又跑了第 16 次调用 | 第 4 道 | 轮数超上限 |

  六个动作里 4 个被拦,分布在第二、三、四道各 1、2、1 个。
  第一道一个都没拦——因为这次用的是能动手的模式。它是「总闸」:切成只读,后面三道大部分都用不上了。
  还有一条要看清:「改 .env」四道全过了。它在项目内、Edit 也在白名单里。
  所以四道防线管的是「越界」,不管「敏感」——敏感文件得靠钩子单独拦(8.7 节)。

  ③ 四道的分工为什么是四道
  --------------------------------------------------------------------
  权限模式管「整体态度」:这次是看还是改。它是粗粒度的,也最可靠。
  白名单管「用什么」:给了 Read 就等于能读所有能读的路径。
  路径限制管「对谁」:这是白名单管不到的那一层。
  成本上限管「多久」:前三个都过了,它可能是第两百轮才出问题。
  四道各管一个维度,缺一个就有一类事没人管。

  ④ 顺序为什么不能换
  --------------------------------------------------------------------
  如果成本上限放最前面,你会先看到「轮数超了」,而真正的原因是它一直在试一个被拦的路径。
  所以顺序该按「谁最能说明问题」排:粗的先、细的后。
  这也解释了为什么第一道是模式而不是白名单:模式决定的事更大。

  ⑤ 自己补第三道
  --------------------------------------------------------------------
  路径限制的现实写法:把项目根算成绝对路径,然后判断目标路径是不是它的子路径。
  别用「字符串以项目根开头」判断——那条判断会被 ../ 绕过。
  要先把路径规范化再比,这是这一道最容易写错的地方。
  ! 四道的划分是这一课的归纳,真实实现里它们可能由不同机制提供。

①四道:权限模式(整体态度)、工具白名单(用什么)、路径限制(对谁)、成本上限(多久)。 四道各管一个维度,正交。 ②六个动作拦住四个:两个路径越界、一个工具不在白名单、一个轮数超上限。 第一道一个都没拦,因为这次用的是能动手的模式。 ③「改 .env」四道全过——它在项目内、Edit 也在白名单里。 所以四道管的是「越界」,不管「敏感」,敏感文件得靠钩子单独拦。 ④第三道选项里没有,得自己写:把项目根算成绝对路径,判断目标是不是它的子路径。 别用字符串前缀判断,会被 ../ 绕过。

30 秒实验

  1. 把权限模式切成只读,重跑一遍。六个动作里有几个连第二道都到不了?这说明第一道的价值在哪?
  2. 把 ALLOW 里加上 Bash,重跑一遍。rm -rf 那个动作会被哪一道拦?如果四道都拦不住,还差什么?
  3. 把路径判断从「以 / 或 .. 开头」改成「字符串以项目根开头」,重跑一遍。哪个动作能绕过它?

常见误区

  1. 以为配了白名单就安全。白名单只管「用哪个工具」,不管「对哪个文件用」。
  2. 不写路径限制。四道里只有这一道管「对谁」,其他人管不到。
  3. 用字符串前缀判断路径是否越界。会被 ../ 和同名目录绕过。
  4. 把成本上限当成性能参数。它是安全防线:跑不完还一直跑,是最贵的一种失败。
  5. 把顺序调成「先查成本」。你会先看到「轮数超了」,而真正的原因在别处。
自测三问(点开对答案) 1. 四道防线分别是什么? —— 权限模式、工具白名单、路径限制、成本上限。四道各管一个维度,串联生效。 2. 为什么「改 .env」四道全过? —— 因为它在项目内、Edit 也在白名单里。 四道管的是「越界」,不管「敏感」——敏感文件要靠钩子单独拦。 3. 路径限制该怎么写? —— 把项目根算成绝对路径,规范化目标路径后判断是不是它的子路径。 不能用字符串前缀判断,会被 ../ 绕过。

防线齐了,下一节换个方向:让它输出的东西能被程序直接读。

相关笔记