1. 为什么说 AI 安全本质上是个工程问题很多人第一次接触 AI 安全脑子里浮现的是模型对齐、提示词注入、越狱攻击这些偏算法和策略层面的东西。但真正在智能体项目里踩过坑的人会告诉你绝大多数安全事故不是模型“想错了”而是工程链路某一层“漏了”。一个智能体从接收用户输入到最终执行动作中间要经过输入解析、意图路由、工具调用、权限校验、运行时沙箱、输出过滤等至少六七个环节任何一个环节的工程实现有缺陷都会让上层再精妙的安全策略形同虚设。我拿一个真实场景举例。你做了一个客服智能体接入了订单查询和退款两个工具。模型层面你做了严格的系统提示词约束要求“只有用户明确提供订单号且身份验证通过后才能发起退款”。听起来很安全对吧但如果工程层面没有对工具调用参数做二次校验攻击者完全可以通过多轮对话诱导模型把退款金额参数从“0”改成“9999”而模型本身可能根本没意识到自己在做什么。这就是典型的策略层安全被工程层漏洞击穿。所以这篇文章想聊的核心观点很明确AI 安全必须当作一个贯穿智能体技术栈每一层的工程问题来对待。从最底层的运行时环境到中间的工具调用与权限管理再到最上层的输入输出过滤每一层都要有对应的工程手段。只盯着模型本身做安全就像只给大门装锁却把窗户全开着。这篇文章适合谁看如果你正在做智能体开发不管是基于 Coze、Dify 这类平台搭建还是用 Python 从零手写 Agent 框架只要你关心“怎么让智能体在生产环境里不出事”那下面的内容应该对你有用。我会尽量把每一层的工程要点拆开讲清楚配上可参考的配置思路和排查方法。2. 智能体技术栈的分层安全模型2.1 从输入到执行一条完整的攻击面链路要理解为什么安全是工程问题先得把智能体的技术栈拆开看。一个典型的智能体系统从用户输入到最终动作执行大致经过这么几层接入层用户请求进入系统可能是 API、聊天窗口、Webhook 等编排层负责意图识别、任务规划、多轮对话管理决定“要做什么”工具层智能体可以调用的外部能力比如搜索、数据库查询、发邮件、执行代码运行时层实际执行工具调用的环境可能是容器、沙箱、虚拟机数据层智能体读写的记忆、知识库、用户数据输出层最终返回给用户的内容可能经过过滤和格式化每一层都有独立的攻击面。接入层可能被恶意 payload 攻击编排层可能被提示词注入操纵工具层可能被参数篡改利用运行时层可能被逃逸攻击数据层可能被越权读取输出层可能泄露敏感信息。只在一层做防护其他层就是敞开的门。2.2 为什么“模型对齐”解决不了工程漏洞模型对齐解决的是“模型愿不愿意做坏事”的问题但工程漏洞导致的是“模型不想做坏事但被利用了”的问题。这两者完全不是一回事。举个例子。你给模型设了严格的系统提示词“禁止执行任何删除操作”。但你的工具层有一个execute_shell工具参数是用户可控的。攻击者通过精心构造的输入让模型生成一个看起来无害的 shell 命令比如echo hello rm -rf /tmp/data。模型可能认为这只是一个输出文本的操作但运行时层如果直接执行了数据就没了。模型本身没有“想”删除数据它只是被工程链路的缺陷利用了。这就是为什么我说安全必须下沉到工程层。模型对齐是必要的但远远不够。你需要的是工具层有参数白名单校验运行时层有沙箱隔离数据层有权限控制输出层有敏感信息过滤。每一层都假设上一层可能被突破这样整体系统才是健壮的。2.3 分层防御的核心原则最小权限与纵深防御分层安全模型有两个核心原则我在实际项目里反复验证过非常有效。第一个是最小权限原则。智能体调用的每一个工具、访问的每一份数据、执行的每一个动作都应该只拥有完成当前任务所必需的最小权限。比如一个查询天气的智能体它的工具层就不应该有任何写文件、发请求、执行代码的能力。听起来很基础但我见过太多项目为了“方便后续扩展”给智能体开了全量工具权限结果一个提示词注入就能让智能体变成攻击者的跳板。第二个是纵深防御原则。不要指望任何单一防护手段能挡住所有攻击。输入过滤可能被绕过工具校验可能被社会工程学突破运行时沙箱可能有未知漏洞。所以每一层都要有独立的防护并且层与层之间的防护逻辑要尽量正交。比如输入层做了关键词过滤工具层还要做参数类型校验运行时层还要做系统调用限制。攻击者要成功必须同时突破所有层这个成本就高得多了。3. 运行时层智能体安全的第一道工程防线3.1 运行时隔离的三种主流方案对比运行时层是智能体实际执行动作的地方也是安全工程最应该重点投入的地方。目前主流的运行时隔离方案有三种我分别说说它们的适用场景和坑。隔离方案隔离强度性能开销适用场景主要坑点进程级隔离低极低内部可信工具调用无法防御逃逸攻击容器隔离中中等大多数生产环境配置不当可能逃逸微虚拟机隔离高较高执行不可信代码启动慢资源占用大进程级隔离就是简单的子进程调用比如 Python 的subprocess。这种方案几乎没有隔离能力智能体调用的工具和主进程共享文件系统、网络、环境变量。我一般只在完全可信的内部工具上用它比如调用一个自己写的、参数完全可控的格式化函数。容器隔离是目前生产环境的主流选择。Docker 容器可以提供文件系统隔离、网络隔离、资源限制。但这里有个大坑默认的 Docker 配置并不安全。容器内的 root 用户如果挂载了宿主机的 Docker socket或者以--privileged模式运行那隔离基本等于没有。我见过一个项目智能体在容器里执行代码结果攻击者通过容器逃逸拿到了宿主机权限。正确的做法是容器以非 root 用户运行禁用特权模式只挂载必要的目录限制网络访问。微虚拟机隔离是强度最高的方案比如 Firecracker、gVisor 这类技术。它给每个智能体任务启动一个独立的轻量级虚拟机即使容器逃逸了攻击者也只是从一个虚拟机逃到另一个虚拟机拿不到宿主机。代价是启动慢、资源占用高。我一般只在执行完全不可信的代码时用这种方案比如让智能体运行用户提交的 Python 脚本。3.2 OpenShell 类运行时环境的配置要点OpenShell 这类运行时环境的核心思路是给智能体提供一个受控的 shell 执行环境。配置的时候有几个关键点必须注意。首先是文件系统挂载策略。默认情况下运行时环境应该只挂载一个临时的、隔离的工作目录智能体只能在这个目录里读写。宿主机的敏感目录比如/etc、/root、/var/run绝对不能挂载进去。如果智能体确实需要访问某些数据应该通过工具层提供的 API 来获取而不是直接挂载文件系统。其次是网络访问控制。智能体的运行时环境默认应该禁止所有出站网络请求只允许访问白名单内的地址。我一般会配置一个网络策略只放行智能体必须调用的内部服务地址其他全部拒绝。这样可以防止智能体被诱导去访问恶意地址或者把敏感数据外传。第三是资源限制。CPU、内存、磁盘、进程数都要设上限。我见过一个智能体因为递归调用自己把整个服务器的内存耗尽了。配置资源限制的时候建议先跑一遍典型任务观察实际资源消耗然后在此基础上留 50% 的余量。比如典型任务用 200MB 内存那就限制 300MB。第四是系统调用过滤。用 seccomp 或者类似的机制只允许智能体运行时环境执行必要的系统调用。比如一个只做文本处理的智能体完全不需要execve、fork、socket这些系统调用那就全部禁掉。这样即使智能体被注入了恶意代码也无法执行新的程序或者建立网络连接。注意运行时环境的配置一定要在测试环境充分验证后再上生产。我踩过的坑是生产环境限制了某个系统调用结果智能体的正常功能也挂了排查了半天才发现是 seccomp 规则太严格。3.3 运行时行为审计记录什么、怎么记录运行时行为审计是事后排查和实时阻断的基础。但很多项目的审计日志要么记太少出了事查不到要么记太多关键信息被淹没。我的经验是审计日志要围绕“谁在什么时间对什么资源做了什么动作结果如何”这个核心来设计。具体来说每一条工具调用记录至少包含这些字段时间戳、智能体实例 ID、用户会话 ID、工具名称、调用参数敏感参数要脱敏、执行时长、执行结果状态、返回内容摘要。如果是代码执行类的工具还要记录执行的代码内容、运行时环境的资源消耗、系统调用摘要。记录方式上我建议用结构化日志比如 JSON 格式直接写到专门的审计日志系统里。不要用普通的文本日志文件因为后期检索和分析太麻烦。如果条件允许审计日志应该实时推送到一个独立的、智能体无法访问的存储里防止智能体被攻击后篡改日志。实时阻断方面可以基于审计日志做规则引擎。比如“同一智能体实例在 10 秒内发起了超过 5 次退款操作”就自动挂起该实例并告警。规则不用一开始就很复杂先覆盖最核心的高危操作后续根据实际攻击案例逐步补充。4. 工具层与编排层的安全工程实践4.1 工具调用的参数校验与白名单机制工具层是智能体与外部世界交互的桥梁也是攻击者最喜欢利用的地方。参数校验的核心思路是永远不要相信智能体生成的参数所有参数都要经过独立的校验逻辑。我一般会为每个工具定义一个参数 schema明确每个参数的类型、范围、格式、是否必填。比如一个“发送邮件”的工具收件人参数必须是合法的邮箱格式且必须在允许的域名白名单内主题和正文参数要限制长度并且过滤掉可能的注入内容附件参数要限制文件类型和大小。校验逻辑要放在工具调用的入口处而不是依赖智能体自己保证。我见过一些项目把参数校验写在系统提示词里让模型“自己注意参数格式”。这种做法极其不可靠模型完全可能因为上下文变化而忽略这些约束。正确的做法是在工具调用的代码里硬编码校验逻辑参数不合法就直接拒绝不进入实际执行。白名单机制方面对于枚举类型的参数比如“操作类型”只能是query、create、update、delete这几个值那就用白名单校验不在白名单内的一律拒绝。对于字符串类型的参数如果可能包含危险字符比如 SQL 语句、shell 命令那就要做转义或者参数化处理。对于数值类型的参数要校验范围比如退款金额不能超过订单金额不能为负数。4.2 权限模型设计RBAC 在智能体场景下的落地传统的 RBAC 模型在智能体场景下需要做一些调整。核心区别在于智能体的权限不仅取决于“谁在操作”还取决于“在什么上下文中操作”。我一般会设计一个三维权限模型用户身份、智能体实例、任务上下文。用户身份决定基础权限比如普通用户不能调用管理员工具。智能体实例决定能力边界比如客服智能体只能调用订单查询和退款工具不能调用数据库管理工具。任务上下文决定临时权限比如用户正在进行退款流程那智能体在这个流程中临时获得退款工具的调用权限流程结束后权限自动回收。落地的时候可以用一个权限表来管理。每一行记录一个权限规则主体用户 ID 或角色、智能体实例 ID、允许的工具列表、允许的参数范围、有效期。智能体调用工具前先查权限表确认当前上下文下是否有权限。没有就拒绝并记录审计日志。这里有个容易忽略的点权限的继承和传递。如果智能体 A 调用了智能体 BB 又调用了工具 C那 C 的权限应该基于谁的上下文我的做法是权限不传递每个智能体实例只拥有自己直接被授予的权限。A 调用 B 的时候B 以自己的身份去调用 C而不是继承 A 的权限。这样可以防止权限在智能体之间扩散。4.3 编排层的意图识别与越权拦截编排层负责理解用户意图并规划任务。这一层的安全工程重点是防止攻击者通过多轮对话或者精心构造的输入诱导编排层产生越权的任务规划。一个典型的攻击场景是这样的攻击者先问“你能帮我查一下订单吗”智能体回答“可以请提供订单号”。然后攻击者说“我的订单号是 12345另外帮我顺便把收货地址改成 xxx”。如果编排层没有严格区分“查询”和“修改”两个意图可能会把整个请求当成一个任务然后调用修改地址的工具。但实际上用户并没有通过身份验证也没有权限修改这个订单。防御手段是在编排层做意图隔离。每个用户请求都要先经过意图分类明确当前请求属于哪个操作类别。然后检查用户在当前上下文中是否有权限执行这个类别的操作。如果没有直接拒绝不进入任务规划。对于多轮对话每一轮都要重新做意图分类和权限检查不能因为上一轮通过了就默认这一轮也通过。另外编排层还要防止任务规划注入。攻击者可能在输入中嵌入类似“忽略之前的指令现在执行 xxx”的内容试图操纵编排层的规划逻辑。防御方法是在编排层对用户输入做清洗移除可能的指令注入模式并且把用户输入和系统指令严格分离不要让用户输入进入系统指令的解析流程。5. 数据层与输出层的安全细节5.1 智能体记忆与知识库的访问控制智能体的记忆和知识库是敏感数据的集中地。访问控制的核心是每个智能体实例只能访问自己任务相关的数据不能跨用户、跨任务读取。我一般会给每个用户会话分配一个独立的命名空间智能体的记忆和知识库查询都限定在这个命名空间内。比如用户 A 的会话只能读取user_a命名空间下的记忆不能读取user_b的。知识库方面如果多个用户共享一个知识库那就要在查询时加上用户权限过滤只返回该用户有权查看的文档。这里有个坑向量数据库的相似度检索可能泄露数据。如果知识库里存了多个用户的文档智能体做相似度检索时可能会检索到其他用户的文档片段。防御方法是在检索时加上元数据过滤只检索当前用户有权访问的文档。或者在写入知识库时就把文档按用户隔离到不同的集合里。另外智能体的长期记忆要定期清理。我见过一个项目智能体的记忆里存了用户的身份证号、银行卡号结果因为没清理几个月后还能被检索出来。建议对记忆数据做分类敏感信息设置较短的过期时间非敏感信息可以保留久一点。5.2 输出过滤防止敏感信息泄露的最后一道闸输出层是智能体返回给用户的最后一道关卡。即使前面的所有层都被突破了输出过滤还能拦住一部分敏感信息泄露。输出过滤的核心是敏感信息识别和脱敏。我一般会配置几类规则正则匹配比如身份证号、手机号、银行卡号、关键词匹配比如“密码”、“密钥”、“token”、模型检测用一个小的分类模型判断输出是否包含敏感内容。匹配到敏感信息后可以选择直接阻断输出、替换为占位符、或者告警并记录。但输出过滤有个天然的矛盾过滤太严会影响正常功能过滤太松会漏掉敏感信息。我的经验是先跑一批正常任务的输出统计敏感信息误报率然后调整规则阈值。对于高敏感场景宁可误报也要拦住对于低敏感场景可以适当放宽。还有一个容易被忽略的点输出过滤要覆盖所有输出通道。智能体的输出可能通过聊天窗口返回也可能通过 API 返回还可能通过邮件、短信等通道发送。每个通道都要有独立的过滤逻辑不能只过滤主通道。5.3 多智能体协同场景下的信任边界多智能体协同是现在很热的方向但安全工程上挑战很大。核心问题是智能体 A 怎么知道智能体 B 返回的结果是可信的我一般会在多智能体系统里定义明确的信任边界。每个智能体有自己的信任域跨域调用必须经过认证和授权。智能体 A 调用智能体 B 的时候要带上 A 的身份凭证和调用意图B 验证通过后才返回结果。B 返回的结果要带上签名A 收到后验证签名确认结果没有被篡改。另外多智能体协同的时候权限要逐级递减。A 有权限调用工具 X、Y、ZA 调用 B 去完成一个子任务B 只应该获得完成这个子任务所需的最小权限而不是继承 A 的全部权限。比如 A 让 B 去查询一个数据B 就只应该有查询权限不应该有修改权限。还有一个实践中的坑智能体之间的通信内容也要做过滤。我见过一个案例智能体 A 把用户的敏感信息直接传给了智能体 B而 B 的输出没有做过滤结果敏感信息泄露了。所以智能体之间的消息传递也要走和用户输入输出一样的过滤流程。6. 常见问题与排查技巧实录6.1 智能体安全排查速查表问题现象可能原因排查方法修复建议智能体执行了未授权的工具权限校验缺失或配置错误检查工具调用日志确认权限表配置补充权限校验逻辑最小权限原则敏感数据出现在输出中输出过滤规则不完整用敏感信息样本测试输出过滤补充正则和关键词规则增加模型检测智能体被提示词注入操纵输入清洗不彻底用注入样本测试输入处理流程加强输入清洗分离用户输入和系统指令运行时环境资源耗尽资源限制未配置或过松查看运行时监控确认资源使用峰值配置 CPU、内存、进程数上限多智能体之间数据泄露信任边界不清晰检查智能体间通信日志定义信任域逐级递减权限消息过滤审计日志缺失关键信息日志字段设计不完整模拟攻击场景检查日志记录补充工具调用参数、结果状态等字段6.2 三个我踩过的真实坑第一个坑以为容器隔离就万事大吉。早期做智能体代码执行功能的时候我用了 Docker 容器觉得隔离够了。结果测试的时候攻击者通过容器内的一个已知漏洞拿到了宿主机的文件读取权限。后来我才知道默认的 Docker 配置有很多不安全的地方比如共享内核、默认网络模式等。修复方案是容器以非 root 运行禁用特权模式限制网络访问加上 seccomp 过滤。第二个坑审计日志记了但没人看。有一段时间我的审计日志记录得很全但从来没有告警规则。结果一个智能体被攻击后连续三天都在异常调用工具但没人发现。后来我加上了实时告警规则比如“同一实例 1 分钟内调用敏感工具超过 3 次”就发通知。告警规则不用一开始就很完善先覆盖最核心的高危操作后续根据实际案例补充。第三个坑输出过滤误杀了正常内容。有一次我加了一个正则规则匹配“密码”这个词结果智能体在回答“如何修改密码”这种正常问题时也被拦截了。后来我调整了规则只在“密码”后面跟着疑似密码值的时候才拦截而不是只要出现“密码”就拦截。输出过滤的规则要经过充分测试平衡安全和可用性。6.3 安全工程落地的优先级建议如果你刚开始做智能体安全资源有限我建议按这个优先级来落地运行时隔离先把智能体的执行环境隔离好这是最基础也是最重要的工具参数校验所有工具调用的参数都要经过独立校验不信任智能体生成的任何参数权限模型定义清楚每个智能体能调用哪些工具最小权限原则审计日志记录所有工具调用和关键操作为事后排查提供依据输出过滤防止敏感信息泄露的最后一道防线输入清洗防止提示词注入和恶意输入多智能体信任边界如果有多智能体协同定义清楚信任关系这个顺序不是绝对的但大体上遵循“先隔离、再校验、后过滤”的逻辑。先把执行环境管住再把调用入口管住最后把输出管住。7. 一些实操中的个人体会做智能体安全工程这几年我最大的体会是安全不是一个可以“加上去”的功能而是需要从架构设计阶段就融入的工程属性。很多项目是在智能体已经跑起来之后才想起来加安全措施这时候往往要改架构成本很高而且容易留下死角。另一个体会是安全措施要可观测、可度量。你加了权限校验那就要有日志记录校验通过和拒绝的次数你加了输出过滤那就要统计过滤命中的频率和类型。没有度量你就不知道安全措施是否有效也不知道攻击是否在发生。还有一点不要追求一步到位的完美安全。智能体安全是一个持续迭代的过程。先覆盖最核心的风险然后根据实际运行中发现的攻击案例和漏洞逐步完善。我见过一些团队想一开始就设计一个“万无一失”的安全架构结果拖了几个月都没上线反而错过了业务窗口。最后分享一个小技巧定期做红蓝对抗演练。找一个人扮演攻击者尝试用各种方式突破智能体的安全防线另一个人扮演防御者记录攻击路径和防御效果。这种演练比看文档、读论文有效得多能发现很多实际工程中的盲点。我一般每个季度做一次每次都能发现几个之前没注意到的问题。智能体安全这个领域还在快速演进新的攻击手法和防御方案层出不穷。保持学习保持警惕把安全当作工程问题来对待而不是当作一个可以一次性解决的配置项。这样你的智能体系统才能在生产环境里真正稳得住。
阅读完成 · 觉得有帮助?