Agent 工具权限控制:让智能体“能做事”,也“不乱做事”
最近在给 Agent 接工具时,我一开始觉得很简单:
搜索工具
数据库工具
文件工具
Shell 工具
代码执行工具
模型能调用,任务就跑通了。
但很快我就发现,能调用工具,不等于可以无限制地调用工具。
如果直接把系统命令、数据库写入、文件删除都交给 Agent,问题会非常现实:
- 用户一句话触发了危险命令;
- 模型传错参数,改错了数据;
- 工具之间权限边界不清;
- 出问题以后找不到是谁执行的;
- Agent 为了“完成任务”,可能越过原本不该越过的边界。
所以,Tool Calling 后面一定还要跟一层:
权限校验、参数校验、环境隔离和操作审计。
一、为什么 Agent 一定要做权限控制?
传统后端接口通常由程序员提前决定调用路径,用户只能传参数。
Agent 不一样,它会根据自然语言动态决定:
是否调用工具
调用哪个工具
传什么参数
调用几次
什么时候继续下一步
灵活性越高,风险也越高。
比如用户说:
“帮我清理一下项目里的临时文件。”
模型可能生成:
rm -rf *
但真正安全的实现应该限制:
只能清理指定目录
只能删除临时文件
禁止删除配置文件
禁止跨工作目录访问
因此,权限控制的目标不是把 Agent 限制到什么都不能做,而是:
只允许它在明确、可控的范围内行动。
二、常见的四种权限控制方式
1. 工具白名单
只允许 Agent 调用明确开放的工具:
ALLOWED_TOOLS = {
"search_web",
"query_database",
"read_file",
"run_tests"
}
模型即使生成了不存在的工具,也不能执行。
2. 参数级限制
工具可以调用,但参数必须满足规则:
文件路径必须位于 WORKDIR
SQL 只允许 SELECT
金额必须大于 0 且小于上限
邮箱地址必须属于公司域名
3. 环境隔离
危险操作不要直接运行在主机环境。
更稳妥的方式是:
Agent
↓
沙箱容器
↓
临时目录
↓
受限权限执行
例如代码执行、Shell 调试、第三方脚本运行,都应该优先放在隔离环境里。
4. 人工确认
高风险动作不能完全自动化:
发邮件
删除文件
修改数据库
提交代码
发起支付
可以设计成:
Agent 提议动作
↓
展示目标与参数
↓
用户确认
↓
真正执行
三、以 Bash 工具为例:先做命令检查
一个最基础的思路是:
DENY_LIST = [
"rm -rf",
"shutdown",
"reboot",
"mkfs",
"dd"
]
SAFE_COMMANDS = {
"ls", "cat", "grep", "pwd",
"cd", "echo", "git", "pytest"
}
接着检查:
def check_bash_command(cmd: str):
# 1. 禁止危险命令
for pattern in DENY_LIST:
if pattern in cmd:
return False, f"检测到危险命令:{pattern}"
# 2. 检查命令主体
command_name = cmd.strip().split()[0]
if command_name not in SAFE_COMMANDS:
return False, f"命令不在白名单中:{command_name}"
return True, "允许执行"
这个版本不复杂,但已经比“模型说什么就执行什么”安全很多。
不过要注意:
只做字符串匹配并不够。
像管道、重定向、命令拼接、环境变量展开,都可能绕过简单规则。
所以生产环境还需要:
命令解析器
路径归一化
系统调用限制
容器隔离
资源配额
超时控制
四、把权限检查接进 Agent Loop
Agent 工具执行流程可以变成:
用户请求
↓
Agent 生成工具调用
↓
工具白名单检查
↓
参数校验
↓
权限判断
↓
执行工具
↓
记录审计日志
↓
返回结果给 Agent
示例:
class ToolExecutor:
def __init__(self, tools, permission_checker):
self.tools = tools
self.permission_checker = permission_checker
def execute(self, tool_name, args, user_id):
if tool_name not in self.tools:
return {
"success": False,
"error": "工具不在白名单中"
}
allowed, reason = self.permission_checker.check(
tool_name=tool_name,
args=args,
user_id=user_id
)
if not allowed:
return {
"success": False,
"error": reason
}
try:
result = self.tools[tool_name](**args)
return {
"success": True,
"data": result
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
这样,模型负责提出动作,但是否执行由后端决定。
五、权限设计不要只看“工具名”
更成熟的方案,通常会同时判断:
谁在调用
调用什么工具
传入什么参数
访问什么资源
当前处于什么环境
例如:
def can_write_file(user, path):
return (
user.role == "developer"
and path.startswith("/workspace/")
and not path.endswith(".env")
)
这其实已经和普通后端的 RBAC、ABAC 思路很接近了。
Agent 权限系统可以理解成:
用户身份
+
工具能力
+
资源范围
+
风险等级
六、如何验证权限控制是否有效?
建议专门准备一套“攻击性测试用例”:
正常场景
读取日志
运行测试
查询只读数据
异常场景
删除工作区外文件
执行危险命令
修改无权限表
读取其他用户记忆
调用不存在的工具
重点观察:
- 是否被正确拦截;
- 错误信息是否清晰;
- 是否留下审计日志;
- Agent 能否根据失败原因重新规划;
- 是否出现绕过规则的情况。
可以记录几个指标:
危险操作拦截率
误报率
权限校验耗时
工具执行成功率
审计日志完整率
七、常见坑
1. 只有黑名单,没有白名单
黑名单永远很难覆盖所有危险组合,优先采用最小权限和白名单。
2. 只信任 Prompt
系统提示词可以告诉模型“不要删除文件”,但真正的安全边界不能只靠模型自觉。
3. 工具权限和用户权限混在一起
用户能做什么,不代表 Agent 自动能做什么。
4. 失败后没有反馈
如果权限拦截只返回“失败”,Agent 很难调整计划。最好返回:
{
"success": false,
"error_type": "permission_denied",
"message": "只能访问 /workspace/project 目录"
}
5. 没有审计
没有 request_id、用户、工具、参数、结果和时间,出问题时很难追责和复盘。
最后
我现在越来越觉得,Agent 安全不是把 Agent 关起来,而是给它一套清晰的边界:
哪些工具能用
哪些参数能传
哪些资源能访问
哪些操作要确认
哪些行为必须记录
如果把 Agent 比作一个新员工:
Tool = 他手里的工具
Permission = 他的工作权限
Sandbox = 他的办公区域
Approval = 关键操作审批
Audit Log = 工作记录
真正成熟的 Agent,不是“什么都能做”,而是:
知道自己能做什么,也知道什么事情必须停下来确认。
标签
#Agent #ToolCalling #权限控制 #AI安全 #后端开发 #智能体 #工程实践
网硕互联帮助中心



评论前必须登录!
注册