7.5. 安全架构需要对工具调用和记忆访问施加细粒度控制

安全架构需要对工具调用和记忆访问施加细粒度控制

2025 年 11 月,一家电商公司的 AI 运维 Agent 在执行“清理过期日志”的指令时,自主追加了一条 --purge 参数。结果,不仅 30 天前的归档日志被删除,当天的实时交易流水也一同消失。事后复盘发现,Agent 并非遭遇攻击,只是忠实地组合了它“能访问的所有工具调用”去完成用户的模糊意图。

这不是 AI 失控,而是权限设计缺位。

当私有模型接入完成(如上一章所述),Agent 就正式成为了企业数据的“持钥人”。它可以调用 API、执行 Shell 命令、读写向量数据库中的长期记忆——这一切让 Agent 变得强大,但也让它变成一个危险的执行器。本章要解决的核心问题只有一个:怎么在赋予 Agent 能力的同时,确保它不会越权操作?答案藏在三个层层递进的防线里:工具权限分级与沙箱、记忆访问控制策略、以及覆盖所有变更的审计日志。

现象:Agent 越权不是意外,是缺少权限模型的必然结果

在 Hermes Agent 的安全设计文档中,有一组被反复提及的数据:2026 年初的 GitHub Issues 里,超过 40% 的“高危场景”反馈与工具调用权限过宽有关。典型案例如下:

场景 用户意图 Agent 实际行为 漏洞根因
清理 /tmp 缓存 删除临时文件 递归删除 /tmp 下所有内容,包括其他服务的运行时 socket 工具调用未限制路径范围
查询用户信息 从数据库读取姓名和邮箱 执行了一条无 WHERE 子句的 SELECT *,返回整表 SQL 工具权限未设定为只读
发送日报 调用企业微信 API 推送消息 同时读取了群聊历史记录并存入个人记忆 API 密钥的 scope 过大

这些案例的共同点不是“Agent 发疯了”,而是工具调用权限与记忆访问权限没有细粒度控制。当 Agent 拿到一把万能钥匙时,我们不能期待它自己决定哪些门可以开——这个边界必须由架构预设。

核心维度一:工具权限分级与沙箱——按风险等级切分执行边界

第一道防线在工具调用的出口处。Hermes Agent 的内部设计中,Skill(技能)是一个基本执行单元,每个 Skill 对应一组工具调用。对 Skill 实施权限分级,本质是在回答一个问题:“这个 Agent 能碰什么,能碰多远?”

风险等级定义

根据调研资料中 Hermes 的危险命令列表和审批机制,可以将工具调用按风险分为四个等级:

等级 风险标签 允许的操作 限制 示例
L0 只读 读取文件、查询 API、查询数据库 禁止任何写操作 catSELECTcurl GET
L1 文件写入 创建/修改指定目录下的文件 路径白名单;禁止修改隐藏文件 echo > /data/reports/
L2 网络出站 调用外部 API、发送消息 目标域名/IP 白名单 企业微信 Webhook、Slack API
L3 命令执行 运行 Shell 命令、管理进程 必须通过危险命令审批;推荐使用容器沙箱 systemctl restartdocker exec

设计要点

  • L0~L1 是绝大多数“数据查询 Agent”需要的权限,应当设为默认值。
  • L3 不应作为默认能力开放,必须由管理员显式赋权。
  • 每个 Skill 声明自己所需的最低权限等级,Agent 运行时强制校验。

沙箱执行环境

Hermes 的安全文档明确指出:当使用 Docker/Singularity/Modal 等容器后端运行时,部分危险命令审批会自动跳过——因为容器本身已构成隔离边界。这不是放松安全,而是将信任从“审批人的判断”转移到“环境的约束”。

沙箱配置推荐(以 Docker 为例):

docker run --rm \
  --read-only \
  --tmpfs /tmp:noexec,nosuid,size=256M \
  --network=none \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  hermes-agent:latest

表格形式总结如下:

沙箱策略 作用 适用风险等级
--read-only 禁止写入容器文件系统 L2~L3
--network=none 禁止网络出站 L3
--cap-drop=ALL 移除所有 Linux Capabilities L3
--tmpfs /tmp:noexec 允许临时文件但禁止执行 L1~L3

这种“即使 Agent 失控,攻击面也被锁定在容器内”的设计,是纵深防御的第一道物理隔离。

核心维度二:记忆访问控制策略——区分 user 和 system 记忆的读写边界

工具调用是“向外”的操作,记忆访问则是“向内”的操作。Agent 的长期记忆(通常存储在向量数据库或 Key-Value 存储中)分为两类:

记忆类型 归属方 可见性 典型内容
user 记忆 终端用户 仅该用户可见(按 user_id 隔离) 个人偏好、历史对话摘要、自定义指令
system 记忆 Agent 系统 所有实例可见(跨用户共享) 系统配置、全局知识库、共享 Skill 定义

当前调研资料尚未明确给出 Hermes 记忆系统的权限控制细节,但从架构原则看,最小权限在此处的实践应是:

  1. user 记忆的隔离:Agent 处理用户 A 的请求时,只能读取/写入 user_id=A 的记忆分区。任何跨用户记忆访问都应被拦截。
  2. system 记忆的只读保护:普通 Agent 实例对 system 记忆仅有读取权限,修改操作必须经过管理 API 或人工审批。
  3. 记忆写入的意图确认:当 Agent 计划将对话中获取的信息写入 user 记忆时,应提示用户确认(尤其是涉及 PII 或敏感数据时)。

操作矩阵(推荐设计):

角色 读 user 记忆 写 user 记忆 读 system 记忆 写 system 记忆
普通 Agent 实例 仅自己的 user_id 仅自己的 user_id(需意图确认) 允许 拒绝
管理 Agent 实例 允许(审计记录) 拒绝(不应修改用户数据) 允许 允许(需审批)
调试模式 允许(用户授权后) 允许(用户授权后) 允许 拒绝

这个矩阵的核心逻辑是:user 记忆是用户的隐私资产,system 记忆是团队的知识资产,不同的资产有独立的访问控制面。

核心维度三:审计日志与异常检测——让每一次越权尝试都被记录

即使有了分级和沙箱,安全架构的最后一环仍是“可观测”。如果一条危险命令被拒绝了,但没有任何记录,我们就失去了对攻击行为的感知能力。

需要记录的事件

事件类别 需记录的字段 保留周期建议
工具调用 用户 ID、时间戳、Skill 名称、完整命令、审批结果(通过/拒绝/超时)、执行环境 90 天
记忆变更 用户 ID、时间戳、操作类型(读/写/删)、记忆 key、变更内容摘要(非全文) 180 天
权限变更 操作用户 ID、时间戳、变更详情(赋予/撤销哪个用户什么权限) 永久
异常模式 触发规则 ID、时间戳、上下文快照 30 天(滚动分析)

异常检测规则(示例)

从 Hermes 的危险命令匹配思路出发,可以扩展为一组持续运行的检测规则:

规则 检测逻辑 告警等级
高频拒绝 同一用户 1 分钟内触发 5 次以上工具调用被拒绝
记忆扫描 短时间内大量读取记忆 key 但无会话交互
权限逃逸尝试 被拒绝的 L3 命令后紧跟着尝试 L2 命令绕过审批 严重
非工作时间活跃 凌晨 2~5 点出现 L2 级以上工具调用 待确认(视业务而定)

关键提醒:审计日志本身也是敏感数据——它记录了“谁在什么时候做了什么”。日志的存储应加密,访问权限应与生产环境权限分离。

结论:安全架构的核心不是“信任 Agent”,而是“不信任任何单一执行路径”

这三个维度——工具分级、记忆隔离、审计检测——共同构成了 Agent 安全的三脚架。它们回答的是同一个底层问题:如果 Agent 犯错了(或被诱导犯错了),破坏力能被限制在多大范围内?

不同场景下的推荐配置

使用场景 工具权限等级 沙箱模式 记忆隔离 审批模式
内部数据分析 Agent L0(只读) 无需沙箱 user 隔离 smart 模式
自动化运维 Agent L1~L3 Docker 沙箱 user 隔离 + system 只读 manual 模式(默认需审批)
面向客户的对话 Agent L0~L1 轻量沙箱(tmpfs) user 隔离 + 写入需确认 smart 模式
开发调试环境 L3(全开) 独立开发容器 隔离但允许手动操作 off 模式(需显式开启 YOLO)

作者的结论:最安全的 Agent 不是“一个漏洞都没有”的 Agent,而是 “即使出现意外行为,影响也能被沙箱限制、被审批拦截、被审计追溯” 的 Agent。从架构第一天起,就把“能做什么”和“不能做什么”刻成代码的硬边界,而不是靠提示词里的“请勿删除生产数据”来祈祷 Agent 自律。

在下一章中,我们将从安全转向成本——当 Agent 频繁调用大模型时,Token 的消耗会成为隐藏的系统开销。“Token 预算管理是成本控制的核心战场” 将告诉你,如何在不牺牲能力的前提下,把每一次调用的开销降到可控范围。安全护住了下限,成本护住了可持续性——两者缺一不可。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~