1. 为什么说 AI 安全本质上是工程问题而不是模型问题很多人第一次接触 AI 安全脑子里浮现的是对齐研究、红队测试、内容过滤这些偏研究向的东西。但真正把智能体推到生产环境的人会告诉你绝大多数安全事故根本不是模型变坏了而是工程链条上某个环节没兜住。模型输出了一段不该输出的内容是因为工具调用的返回值没有做校验智能体执行了一个危险操作是因为权限边界在编排层被绕过了用户数据泄露了是因为记忆模块的存储没有做隔离。这些问题没有一个是靠换个更安全的模型能解决的。我做过几个智能体落地的项目踩过的坑几乎全部集中在工程层面。有一次一个客服智能体在测试环境表现完美上线第二天就开始胡言乱语排查了半天发现是工具调用的超时重试逻辑写错了导致同一个查询被重复执行了三次上下文里塞了三份矛盾的数据。模型本身没有任何问题是工程代码的锅。这件事让我彻底转变了思路AI 安全不是一个可以加上去的模块而是需要在智能体技术栈的每一层都嵌入的工程约束。所谓智能体技术栈从下往上大致可以分成这么几层模型推理层、编排与规划层、工具与执行层、记忆与状态层、以及最外层的可观测与审计层。每一层都有自己特有的安全风险也都有对应的工程解法。下面我按层拆开讲每一层都会说清楚风险在哪、怎么防、以及我在实际项目里是怎么做的。一个基本判断如果你的智能体系统出了安全问题先别急着怪模型从工程链路上逐层排查八成能找到根因。2. 模型推理层输入输出的边界控制与降级策略2.1 输入侧的第一道闸门结构化约束而非关键词黑名单模型推理层是智能体的大脑但这一层的安全防护重点不是教模型做好人而是控制它能接触到什么、能输出什么。输入侧最常见的做法是关键词黑名单但这个方法在实际工程里几乎没用——稍微变个说法就绕过去了而且误杀率极高。我现在的做法是结构化约束所有进入模型的用户输入先经过一层预处理管道把自由文本转成带 schema 的结构化请求。具体来说用户输入会先过一个意图分类器可以是一个小模型也可以是规则引擎判断这次请求属于哪类任务然后按照预设的模板填充参数。比如用户说帮我查一下上个月的订单预处理管道会把它转成{intent: query_order, params: {time_range: last_month}}这样的结构。模型拿到的是结构化数据而不是原始的自由文本这样就把注入攻击的面大大缩小了。当然不是所有场景都能完全结构化对于必须传自由文本的场景我会在 prompt 里明确用分隔符把用户输入和系统指令隔开并且在输出解析时严格校验格式。2.2 输出侧的校验与降级别让模型直接决定最终动作输出侧的核心原则是模型的输出永远只是建议不是命令。所有模型生成的内容在真正执行之前必须经过一层校验器。校验器做的事情包括格式校验是不是合法的 JSON、语义校验参数值是否在允许范围内、以及业务规则校验这个操作当前用户有没有权限。我见过太多项目直接把模型的输出丢给工具执行这是极其危险的。正确的做法是加一个动作确认环节。比如模型说删除订单 12345校验器会先检查当前用户有没有删除权限订单 12345 是否属于当前用户删除操作是否在允许的时间窗口内三个都通过才真正执行。任何一个不通过就走降级路径——要么返回一个安全的默认响应要么把请求转人工审核。降级策略本身也需要工程设计。我一般会准备三档降级第一档是重试换个 prompt 再问一次模型第二档是回退到规则引擎用确定性逻辑处理第三档是转人工。这三档的触发条件、超时时间、以及状态回滚逻辑都需要在代码里写清楚不能靠模型自己判断。2.3 推理层的资源隔离别让一个请求拖垮整个系统还有一个容易被忽略的点是资源隔离。模型推理是计算密集型操作如果一个恶意请求构造了超长输入或者触发了无限循环的规划可能会把整个推理服务拖垮。我在工程上的做法是给每个请求设置硬性的 token 上限和时间上限超了直接掐断返回一个标准的超时响应。同时不同优先级的请求走不同的队列避免低优先级的批量任务把高优先级的实时请求堵死。这些措施听起来很基础但真正在项目里全部落实的团队并不多。我见过一个智能体系统因为没做 token 上限被一个用户用超长输入打满了 GPU 显存整个服务挂了半小时。这种事故完全是工程问题跟模型安全没有半点关系。3. 编排与规划层让智能体的决策路径可约束、可中断3.1 规划层的核心风险目标漂移与无限循环编排与规划层是智能体的指挥官它决定先做什么、后做什么、什么时候停下来。这一层最典型的安全问题是目标漂移和无限循环。目标漂移是指智能体在执行过程中逐渐偏离了原始任务比如本来是要查订单结果绕到去修改用户资料了。无限循环是指智能体在两个动作之间反复横跳永远达不到终止条件。这两个问题的根因都是规划逻辑缺乏约束。我的解法是在编排层引入一个任务契约的概念。任务开始时系统会生成一份明确的任务契约里面写清楚目标是什么、允许调用哪些工具、最大执行步数是多少、什么条件下必须终止。智能体的每一步规划都必须对照这份契约如果某一步的动作不在允许的工具列表里或者执行步数超过了上限编排器会强制中断并返回错误。3.2 步数预算与超时中断给智能体装上刹车步数预算是防止无限循环最有效的手段。我在项目里一般会把最大步数设在 10 到 15 步之间具体数值根据任务复杂度调整。超过预算还没完成就判定为失败走降级路径。这个预算不是拍脑袋定的而是通过分析历史任务的执行步数分布来确定的——取 P95 的值作为上限既能覆盖绝大多数正常任务又能及时掐断异常任务。超时中断是另一道保险。每个步骤都有独立的超时时间整个任务也有总超时时间。任何一层超时编排器都会立即中断执行并且回滚已经产生的副作用。这里有个工程细节回滚逻辑必须在设计每个工具的时候就考虑好不能等出了问题再补。比如一个创建订单的工具必须配套一个取消订单的回滚工具否则中断之后系统状态就不一致了。3.3 人在回路关键决策点必须有人确认不是所有决策都适合让智能体自动做。我在编排层会标记出关键决策点这些点上的动作必须经过人工确认才能执行。哪些算关键决策点我的判断标准是不可逆的操作删除、支付、发送、涉及敏感数据的操作读取用户隐私信息、以及超出预设金额或范围的操作。人在回路的实现方式可以很轻量。最简单的是在编排器里加一个确认队列智能体执行到关键决策点时把待确认的动作写入队列然后暂停执行等人工在管理后台点确认后再继续。这个暂停状态需要持久化因为人工确认可能需要几分钟甚至几小时不能让智能体一直占着资源等。实操心得人在回路的确认界面一定要把智能体为什么要做这个动作展示清楚包括它的推理过程和依据的数据。否则人工确认就变成了盲目点按钮失去了意义。4. 工具与执行层权限最小化与沙箱隔离的落地细节4.1 工具权限的最小化设计每个工具只做一件事工具与执行层是智能体真正动手的地方也是安全事故的高发区。这一层的核心原则是权限最小化。具体怎么做我的经验是把工具拆得足够细每个工具只做一件明确的事并且只拥有完成这件事所需的最小权限。举个例子不要做一个管理订单的大工具而是拆成查询订单、修改订单地址、取消订单三个独立工具。查询工具只有读权限修改工具只能改地址字段取消工具只能把状态改成已取消。这样即使智能体被诱导调用了错误的工具造成的损害也是有限的。拆得细还有一个好处是审计方便每个工具的调用记录都很清晰出了问题容易定位。4.2 沙箱执行代码执行类工具必须隔离如果智能体需要执行代码比如数据分析场景沙箱隔离是必须的。我一般用容器化的方式每个代码执行请求起一个独立的容器容器里只挂载必要的数据卷网络访问默认关闭CPU 和内存都有硬性上限执行完立即销毁。这样即使代码里有恶意逻辑也影响不到宿主机和其他请求。沙箱的配置有几个容易踩的坑。第一是超时设置代码执行很容易写出死循环超时时间要设得足够短我一般设 30 秒。第二是输出大小限制有些代码会打印海量日志把磁盘写满需要限制标准输出的最大字节数。第三是依赖管理沙箱镜像里的依赖要预先装好并且锁定版本不能让代码自己联网安装包。4.3 工具调用的参数校验别信任模型给的任何参数模型生成的工具调用参数在真正传给工具之前必须经过严格校验。校验的内容包括参数类型对不对、必填项有没有缺、数值范围是否合理、字符串长度是否超限、以及是否符合业务规则。我见过一个案例模型生成了一个 SQL 查询工具的参数里面带了DROP TABLE语句因为工具本身没有做参数校验直接执行了数据全没了。参数校验的工程实现建议用 schema 校验库比如 Python 的 Pydantic 或者 JSON Schema。每个工具定义一份参数 schema调用前先过一遍校验不通过就拒绝执行并返回错误信息给编排器。错误信息也要注意不要直接把内部错误堆栈返回给模型那样可能泄露系统信息要返回一个脱敏后的通用错误。5. 记忆与状态层数据隔离、过期策略与污染防护5.1 记忆隔离不同用户、不同会话的数据绝不能串记忆与状态层是智能体保持上下文连贯性的基础但也是数据泄露的重灾区。最基本的要求是隔离不同用户的记忆必须物理隔离或逻辑隔离不同会话之间的短期记忆不能互相污染。我在工程上的做法是给每个用户分配独立的命名空间所有记忆的读写都带上用户 ID 和会话 ID 作为前缀底层存储层面用行级权限控制确保一个用户的数据不会被另一个用户的请求读到。长期记忆和短期记忆要分开处理。短期记忆当前会话的上下文存在内存或高速缓存里会话结束就清理。长期记忆跨会话的用户偏好、历史记录存在持久化存储里但必须有明确的过期策略和用户可控的删除接口。我一般会给长期记忆设一个默认的保留期限比如 90 天到期自动清理同时提供 API 让用户可以主动删除自己的记忆数据。5.2 记忆污染防护别让脏数据影响后续决策记忆污染是智能体特有的安全问题。如果智能体在某个会话里被诱导写入了错误的信息到长期记忆后续所有会话都可能受这个错误信息影响。防护手段有两个一是写入校验所有写入长期记忆的数据都要经过校验确认是合法、合理、不矛盾的信息二是来源标记每条记忆都记录它的来源会话和时间戳当发现某条记忆导致异常行为时可以追溯到源头并批量清理。我在项目里还加了一个记忆置信度的机制。每条记忆除了内容本身还带一个置信度分数这个分数根据信息的来源、一致性、以及后续验证结果动态调整。智能体在决策时低置信度的记忆只作为参考不作为主要依据。这个机制实现起来不复杂但对防止记忆污染扩散非常有效。5.3 状态回滚出问题时能回到干净状态状态层的另一个工程要点是回滚能力。智能体执行过程中可能修改了多个状态数据库记录、缓存、文件等如果中途失败需要能把这些状态回滚到执行前的样子。我的做法是在任务开始时创建一个状态快照记录所有可能被修改的资源的当前值任务失败或中断时根据快照恢复。快照的粒度需要权衡。太粗了回滚不精确太细了开销太大。我一般只对关键资源做快照比如订单状态、账户余额、权限配置这些。对于日志类、统计类的数据不做快照因为它们的错误影响可以通过后续修正来弥补。这个取舍需要在项目初期就想清楚不能等出了问题再补。6. 可观测与审计层让每一次智能体行为都可追溯6.1 全链路追踪从用户输入到最终动作的完整记录可观测与审计层是智能体安全的最后一道防线也是事后排查的唯一依据。核心要求是全链路追踪从用户输入开始经过意图识别、规划、工具调用、记忆读写到最终输出每一个环节都要有日志记录。日志里要包含时间戳、请求 ID、用户 ID、会话 ID、以及每个环节的输入输出摘要。我一般会用 OpenTelemetry 这类标准化的追踪框架把智能体的每个步骤做成一个 span串成完整的 trace。这样出问题时可以通过请求 ID 快速拉出整个执行链路看到底是哪一步出了问题。日志的存储要注意脱敏用户隐私数据不能明文落盘敏感字段要加密或哈希处理。6.2 行为审计识别异常模式而非逐条审查审计不是把每条日志都看一遍那不现实。审计的重点是识别异常模式。我会在审计层定义一组异常规则比如同一用户在短时间内大量调用删除类工具、某个工具的错误率突然飙升、智能体的平均执行步数异常增长、出现了从未见过的工具调用组合。这些规则触发时系统会自动告警并冻结相关会话等待人工介入。审计规则需要持续迭代。我一般会每周回顾一次告警记录看看哪些是误报、哪些是漏报然后调整规则。这个过程很像安全运营需要有人持续盯着不能设完规则就不管了。6.3 红队测试与对抗演练主动找问题而不是等出问题最后说一个容易被忽略的工程实践红队测试。不要等生产环境出了问题才去修要主动构造对抗性输入来测试智能体的安全性。我一般会在上线前做一轮系统的红队测试覆盖提示注入、越权调用、数据泄露、资源耗尽这几大类场景。测试用例要持续更新因为攻击手法在进化。红队测试的结果要形成闭环发现的问题要修复修复后要回归测试回归通过的用例要加入常规测试集。这个循环跑起来之后智能体的安全水位会持续提升。我自己的经验是第一轮红队测试通常能发现十几个问题第二轮能发现五六个到第三轮基本就稳定了。7. 把安全嵌进每一层的工程习惯回到最开始的那个判断AI 安全是工程问题。这意味着它不能靠某个单点方案解决而是要在智能体技术栈的每一层都建立对应的工程约束。模型推理层管好输入输出的边界编排层管好决策路径的约束工具层管好权限和隔离记忆层管好数据隔离和污染防护审计层管好可追溯和主动发现。这五层缺任何一层安全链条就是断的。我在实际项目里最大的体会是这些措施单独看都不复杂难的是坚持在每一层都落实并且在迭代过程中不退化。新功能上线时很容易为了赶进度跳过某些校验或者把权限放宽一点图方便这些妥协积累起来就是安全隐患。所以我现在会把安全校验做成框架级的强制约束而不是靠开发人员自觉——比如工具调用的参数校验直接集成到工具注册的基类里不写校验就注册不了工具。用工程手段保证工程安全这才是可持续的做法。另外分享一个实用的小技巧在智能体的系统提示里明确写上当你遇到不确定的情况时优先选择拒绝执行并说明原因而不是猜测。这句话看起来简单但能显著降低智能体在边界情况下的冒险行为。配合前面的工程约束效果会更好。