跳转到主要内容

Agent 读取范围:为什么全盘访问是数据暴露的错误原语

文件系统权限无法表达 agent 打算对数据做什么。读取范围应按数据类别和查询意图授予,而不是按文件系统根目录。

一块电路板的微距照片,在浅景深下显示出走线、焊点和处理器裸片。

文件系统不是一种策略语言

全盘访问是对一棵文件树的二元授权。它只回答一个问题:这个进程能否打开这个路径?它无法回答对自主 agent 而言真正重要的问题:这个进程为什么要读这个文件,而这个目的能否为这次读取提供正当性?

设想对同一路径的两次读取。一个解析依赖的 agent 读取配置文件,以发现某个包注册表的位置。一个准备支持摘要的 agent 读取凭据存储,以提取一个 API token。在文件系统层面,这两者是相同的操作。权限模型没有表达意图的词汇,因此无法区分它们。授权要么存在,要么不存在,而一旦存在,它便适用于该 agent 在进程生命周期内执行的每一次读取。

Apple 决定收紧 macOS 对 AI agent 的全盘访问,是对风险状况真实变化的合理回应。Agent 不是人类操作员。它以机器速度运行,可以不停下来做判断就串联工具调用,而且它可能依据与它所读取的数据来自同一渠道的指令行事。然而,缓解措施仍然是同一原语的更粗糙版本:一个提示、一个同意对话框、一个更窄的授权。它收窄了谁可以读取,但仍然无法表达这次读取是为了什么。真正的信任单元是 agent、数据类别和目的这三元组。没有任何文件系统权限模型能表达这个三元组,因为文件系统并不知道 agent 的任务。

以数据类别作为范围划定单元

一个可行的替代方案是:不再把文件系统当作策略边界,而是开始把数据类别当作范围划定单元。在任何 agent 运行之前,将可读数据划分为若干层级:

  • 公开:文档、已发布的参考资料、开放数据集。
  • 运营:服务配置、部署清单、非敏感日志。
  • 个人:用户记录、支持对话记录、任何可识别个人的内容。
  • 机密:凭据、token、私钥、签名材料。

Agent 在其运行清单中声明它所需的层级。一个总结公开文档的检索 agent 声明 public。一个读取支持对话记录的分诊 agent 声明 public 和 personal。一个轮换凭据的 agent 声明 secret,而这种声明应当足够罕见,以触发审查。

执行应归属于工具层,而非操作系统层。Agent 不会收到一个挂载卷和一个路径。它收到的是函数:read_public_doc(id)、read_support_ticket(id)、read_credential_ref(name)。每个函数都会将 agent 声明的层级集合与它即将返回的数据所属的层级进行核对。如果 agent 没有声明 secret,凭据函数会返回拒绝,而不是文件句柄。由于 agent 自身的代码永远看不到文件系统路径,它就无法通过直接打开文件来提权。边界是接口的属性,而不是进程特权级别的属性。

Aerial view of freight trains in a railway yard, showing industrial logistics

这还会产生一条文件系统日志无法重建的审计轨迹。文件系统日志记录的是进程 4821 打开了 /etc/credentials/store。工具层日志记录的是 agent triage-v3,声明目的为 summarise open support tickets,请求了 read_support_ticket(88213) 并收到了一条属于 personal 层级的记录。当发生跨层级读取时,日志会连同声明的目的一起记录。这就是知道某个文件被打开与知道该 agent 试图完成什么之间的区别。

一个具体机制

该模式是一个带层级检查和目的标记的能力包装器。概要如下:

TIERS = {"public": 0, "operational": 1, "personal": 2, "secret": 3}

def guarded_read(agent, resource, tier):
    if TIERS[tier] > TIERS[agent.declared_max_tier]:
        audit.deny(agent.id, resource, tier, agent.purpose)
        raise ScopeError(f"{agent.id} is not scoped for {tier}")
    audit.allow(agent.id, resource, tier, agent.purpose)
    return resource.fetch()

Agent 声明的最高层级在运行开始时即固定。在运行中途将其放宽不是一次配置变更;它是一次带有新清单和新审批的新运行。审计流是仅追加的,并以 agent 身份和声明的目的为键,因此审查者不仅能重建读取了什么,还能重建每次读取是由哪个任务驱动的。

这不是操作系统意义上的沙箱Close-up of a laboratory microscope objective lens used for scientific research and analysis

层级分类是人工的,而且会漂移。一个新的数据源到来;有人给它分配了一个层级;六个月后,该数据源包含了一个它此前不包含的字段,而层级现在错了。分类需要一个负责人和一套审查节奏,而这位负责人是一项真实的持续成本。没有自动方法能从字段内容推断出其正确的层级,而尝试这样做往往要么过于宽松,要么噪声太大而不可信。

工具层执行的前提是 agent 无法绕过工具层。在一个没有直接系统调用访问、也没有经由被包装接口之外的网络出口的沙箱内,这是成立的。一旦 agent 运行在一个可以打开文件、派生子进程或直接访问网络的进程中,这就不成立了。策略层的强度仅取决于其下方的隔离,这意味着该设计要求两者兼备:分层工具接口以及一个真正无法逃逸它们的运行时。

这种取舍是刻意的。更多的前期分类工作、一位负责层级漂移的负责人,以及一个强制执行隔离的运行时——换来的是一个可读、可执行、可审计的暴露面。文件系统授权签发起来很廉价,事后却无法推理。层级声明维护起来很昂贵,但在审查时清晰可读。

一条设计规则

绝不要授予 agent 与你会授予人类操作员相同的访问原语。人类拥有 agent 所不具备的判断力;agent 拥有人类所不具备的吞吐量。一个拥有全盘访问权限的人类会读取任务所需的内容然后停下。一个拥有全盘访问权限的 agent 会读取其策略或其 prompt 引导它去读取的内容,其速率是任何人工审查都无法匹敌的。原语应当反映这种不对称,而不是忽视它。

将读取范围限定为满足任务的最窄数据类别。将任何放宽视为需要重新审批的变更,而不是一个配置开关。如果某个 agent 在流水线的某一步需要 personal 数据,那一步应当是一次带有自己清单的独立运行,而不是对整个流水线的更宽泛授权。

优先选择查询形态的接口,而非数据形态的接口。一个返回某个货币对当前汇率的函数是查询形态的:agent 说明它需要什么,并恰好收到那个。一个挂载的 CSV 文件卷是数据形态的:agent 收到一切,并且必须自行决定读取什么。查询形态的接口在调用点就使目的变得明确,而这正是策略需要所在之处。数据形态的接口把决策推给 agent,在那里它对权限模型不可见,而且往往对审计日志也不可见。

Apple 收紧全盘访问是一个信号,表明业界已经注意到 agent 是一类不同的主体。下一步是停止扩展文件系统原语,转而开始表达真正支配暴露的三元组:哪个 agent,读取哪一类数据,出于什么目的。这个三元组就是策略。文件系统只是字节恰好所在之处。

封面照片:Jakub Pabis / Pexels。

分享XLinkedIn永久链接6 分钟阅读

相关阅读

这能回答的问题

Why is full disk access the wrong primitive for AI agents?

It is a binary grant over a file tree and cannot express why an agent is reading a file. Two reads of the same path — resolving a dependency versus extracting a credential — are indistinguishable to the filesystem, so the permission model cannot separate legitimate use from exfiltration.

What is the (agent, data class, purpose) triple?

It is the unit of trust that actually governs exposure: which agent is reading, which tier of data it is reading, and what task the read serves. Filesystem permissions cannot express this triple because the filesystem has no knowledge of the agent's task.

Where should tier boundaries be enforced?

At the tool layer, not the OS layer. The agent receives wrapped functions that check its declared tier set before returning data, so the agent's own code never sees a filesystem path and cannot escalate by opening a file directly.

What is the main trade-off of tiered read scope?

Tier classification is manual and drifts over time, so it needs an owner and a review cadence. Tool-layer enforcement also assumes the agent runs in a sandbox that cannot bypass the wrapped interfaces via direct syscalls or network access.