一、Permissions 是什么
在 DeepAgents 中,Agent 通常可以使用一组内置文件系统工具,例如:
text
ls
read_file
glob
grep
write_file
edit_file
这些工具让 Agent 可以像操作文件系统一样读取目录、搜索文件、写入文件、修改文件。
但是实际项目中,不能让 Agent 想读哪里就读哪里、想写哪里就写哪里。例如:
- 不希望 Agent 读取
.env、密钥文件、用户隐私数据; - 不希望 Agent 修改生产配置、策略文件、共享知识库;
- 只允许 Agent 在
/workspace/目录中工作; - 对某些敏感目录的写入必须先让人审批;
- 子 Agent 只能做代码审查,不能写文件。
这时就需要 DeepAgents 的 permissions。
一句话理解:
text
Permissions 是 DeepAgents 给内置文件系统工具加的一层路径级访问控制。
它通过声明式规则告诉 Agent:
text
哪些操作可以做?
哪些路径可以访问?
遇到匹配规则时是允许、拒绝,还是暂停等待人工审批?
二、Permissions 能管什么,不能管什么
这是学习 Permissions 最容易踩坑的地方。
1. 能管的范围
DeepAgents 官方文档说明,permissions 只作用于内置文件系统工具:
| 操作类型 | 覆盖的工具 | 含义 |
|---|---|---|
read |
ls、read_file、glob、grep |
读取目录、读取文件、查找文件、搜索内容 |
write |
write_file、edit_file |
创建、覆盖、编辑文件 |
也就是说,下面这些行为可以被 permissions 控制:
text
Agent 想 read_file("/workspace/app.py")
Agent 想 grep("/workspace/**/*.py", "password")
Agent 想 write_file("/workspace/a.txt", "hello")
Agent 想 edit_file("/workspace/config.py", ...)
2. 不能管的范围
permissions 不是一个万能沙箱。
它不能覆盖:
- 自定义工具中自己实现的文件读写;
- MCP 工具中的文件读写;
- sandbox backend 里的任意命令执行,例如通过
execute执行 shell 命令; - 业务级权限逻辑,例如限流、审计日志、文件内容检查。
如果你的自定义工具里写了:
python
def dangerous_tool(path: str):
return open(path).read()
那么这个工具是否能读文件,不由 FilesystemPermission 自动控制。你需要在自定义工具内部自己做校验,或者使用 backend policy hooks 之类的更底层策略。
可以这样记:
text
permissions 管 DeepAgents 内置文件工具;
自定义工具、MCP 工具、shell 执行能力,需要额外控制。
三、最小示例:创建一个只读 Agent
下面这个例子禁止 Agent 写任何文件:
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
],
)
解释一下:
operations=["write"]:这条规则只管写操作;paths=["/**"]:匹配所有路径;mode="deny":命中后拒绝。
所以 Agent 仍然可以读文件,但不能写文件。
如果 Agent 尝试调用:
text
write_file("/workspace/demo.txt", "hello")
这属于:
text
write 操作 + 路径匹配 /** + deny
因此会被拒绝。
四、FilesystemPermission 的三个核心字段
DeepAgents 使用 FilesystemPermission 描述一条权限规则。它有三个关键字段:
python
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
)
1. operations:控制操作类型
operations 是一个列表,只能写:
python
["read"]
["write"]
["read", "write"]
对应关系如下:
| operations | 影响的行为 |
|---|---|
read |
看目录、读文件、glob 查找、grep 搜索 |
write |
写文件、编辑文件 |
常见写法:
python
# 只限制写入
operations=["write"]
# 同时限制读写
operations=["read", "write"]
如果你的目标是"可以看但不能改",就只配置 write 的拒绝规则。
如果你的目标是"连看都不能看",就需要同时限制 read 和 write。
2. paths:控制路径范围
paths 是路径 glob 模式列表,例如:
python
paths=["/workspace/**"]
paths=["/workspace/.env"]
paths=["/workspace/examples/**", "/workspace/.env"]
常见匹配方式:
| 写法 | 含义 |
|---|---|
/workspace/** |
/workspace/ 下所有文件和子目录 |
/workspace/*.py |
/workspace/ 这一层的 Python 文件 |
/workspace/.env |
精确匹配 .env 文件 |
/** |
所有路径 |
/projects/*/secrets/** |
/projects/项目名/secrets/ 下所有内容 |
注意:路径通常写成以 / 开头的虚拟文件系统路径,而不是 Windows 的 C:\xxx 或 Linux 的真实磁盘路径。DeepAgents 的 backend 会负责把这些虚拟路径映射到实际存储。
3. mode:控制命中后的处理方式
mode 有三种:
| mode | 含义 | 适用场景 |
|---|---|---|
allow |
允许操作 | 白名单目录、明确可访问路径 |
deny |
拒绝操作 | 敏感文件、禁止写入目录 |
interrupt |
暂停,等待人工审批 | 高风险写入、需要人工确认的变更 |
最常见的是 allow 和 deny。
interrupt 适合这类场景:
text
不是绝对禁止,但每次修改前都要人看一眼。
例如:
- 修改
/secrets/**; - 修改
/production-config/**; - 修改组织级策略
/policies/**; - 修改需要审计的重要文件。
五、最重要的规则:按顺序匹配,首个命中生效
DeepAgents 的权限规则采用:
text
first-match-wins
也就是:
text
从上到下检查规则,第一条同时匹配 operations 和 paths 的规则决定结果。
后面的规则不会再看。
如果没有任何规则匹配,默认是允许。
这点非常重要。
正确示例:先写特殊规则,再写通用规则
需求:
text
允许访问 /workspace/**,
但是禁止访问 /workspace/.env,
其他路径全部禁止。
正确写法:
python
from deepagents import FilesystemPermission
permissions = [
# 1. 先保护最敏感的具体文件
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
# 2. 再允许 workspace 目录
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
# 3. 最后兜底拒绝其他路径
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
为什么要这样排?
因为 /workspace/.env 也属于 /workspace/**。如果先写允许 /workspace/**,那么 .env 会先命中允许规则,后面的拒绝规则就不会生效。
错误示例:通用规则放前面
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
]
这里 .env 会先匹配 /workspace/**,结果是允许。
记住一个经验:
text
权限规则要从具体到宽泛:
具体敏感文件 -> 普通业务目录 -> 全局兜底规则
六、为什么"无匹配默认允许"很关键
官方文档提到,如果没有规则匹配,操作默认允许。
这意味着下面这个配置不是"只允许读 /workspace/":
python
permissions = [
FilesystemPermission(
operations=["read"],
paths=["/workspace/**"],
mode="allow",
),
]
它的实际效果是:
text
读 /workspace/**:命中 allow,允许
读 /other/**:没有规则匹配,默认允许
写任何路径:没有 write 规则匹配,默认允许
所以它几乎没有达到限制目的。
如果你想做白名单,必须加兜底拒绝:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
这才表示:
text
只允许读写 /workspace/**,其他路径全部拒绝。
七、常见场景一:只允许 Agent 在工作区内读写
这是最常见的权限模型。
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
],
)
效果:
| 操作 | 结果 |
|---|---|
读 /workspace/app.py |
允许 |
写 /workspace/result.md |
允许 |
读 /secrets/key.txt |
拒绝 |
写 /tmp/a.txt |
拒绝 |
这个配置适合:
- 代码生成 Agent;
- 文档整理 Agent;
- 只允许在项目工作目录内操作的研发助手;
- 不希望 Agent 访问其他虚拟路径的场景。
八、常见场景二:保护 .env 和示例目录
需求:
text
Agent 可以操作 /workspace/,
但是不能读写 /workspace/.env,
也不能碰 /workspace/examples/**。
代码:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env", "/workspace/examples/**"],
mode="deny",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
匹配过程示例:
text
read_file("/workspace/.env")
-> 命中第 1 条 deny
-> 拒绝
write_file("/workspace/src/app.py")
-> 第 1 条不匹配
-> 第 2 条 /workspace/** 匹配 allow
-> 允许
read_file("/other/data.txt")
-> 第 1 条不匹配
-> 第 2 条不匹配
-> 第 3 条 /** 匹配 deny
-> 拒绝
九、常见场景三:共享记忆只读
DeepAgents 可以通过 backend 把不同路径路由到不同存储,例如:
/memories/:用户长期记忆;/policies/:组织级策略;- 默认路径:临时状态或工作区。
有些文件 Agent 可以读,但不应该由 Agent 直接修改。
例如组织级策略文件:
text
/policies/security.md
/policies/style-guide.md
可以让 Agent 读取它们作为参考,但禁止 Agent 改写:
python
from deepagents import FilesystemPermission, create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
agent = create_deep_agent(
model=model,
backend=CompositeBackend(
default=StateBackend(),
routes={
"/memories/": StoreBackend(
namespace=lambda rt: (rt.server_info.user.identity,),
),
"/policies/": StoreBackend(
namespace=lambda rt: (rt.context.org_id,),
),
},
),
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/memories/**", "/policies/**"],
mode="deny",
),
],
)
这段配置的含义:
text
读 /memories/**:没有匹配 write 规则,因此默认允许
写 /memories/**:命中 deny,拒绝
读 /policies/**:允许
写 /policies/**:拒绝
适合场景:
- 组织级知识库只能由后台管理系统更新;
- 用户长期记忆只能通过审核流程更新;
- Agent 可以参考规范,但不能擅自修改规范。
十、常见场景四:完全禁止文件访问
如果你希望 Agent 完全不能碰文件系统:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
效果:
| 工具 | 结果 |
|---|---|
ls |
拒绝 |
read_file |
拒绝 |
glob |
拒绝 |
grep |
拒绝 |
write_file |
拒绝 |
edit_file |
拒绝 |
这个配置适合:
- 纯对话 Agent;
- 只允许调用业务 API,不允许读写文件;
- 高安全要求环境;
- 先做最小权限,再逐步开放。
十一、interrupt:敏感写入前暂停等待人工审批
mode="interrupt" 是比 deny 更灵活的一种模式。
它不是直接拒绝,而是:
text
当 Agent 尝试执行匹配规则的文件操作时,暂停执行,交给人工审批。
例如:
python
from deepagents import FilesystemPermission, create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model=model,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/secrets/**"],
mode="interrupt",
),
],
checkpointer=InMemorySaver(),
)
这里的含义是:
text
Agent 写 /secrets/** 时,不直接执行,而是触发 human-in-the-loop 中断。
interrupt 为什么需要 checkpointer
因为中断意味着 Agent 要暂停,然后等待人类操作后继续运行。
这就需要保存当前状态:
text
暂停前 Agent 在做什么?
准备调用哪个工具?
工具参数是什么?
审批后从哪里继续?
所以 interrupt 需要配置 checkpointer,例如:
python
checkpointer=InMemorySaver()
生产环境中通常会换成更持久化的 checkpointer。
interrupt 适合哪些场景
interrupt 不适合所有文件操作都审批,否则体验会很差。
它更适合高风险路径:
text
/secrets/**
/production/**
/deploy/**
/policies/**
/billing/**
例如:
python
permissions = [
FilesystemPermission(
operations=["write"],
paths=["/production/**"],
mode="interrupt",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
这个配置表示:
text
写 /production/**:需要审批
读写 /workspace/**:允许
其他路径:拒绝
注意规则顺序:/production/** 必须放在 /** 拒绝规则之前,否则可能被兜底拒绝直接拦掉。
十二、interrupt 路径最好有明确前缀
官方文档特别提醒,interrupt 的路径模式最好有明确的前缀,例如:
text
/secrets/**
/projects/*/secrets/**
不建议写过于模糊的模式:
text
/**/secrets
原因是 ls、glob、grep 这类批量工具会搜索一片目录。对于过于宽泛的模式,系统为了安全可能会保守地触发更多中断,导致审批过于频繁。
实践建议:
text
interrupt 路径尽量写成"明确目录前缀 + 通配符"。
例如:
python
FilesystemPermission(
operations=["write"],
paths=["/projects/*/secrets/**"],
mode="interrupt",
)
十三、子 Agent 的权限
DeepAgents 支持 subagents。默认情况下:
text
子 Agent 会继承父 Agent 的 permissions。
如果你在子 Agent spec 中显式设置 permissions,则:
text
子 Agent 的权限会完全替换父 Agent 的权限,而不是追加。
这一点很重要。
示例:父 Agent 能读写,审查子 Agent 只能读不能写
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
],
subagents=[
{
"name": "auditor",
"description": "Read-only code reviewer",
"system_prompt": "Review the code for issues.",
"permissions": [
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
FilesystemPermission(
operations=["read"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read"],
paths=["/**"],
mode="deny",
),
],
}
],
)
这里父 Agent:
text
可以读写 /workspace/**
而 auditor 子 Agent:
text
可以读 /workspace/**
不能写任何路径
不能读 /workspace/ 之外的路径
适合场景:
- 主 Agent 负责实现代码;
- 子 Agent 负责代码审查;
- 子 Agent 可以读代码,但不能改代码;
- 防止审查 Agent 擅自修复、覆盖文件。
子 Agent 权限的常见误解
很多人会以为子 Agent 的 permissions 是在父权限基础上追加。
实际不是。
如果你写:
python
subagents=[
{
"name": "auditor",
"permissions": [
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
],
}
]
这并不表示:
text
继承父 Agent 的读权限 + 禁止写
而是:
text
子 Agent 只有这一条规则。
由于没有匹配的读规则时默认允许,所以这个子 Agent 可能仍能读取很多路径。
更稳妥的写法是显式补全读权限白名单和兜底拒绝。
十四、CompositeBackend 和 sandbox 的限制
CompositeBackend 可以把不同路径路由到不同 backend。
例如:
python
from deepagents.backends import CompositeBackend
composite = CompositeBackend(
default=sandbox,
routes={
"/memories/": memories_backend,
},
)
这里:
text
/memories/ 走 memories_backend
其他路径走 sandbox
官方文档指出:如果 CompositeBackend 的默认 backend 是 sandbox,那么权限路径必须限制在已知 route 前缀下。
原因是 sandbox 支持任意命令执行。仅靠路径级 permissions 无法阻止 Agent 通过 shell 命令访问文件系统。
可行写法
python
agent = create_deep_agent(
model=model,
backend=composite,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/memories/**"],
mode="deny",
),
],
)
这里 /memories/** 属于明确 route,所以可以做路径权限控制。
可能报错的写法
python
agent = create_deep_agent(
model=model,
backend=composite,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/workspace/**"],
mode="deny",
),
],
)
如果 /workspace/ 没有配置成 route,而是落到 sandbox default,就可能抛出 NotImplementedError。
下面这种也不适合:
python
FilesystemPermission(
operations=["read"],
paths=["/**"],
mode="deny",
)
因为 /** 覆盖了 route 和 sandbox default。对于 sandbox default,单纯路径规则并不足以表达安全边界。
十五、完整实战模板:安全的代码助手权限配置
假设我们要做一个代码助手:
需求:
text
1. 只允许 Agent 在 /workspace/ 内工作;
2. 禁止读取和修改 .env;
3. 禁止修改 /workspace/README.md,但允许读取;
4. 修改 /workspace/deploy/** 时需要人工审批;
5. 其他路径全部禁止。
可以这样写:
python
from deepagents import FilesystemPermission, create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver
permissions = [
# 1. 密钥文件完全禁止读写
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
# 2. 部署目录写入前需要审批
FilesystemPermission(
operations=["write"],
paths=["/workspace/deploy/**"],
mode="interrupt",
),
# 3. README 允许读,但禁止写
FilesystemPermission(
operations=["write"],
paths=["/workspace/README.md"],
mode="deny",
),
# 4. 工作区读写默认允许
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
# 5. 工作区之外全部拒绝
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
agent = create_deep_agent(
model=model,
backend=backend,
permissions=permissions,
checkpointer=InMemorySaver(),
)
逐条解释:
| 路径和操作 | 命中规则 | 结果 |
|---|---|---|
读 /workspace/.env |
第 1 条 | 拒绝 |
写 /workspace/.env |
第 1 条 | 拒绝 |
写 /workspace/deploy/app.yaml |
第 2 条 | 暂停审批 |
读 /workspace/deploy/app.yaml |
第 4 条 | 允许 |
写 /workspace/README.md |
第 3 条 | 拒绝 |
读 /workspace/README.md |
第 4 条 | 允许 |
写 /workspace/src/main.py |
第 4 条 | 允许 |
读 /secrets/key.txt |
第 5 条 | 拒绝 |
这个例子体现了权限设计的典型思路:
text
敏感文件先拒绝;
高风险目录用 interrupt;
普通工作区允许;
最后用 /** 兜底拒绝。
十六、权限设计最佳实践
1. 优先使用白名单模型
不要只写几条 deny,然后让其他路径默认允许。
更推荐:
text
允许明确工作区;
拒绝其他所有路径。
模板:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
2. 具体规则放前面,宽泛规则放后面
推荐顺序:
text
1. 特别敏感文件 deny
2. 高风险路径 interrupt
3. 普通目录 allow
4. 全局兜底 deny
不要把 /workspace/**、/** 这种大范围规则放在太前面。
3. 读写权限分开思考
很多路径可以读但不能写,例如:
- README;
- 规范文档;
- 共享知识库;
- 历史记录;
- 策略文件。
这时不要写:
python
operations=["read", "write"]
而应该只限制写:
python
FilesystemPermission(
operations=["write"],
paths=["/policies/**"],
mode="deny",
)
4. 不要忘记默认允许
只要没有匹配规则,DeepAgents 默认允许。
因此,想要安全收口时,一定要加兜底规则:
python
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
)
5. 自定义工具要单独做安全控制
permissions 不会自动限制自定义工具。
如果你写了自定义工具:
python
def load_file(path: str) -> str:
with open(path, "r", encoding="utf-8") as f:
return f.read()
你应该自己检查路径:
python
from pathlib import Path
WORKSPACE = Path("/safe/workspace").resolve()
def load_file(path: str) -> str:
target = Path(path).resolve()
if not str(target).startswith(str(WORKSPACE)):
raise PermissionError("Only workspace files are allowed")
return target.read_text(encoding="utf-8")
实际生产中还要处理符号链接、路径规范化、租户隔离、审计日志等问题。
6. sandbox 不等于 permissions
如果 backend 提供 execute 工具,Agent 可能通过 shell 命令访问文件。
例如:
text
cat /etc/passwd
find / -name "*.env"
这类能力不是 FilesystemPermission 通过路径规则就能完全管住的。
所以:
text
permissions 是文件工具权限;
sandbox 是执行环境隔离;
两者不能互相替代。
十七、常见错误总结
错误 1:以为 allow /workspace/** 就是只允许 workspace
错误:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
]
问题:
text
其他路径没有规则匹配,默认允许。
修正:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
错误 2:把大范围 allow 放在敏感 deny 前面
错误:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
]
问题:
text
/workspace/.env 先命中 /workspace/**,后面的 deny 不会执行。
修正:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
]
错误 3:给子 Agent 写了局部权限,以为会继承父权限
错误理解:
text
子 Agent permissions = 父 Agent permissions + 子 Agent permissions
正确理解:
text
子 Agent 如果显式设置 permissions,会替换父 Agent permissions。
所以给子 Agent 配权限时,要写完整规则,不要只写一条局部限制。
错误 4:用 permissions 管自定义工具
错误理解:
text
只要配置了 FilesystemPermission,自定义工具也不能乱读写文件。
正确理解:
text
FilesystemPermission 只管 DeepAgents 内置文件系统工具。
自定义工具要自己加权限判断。
十八、速查表
1. 规则字段速查
| 字段 | 示例 | 说明 |
|---|---|---|
operations |
["read"] |
限制读相关工具 |
operations |
["write"] |
限制写相关工具 |
paths |
["/workspace/**"] |
匹配工作区所有内容 |
paths |
["/**"] |
匹配所有路径 |
mode |
"allow" |
允许 |
mode |
"deny" |
拒绝 |
mode |
"interrupt" |
暂停等待人工审批 |
2. 常用模板速查
只读 Agent:
python
[
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
)
]
只允许工作区:
python
[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
保护 .env:
python
[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
敏感目录写入审批:
python
[
FilesystemPermission(
operations=["write"],
paths=["/secrets/**"],
mode="interrupt",
)
]
十九、总结
DeepAgents 的 permissions 是文件系统工具的路径级权限控制机制。
学习时重点抓住五句话:
text
1. permissions 只管 DeepAgents 内置文件系统工具。
2. FilesystemPermission 由 operations、paths、mode 三部分组成。
3. 规则从上到下匹配,第一条命中就决定结果。
4. 没有任何规则匹配时,默认允许。
5. 子 Agent 显式配置 permissions 时,会替换父 Agent 的权限规则。
实际项目中,推荐优先使用白名单策略:
text
先允许必要目录,再用 /** 兜底拒绝。
对于敏感文件,使用 deny;对于高风险但不是绝对禁止的写入,使用 interrupt 接入人工审批。
最后要记住:permissions 是安全设计的一部分,不是全部。自定义工具、MCP 工具、sandbox 命令执行、业务级审计和租户隔离,都需要额外设计。
DeepAgents Permissions 权限机制详解:从概念到实战配置
参考文档:https://docs.langchain.com/oss/python/deepagents/permissions
适用版本:
deepagents>=0.5.2;其中mode="interrupt"需要deepagents>=0.6.8。本文适合发布到 CSDN,目标是用通俗方式讲清楚 DeepAgents 的文件权限机制、规则写法、常见场景和避坑点。
一、Permissions 是什么
DeepAgents Permissions 权限控制完全指南
📖 目录大纲
- [一、Permissions 是什么](#一、Permissions 是什么)
- [二、Permissions 能管什么,不能管什么](#二、Permissions 能管什么,不能管什么)
- [1. 能管的范围](#1. 能管的范围)
- [2. 不能管的范围](#2. 不能管的范围)
- [三、最小示例:创建一个只读 Agent](#三、最小示例:创建一个只读 Agent)
- [四、FilesystemPermission 的三个核心字段](#四、FilesystemPermission 的三个核心字段)
- [1. operations:控制操作类型](#1. operations:控制操作类型)
- [2. paths:控制路径范围](#2. paths:控制路径范围)
- [3. mode:控制命中后的处理方式](#3. mode:控制命中后的处理方式)
- 五、最重要的规则:按顺序匹配,首个命中生效
- 六、为什么"无匹配默认允许"很关键
- [七、常见场景一:只允许 Agent 在工作区内读写](#七、常见场景一:只允许 Agent 在工作区内读写)
- [八、常见场景二:保护
.env和示例目录](#八、常见场景二:保护 .env 和示例目录) - 九、常见场景三:共享记忆只读
- 十、常见场景四:完全禁止文件访问
- 十一、interrupt:敏感写入前暂停等待人工审批
- [interrupt 为什么需要 checkpointer](#interrupt 为什么需要 checkpointer)
- [interrupt 适合哪些场景](#interrupt 适合哪些场景)
- [十二、interrupt 路径最好有明确前缀](#十二、interrupt 路径最好有明确前缀)
- [十三、子 Agent 的权限](#十三、子 Agent 的权限)
- [示例:父 Agent 能读写,审查子 Agent 只能读不能写](#示例:父 Agent 能读写,审查子 Agent 只能读不能写)
- [子 Agent 权限的常见误解](#子 Agent 权限的常见误解)
- [十四、CompositeBackend 和 sandbox 的限制](#十四、CompositeBackend 和 sandbox 的限制)
- 十五、完整实战模板:安全的代码助手权限配置
- 十六、权限设计最佳实践
- [1. 优先使用白名单模型](#1. 优先使用白名单模型)
- [2. 具体规则放前面,宽泛规则放后面](#2. 具体规则放前面,宽泛规则放后面)
- [3. 读写权限分开思考](#3. 读写权限分开思考)
- [4. 不要忘记默认允许](#4. 不要忘记默认允许)
- [5. 自定义工具要单独做安全控制](#5. 自定义工具要单独做安全控制)
- [6. sandbox 不等于 permissions](#6. sandbox 不等于 permissions)
它通过声明式规则告诉 Agent:
text
哪些操作可以做?
哪些路径可以访问?
遇到匹配规则时是允许、拒绝,还是暂停等待人工审批?
二、Permissions 能管什么,不能管什么
这是学习 Permissions 最容易踩坑的地方。
1. 能管的范围
DeepAgents 官方文档说明,permissions 只作用于内置文件系统工具:
| 操作类型 | 覆盖的工具 | 含义 |
|---|---|---|
read |
ls、read_file、glob、grep |
读取目录、读取文件、查找文件、搜索内容 |
write |
write_file、edit_file |
创建、覆盖、编辑文件 |
也就是说,下面这些行为可以被 permissions 控制:
text
Agent 想 read_file("/workspace/app.py")
Agent 想 grep("/workspace/**/*.py", "password")
Agent 想 write_file("/workspace/a.txt", "hello")
Agent 想 edit_file("/workspace/config.py", ...)
2. 不能管的范围
permissions 不是一个万能沙箱。
它不能覆盖:
- 自定义工具中自己实现的文件读写;
- MCP 工具中的文件读写;
- sandbox backend 里的任意命令执行,例如通过
execute执行 shell 命令; - 业务级权限逻辑,例如限流、审计日志、文件内容检查。
如果你的自定义工具里写了:
python
def dangerous_tool(path: str):
return open(path).read()
那么这个工具是否能读文件,不由 FilesystemPermission 自动控制。你需要在自定义工具内部自己做校验,或者使用 backend policy hooks 之类的更底层策略。
可以这样记:
text
permissions 管 DeepAgents 内置文件工具;
自定义工具、MCP 工具、shell 执行能力,需要额外控制。
三、最小示例:创建一个只读 Agent
下面这个例子禁止 Agent 写任何文件:
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
],
)
解释一下:
operations=["write"]:这条规则只管写操作;paths=["/**"]:匹配所有路径;mode="deny":命中后拒绝。
所以 Agent 仍然可以读文件,但不能写文件。
如果 Agent 尝试调用:
text
write_file("/workspace/demo.txt", "hello")
这属于:
text
write 操作 + 路径匹配 /** + deny
因此会被拒绝。
四、FilesystemPermission 的三个核心字段
DeepAgents 使用 FilesystemPermission 描述一条权限规则。它有三个关键字段:
python
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
)
1. operations:控制操作类型
operations 是一个列表,只能写:
python
["read"]
["write"]
["read", "write"]
对应关系如下:
| operations | 影响的行为 |
|---|---|
read |
看目录、读文件、glob 查找、grep 搜索 |
write |
写文件、编辑文件 |
常见写法:
python
# 只限制写入
operations=["write"]
# 同时限制读写
operations=["read", "write"]
如果你的目标是"可以看但不能改",就只配置 write 的拒绝规则。
如果你的目标是"连看都不能看",就需要同时限制 read 和 write。
2. paths:控制路径范围
paths 是路径 glob 模式列表,例如:
python
paths=["/workspace/**"]
paths=["/workspace/.env"]
paths=["/workspace/examples/**", "/workspace/.env"]
常见匹配方式:
| 写法 | 含义 |
|---|---|
/workspace/** |
/workspace/ 下所有文件和子目录 |
/workspace/*.py |
/workspace/ 这一层的 Python 文件 |
/workspace/.env |
精确匹配 .env 文件 |
/** |
所有路径 |
/projects/*/secrets/** |
/projects/项目名/secrets/ 下所有内容 |
注意:路径通常写成以 / 开头的虚拟文件系统路径,而不是 Windows 的 C:\xxx 或 Linux 的真实磁盘路径。DeepAgents 的 backend 会负责把这些虚拟路径映射到实际存储。
3. mode:控制命中后的处理方式
mode 有三种:
| mode | 含义 | 适用场景 |
|---|---|---|
allow |
允许操作 | 白名单目录、明确可访问路径 |
deny |
拒绝操作 | 敏感文件、禁止写入目录 |
interrupt |
暂停,等待人工审批 | 高风险写入、需要人工确认的变更 |
最常见的是 allow 和 deny。
interrupt 适合这类场景:
text
不是绝对禁止,但每次修改前都要人看一眼。
例如:
- 修改
/secrets/**; - 修改
/production-config/**; - 修改组织级策略
/policies/**; - 修改需要审计的重要文件。
五、最重要的规则:按顺序匹配,首个命中生效
DeepAgents 的权限规则采用:
text
first-match-wins
也就是:
text
从上到下检查规则,第一条同时匹配 operations 和 paths 的规则决定结果。
后面的规则不会再看。
如果没有任何规则匹配,默认是允许。
这点非常重要。
正确示例:先写特殊规则,再写通用规则
需求:
text
允许访问 /workspace/**,
但是禁止访问 /workspace/.env,
其他路径全部禁止。
正确写法:
python
from deepagents import FilesystemPermission
permissions = [
# 1. 先保护最敏感的具体文件
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
# 2. 再允许 workspace 目录
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
# 3. 最后兜底拒绝其他路径
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
为什么要这样排?
因为 /workspace/.env 也属于 /workspace/**。如果先写允许 /workspace/**,那么 .env 会先命中允许规则,后面的拒绝规则就不会生效。
错误示例:通用规则放前面
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
]
这里 .env 会先匹配 /workspace/**,结果是允许。
记住一个经验:
text
权限规则要从具体到宽泛:
具体敏感文件 -> 普通业务目录 -> 全局兜底规则
六、为什么"无匹配默认允许"很关键
官方文档提到,如果没有规则匹配,操作默认允许。
这意味着下面这个配置不是"只允许读 /workspace/":
python
permissions = [
FilesystemPermission(
operations=["read"],
paths=["/workspace/**"],
mode="allow",
),
]
它的实际效果是:
text
读 /workspace/**:命中 allow,允许
读 /other/**:没有规则匹配,默认允许
写任何路径:没有 write 规则匹配,默认允许
所以它几乎没有达到限制目的。
如果你想做白名单,必须加兜底拒绝:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
这才表示:
text
只允许读写 /workspace/**,其他路径全部拒绝。
七、常见场景一:只允许 Agent 在工作区内读写
这是最常见的权限模型。
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
],
)
效果:
| 操作 | 结果 |
|---|---|
读 /workspace/app.py |
允许 |
写 /workspace/result.md |
允许 |
读 /secrets/key.txt |
拒绝 |
写 /tmp/a.txt |
拒绝 |
这个配置适合:
- 代码生成 Agent;
- 文档整理 Agent;
- 只允许在项目工作目录内操作的研发助手;
- 不希望 Agent 访问其他虚拟路径的场景。
八、常见场景二:保护 .env 和示例目录
需求:
text
Agent 可以操作 /workspace/,
但是不能读写 /workspace/.env,
也不能碰 /workspace/examples/**。
代码:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env", "/workspace/examples/**"],
mode="deny",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
匹配过程示例:
text
read_file("/workspace/.env")
-> 命中第 1 条 deny
-> 拒绝
write_file("/workspace/src/app.py")
-> 第 1 条不匹配
-> 第 2 条 /workspace/** 匹配 allow
-> 允许
read_file("/other/data.txt")
-> 第 1 条不匹配
-> 第 2 条不匹配
-> 第 3 条 /** 匹配 deny
-> 拒绝
九、常见场景三:共享记忆只读
DeepAgents 可以通过 backend 把不同路径路由到不同存储,例如:
/memories/:用户长期记忆;/policies/:组织级策略;- 默认路径:临时状态或工作区。
有些文件 Agent 可以读,但不应该由 Agent 直接修改。
例如组织级策略文件:
text
/policies/security.md
/policies/style-guide.md
可以让 Agent 读取它们作为参考,但禁止 Agent 改写:
python
from deepagents import FilesystemPermission, create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
agent = create_deep_agent(
model=model,
backend=CompositeBackend(
default=StateBackend(),
routes={
"/memories/": StoreBackend(
namespace=lambda rt: (rt.server_info.user.identity,),
),
"/policies/": StoreBackend(
namespace=lambda rt: (rt.context.org_id,),
),
},
),
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/memories/**", "/policies/**"],
mode="deny",
),
],
)
这段配置的含义:
text
读 /memories/**:没有匹配 write 规则,因此默认允许
写 /memories/**:命中 deny,拒绝
读 /policies/**:允许
写 /policies/**:拒绝
适合场景:
- 组织级知识库只能由后台管理系统更新;
- 用户长期记忆只能通过审核流程更新;
- Agent 可以参考规范,但不能擅自修改规范。
十、常见场景四:完全禁止文件访问
如果你希望 Agent 完全不能碰文件系统:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
效果:
| 工具 | 结果 |
|---|---|
ls |
拒绝 |
read_file |
拒绝 |
glob |
拒绝 |
grep |
拒绝 |
write_file |
拒绝 |
edit_file |
拒绝 |
这个配置适合:
- 纯对话 Agent;
- 只允许调用业务 API,不允许读写文件;
- 高安全要求环境;
- 先做最小权限,再逐步开放。
十一、interrupt:敏感写入前暂停等待人工审批
mode="interrupt" 是比 deny 更灵活的一种模式。
它不是直接拒绝,而是:
text
当 Agent 尝试执行匹配规则的文件操作时,暂停执行,交给人工审批。
例如:
python
from deepagents import FilesystemPermission, create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model=model,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/secrets/**"],
mode="interrupt",
),
],
checkpointer=InMemorySaver(),
)
这里的含义是:
text
Agent 写 /secrets/** 时,不直接执行,而是触发 human-in-the-loop 中断。
interrupt 为什么需要 checkpointer
因为中断意味着 Agent 要暂停,然后等待人类操作后继续运行。
这就需要保存当前状态:
text
暂停前 Agent 在做什么?
准备调用哪个工具?
工具参数是什么?
审批后从哪里继续?
所以 interrupt 需要配置 checkpointer,例如:
python
checkpointer=InMemorySaver()
生产环境中通常会换成更持久化的 checkpointer。
interrupt 适合哪些场景
interrupt 不适合所有文件操作都审批,否则体验会很差。
它更适合高风险路径:
text
/secrets/**
/production/**
/deploy/**
/policies/**
/billing/**
例如:
python
permissions = [
FilesystemPermission(
operations=["write"],
paths=["/production/**"],
mode="interrupt",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
这个配置表示:
text
写 /production/**:需要审批
读写 /workspace/**:允许
其他路径:拒绝
注意规则顺序:/production/** 必须放在 /** 拒绝规则之前,否则可能被兜底拒绝直接拦掉。
十二、interrupt 路径最好有明确前缀
官方文档特别提醒,interrupt 的路径模式最好有明确的前缀,例如:
text
/secrets/**
/projects/*/secrets/**
不建议写过于模糊的模式:
text
/**/secrets
原因是 ls、glob、grep 这类批量工具会搜索一片目录。对于过于宽泛的模式,系统为了安全可能会保守地触发更多中断,导致审批过于频繁。
实践建议:
text
interrupt 路径尽量写成"明确目录前缀 + 通配符"。
例如:
python
FilesystemPermission(
operations=["write"],
paths=["/projects/*/secrets/**"],
mode="interrupt",
)
十三、子 Agent 的权限
DeepAgents 支持 subagents。默认情况下:
text
子 Agent 会继承父 Agent 的 permissions。
如果你在子 Agent spec 中显式设置 permissions,则:
text
子 Agent 的权限会完全替换父 Agent 的权限,而不是追加。
这一点很重要。
示例:父 Agent 能读写,审查子 Agent 只能读不能写
python
from deepagents import FilesystemPermission, create_deep_agent
agent = create_deep_agent(
model=model,
backend=backend,
permissions=[
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
],
subagents=[
{
"name": "auditor",
"description": "Read-only code reviewer",
"system_prompt": "Review the code for issues.",
"permissions": [
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
FilesystemPermission(
operations=["read"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read"],
paths=["/**"],
mode="deny",
),
],
}
],
)
这里父 Agent:
text
可以读写 /workspace/**
而 auditor 子 Agent:
text
可以读 /workspace/**
不能写任何路径
不能读 /workspace/ 之外的路径
适合场景:
- 主 Agent 负责实现代码;
- 子 Agent 负责代码审查;
- 子 Agent 可以读代码,但不能改代码;
- 防止审查 Agent 擅自修复、覆盖文件。
子 Agent 权限的常见误解
很多人会以为子 Agent 的 permissions 是在父权限基础上追加。
实际不是。
如果你写:
python
subagents=[
{
"name": "auditor",
"permissions": [
FilesystemPermission(
operations=["write"],
paths=["/**"],
mode="deny",
),
],
}
]
这并不表示:
text
继承父 Agent 的读权限 + 禁止写
而是:
text
子 Agent 只有这一条规则。
由于没有匹配的读规则时默认允许,所以这个子 Agent 可能仍能读取很多路径。
更稳妥的写法是显式补全读权限白名单和兜底拒绝。
十四、CompositeBackend 和 sandbox 的限制
CompositeBackend 可以把不同路径路由到不同 backend。
例如:
python
from deepagents.backends import CompositeBackend
composite = CompositeBackend(
default=sandbox,
routes={
"/memories/": memories_backend,
},
)
这里:
text
/memories/ 走 memories_backend
其他路径走 sandbox
官方文档指出:如果 CompositeBackend 的默认 backend 是 sandbox,那么权限路径必须限制在已知 route 前缀下。
原因是 sandbox 支持任意命令执行。仅靠路径级 permissions 无法阻止 Agent 通过 shell 命令访问文件系统。
可行写法
python
agent = create_deep_agent(
model=model,
backend=composite,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/memories/**"],
mode="deny",
),
],
)
这里 /memories/** 属于明确 route,所以可以做路径权限控制。
可能报错的写法
python
agent = create_deep_agent(
model=model,
backend=composite,
permissions=[
FilesystemPermission(
operations=["write"],
paths=["/workspace/**"],
mode="deny",
),
],
)
如果 /workspace/ 没有配置成 route,而是落到 sandbox default,就可能抛出 NotImplementedError。
下面这种也不适合:
python
FilesystemPermission(
operations=["read"],
paths=["/**"],
mode="deny",
)
因为 /** 覆盖了 route 和 sandbox default。对于 sandbox default,单纯路径规则并不足以表达安全边界。
十五、完整实战模板:安全的代码助手权限配置
假设我们要做一个代码助手:
需求:
text
1. 只允许 Agent 在 /workspace/ 内工作;
2. 禁止读取和修改 .env;
3. 禁止修改 /workspace/README.md,但允许读取;
4. 修改 /workspace/deploy/** 时需要人工审批;
5. 其他路径全部禁止。
可以这样写:
python
from deepagents import FilesystemPermission, create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver
permissions = [
# 1. 密钥文件完全禁止读写
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/.env"],
mode="deny",
),
# 2. 部署目录写入前需要审批
FilesystemPermission(
operations=["write"],
paths=["/workspace/deploy/**"],
mode="interrupt",
),
# 3. README 允许读,但禁止写
FilesystemPermission(
operations=["write"],
paths=["/workspace/README.md"],
mode="deny",
),
# 4. 工作区读写默认允许
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
# 5. 工作区之外全部拒绝
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
agent = create_deep_agent(
model=model,
backend=backend,
permissions=permissions,
checkpointer=InMemorySaver(),
)
逐条解释:
| 路径和操作 | 命中规则 | 结果 |
|---|---|---|
读 /workspace/.env |
第 1 条 | 拒绝 |
写 /workspace/.env |
第 1 条 | 拒绝 |
写 /workspace/deploy/app.yaml |
第 2 条 | 暂停审批 |
读 /workspace/deploy/app.yaml |
第 4 条 | 允许 |
写 /workspace/README.md |
第 3 条 | 拒绝 |
读 /workspace/README.md |
第 4 条 | 允许 |
写 /workspace/src/main.py |
第 4 条 | 允许 |
读 /secrets/key.txt |
第 5 条 | 拒绝 |
这个例子体现了权限设计的典型思路:
text
敏感文件先拒绝;
高风险目录用 interrupt;
普通工作区允许;
最后用 /** 兜底拒绝。
十六、权限设计最佳实践
1. 优先使用白名单模型
不要只写几条 deny,然后让其他路径默认允许。
更推荐:
text
允许明确工作区;
拒绝其他所有路径。
模板:
python
permissions = [
FilesystemPermission(
operations=["read", "write"],
paths=["/workspace/**"],
mode="allow",
),
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
),
]
2. 具体规则放前面,宽泛规则放后面
推荐顺序:
text
1. 特别敏感文件 deny
2. 高风险路径 interrupt
3. 普通目录 allow
4. 全局兜底 deny
不要把 /workspace/**、/** 这种大范围规则放在太前面。
3. 读写权限分开思考
很多路径可以读但不能写,例如:
- README;
- 规范文档;
- 共享知识库;
- 历史记录;
- 策略文件。
这时不要写:
python
operations=["read", "write"]
而应该只限制写:
python
FilesystemPermission(
operations=["write"],
paths=["/policies/**"],
mode="deny",
)
4. 不要忘记默认允许
只要没有匹配规则,DeepAgents 默认允许。
因此,想要安全收口时,一定要加兜底规则:
python
FilesystemPermission(
operations=["read", "write"],
paths=["/**"],
mode="deny",
)
5. 自定义工具要单独做安全控制
permissions 不会自动限制自定义工具。
如果你写了自定义工具:
python
def load_file(path: str) -> str:
with open(path, "r", encoding="utf-8") as f:
return f.read()
你应该自己检查路径:
python
from pathlib import Path
WORKSPACE = Path("/safe/workspace").resolve()
def load_file(path: str) -> str:
target = Path(path).resolve()
if not str(target).startswith(str(WORKSPACE)):
raise PermissionError("Only workspace files are allowed")
return target.read_text(encoding="utf-8")
实际生产中还要处理符号链接、路径规范化、租户隔离、审计日志等问题。
6. sandbox 不等于 permissions
如果 backend 提供 execute 工具,Agent 可能通过 shell 命令访问文件。
例如:
text
cat /etc/passwd
find / -name "*.env"
这类能力不是 FilesystemPermission 通过路径规则就能完全管住的。
所以:
text
permissions 是文件工具权限;
sandbox 是执行环境隔离;
两者不能互相替代。