DeepAgents Permissions 权限机制详解

一、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 lsread_fileglobgrep 读取目录、读取文件、查找文件、搜索内容
write write_fileedit_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 的拒绝规则。

如果你的目标是"连看都不能看",就需要同时限制 readwrite

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 暂停,等待人工审批 高风险写入、需要人工确认的变更

最常见的是 allowdeny

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

原因是 lsglobgrep 这类批量工具会搜索一片目录。对于过于宽泛的模式,系统为了安全可能会保守地触发更多中断,导致审批过于频繁。

实践建议:

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 lsread_fileglobgrep 读取目录、读取文件、查找文件、搜索内容
write write_fileedit_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 的拒绝规则。

如果你的目标是"连看都不能看",就需要同时限制 readwrite

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 暂停,等待人工审批 高风险写入、需要人工确认的变更

最常见的是 allowdeny

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

原因是 lsglobgrep 这类批量工具会搜索一片目录。对于过于宽泛的模式,系统为了安全可能会保守地触发更多中断,导致审批过于频繁。

实践建议:

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 是执行环境隔离;
两者不能互相替代。