生产环境中的 LLM 护栏:哪些方法真正奏效
大多数团队在发布他们的第一个 LLM 功能后,会在生产环境中因糟糕的输出而受挫,然后紧急加上护栏进行损害控制。结果是一个脆弱的系统,它会阻止合法的请求,减慢响应速度,并且在关键的边缘情况下仍然失效。护栏值得做好——但天真的方法会以你意想不到的方式伤害你。
以下是实际的权衡取舍,以及如何构建一个不会悄悄破坏你产品的护栏层。
护栏不是测试
第一个错误是将护栏视为测试套件。部署前测试在你发布之前评估模型在固定数据集上的行为。护栏在运行时针对实时、不可预测的流量强制执行策略。这种区别很重要,因为用户总会找到你未测试过的输入,而抵御实时对抗性输入的唯一保护措施是每次请求都运行的东西。
护栏会拦截你模型的输入或它生成的输出——或两者都拦截。它可以阻止、修改、标记或记录。它在你的请求路径中运行,这意味着它会增加延迟,从而意味着你需要对要强制执行的内容和方式采取策略。
目标不是运行所有可能的检查。而是在正确的点,以尽可能低的成本运行正确的检查。
真正重要的三个层级
生产环境中的护栏架构有三个层级,它们服务于不同的目的:
第 1 层:输入验证
在用户的消息到达你的 LLM 之前,对其进行验证。这是你捕获提示注入尝试、越狱模式、不应跨越模型边界的显式 PII 以及你的产品不支持的离题请求的地方。基于规则的过滤器和轻量级分类器在这里效果很好。它们快速、廉价且确定。
你在此层阻止的内容可以节省 token 成本,并防止一类攻击甚至到达你的模型。不要因为感觉多疑就跳过它——注入尝试和超出范围的查询在生产环境中是持续存在的。
第 2 层:模型级别约束
你的系统提示就是一个护栏。一个精心设计的系统提示,包含明确的行为指令——范围限制、角色约束、语气指导——可以减少你的输出层需要干预的频率。对于面向客户的产品,使用经过强安全训练的模型。设置保守的温度和明确的 token 限制。这些不仅仅是质量改进;它们减少了你的输出护栏需要覆盖的表面积。
除了你为模型调用支付的费用之外,此层在运行时无需额外成本。在添加昂贵的下游检查之前,请先将其做好。
第 3 层:输出过滤
在模型生成响应之后,但在它到达用户之前,运行你的内容检查。这是你检测 PII 泄露、毒性、幻觉事实、品牌安全违规以及尽管有系统提示模型仍然产生的策略失败的地方。
输出过滤是最昂贵的层,因为它发生在 token 生成之后。尤其是基于 LLM 的输出检查——你调用第二个模型来评估第一个模型的响应——可能会使你的延迟增加 5-10 倍。谨慎使用它们,并且仅用于最高风险的内容类别。
RAG 管道的复杂性
标准的输入/输出护栏假设威胁来自用户。在 RAG 管道中,情况不再如此。
当你的代理检索外部文档并将其注入上下文时,这些文档就成为提示的一部分。检索到的文档可能包含覆盖你系统提示的指令——这是一种称为间接提示注入的技术。用户的查询是完全良性的;攻击是通过你的检索层进行的。
这意味着 RAG 系统需要第三个验证点:在检索到的内容进入模型上下文之前对其进行清理。这不一定很昂贵——一个快速分类器,标记带有指令类模式(祈使句、角色转换短语、明确指令)的文档通常就足够了。你不能做的是,仅仅因为用户的输入是干净的,就假设整个提示也是干净的。
为什么误报会累积
对于以前没有构建过此系统的团队来说,这里有一个令人惊讶的效果:误报率会在护栏层之间累积。
假设每个独立的护栏检查都有 2% 的误报率——它会在 2% 的时间里阻止合法的请求。连续运行五个独立的检查,其中至少一个在合法请求上触发的概率会上升到接近 10%。用户会将此体验为随机的、无法解释的拒绝。它会迅速侵蚀信任,并且由于没有单个检查看起来有问题而难以调试。
解决方案不是让每个检查更具侵略性——更高的敏感度通常会提高误报率。解决方案是审慎选择你分层的检查,整合可以共享上下文的检查,并在生产环境中监控每个检查的误报率,以便你可以使用真实数据调整阈值。一个按检查类型细分的干预率仪表板比单一的“已阻止”指标更有用。
串行与并行执行
另一个延迟陷阱是,当护栏检查相互独立时,却以串行方式运行它们。
一个典型的输出验证步骤可能包括:毒性分类器、PII(个人身份信息)检测器和主题相关性检查。依次运行它们,你将承担它们的延迟总和——例如,60毫秒 + 50毫秒 + 70毫秒 = 180毫秒。并行运行它们,你的总延迟将是其中最慢的检查——70毫秒。
这在原则上很明显,但在实现中很容易被忽视。大多数团队按顺序连接检查,因为这是编写代码的自然方式。并行化它们需要异步执行和结果聚合,这会增加几行代码开销——但这是你能做的最高杠杆优化之一。
作为粗略的启发式:一个聊天机器人可以容忍大约100毫秒的护栏开销,用户才开始察觉。仔细规划这部分预算。一个同步的LLM(大型语言模型)判断至少增加500毫秒。仅在风险真正需要时才使用它。
同步与流式护栏
如果你正在向用户流式传输输出(为了感知延迟,你应该这样做),那么护栏会变得更复杂。
三种模式被普遍使用:
同步:生成完整响应,运行所有检查,然后交付或阻止。实现最简单,延迟最高,保护最好。适用于可接受阻止的高风险流程。
分块异步:在每个数据块流式传输时,对其运行快速的、基于规则的检查。尽早捕获明显的违规;在生成完整响应后,对其运行语义检查。延迟更低,在语义层面的保障略弱。
事后过滤:流式传输响应,并行运行检查,如果在传输过程中检测到违规,则中断或免责。难以清晰实现——你已经发送了需要撤回的内容。除非你有特定的流式用户体验要求迫使你这样做,否则应避免此方法。
对于大多数应用来说,异步分块模式是正确的默认选择:在每个token块上使用快速的基于规则的过滤器,在流式传输完成后对完整响应进行基于LLM的验证。
实际需要监控什么
四项指标可以告诉你护栏是否有效:
- 干预率:有多少比例的请求被阻止或修改?突然的飙升意味着发生了变化——要么是恶意流量,要么是模型更新导致输出分布发生变化。
- 误报率:合法请求是否被阻止?通过标记测试集或人工审查被阻止的样本来衡量。
- 延迟开销:护栏会增加时间。将护栏的P50和P99延迟与 模型延迟分开跟踪,以便你能正确归因延迟原因。
- 绕过尝试:用户在被阻止后多久会重试?高重试率并伴随重构的提示,表明存在恶意行为——并且可能表明护栏是基于表面模式而非意图触发的。
这四项指标足以让你调整阈值,识别哪些检查正在发挥作用,并在问题积累前捕获退化。
优先级的决策框架
并非所有事物都需要护栏。以下是如何决定哪些值得进行检测:
从对用户最明显或对业务损害最大的故障模式开始。PII(个人身份信息)泄露通常是首要的——用户看到其他用户数据的一次事件就可能造成灾难性后果。对于面向客户的产品,有害内容是第二位的。提示注入对于任何采取行动的代理都至关重要。
对于每种风险,问自己:哪种最便宜的检查能提供可接受的覆盖范围?基于正则表达式的PII扫描器,用于常见模式(社保号、信用卡格式、电子邮件),成本仅为微秒级,可捕获简单情况。一个语义PII分类器成本为50-100毫秒,可捕获复杂情况。你可能两者都需要,但要分层使用——先运行便宜的那个。
逐步构建护栏。在强制执行模式之前,先以日志模式部署,以便你了解基线干预率。在阻止任何内容之前,根据实际流量调整阈值。先小范围推行强制执行,然后随着信心增长逐步扩展。
真正的风险
我最常看到的故障模式并非护栏过于宽松。而是团队过早地添加激进的护栏,导致15%的误报率,训练用户绕过它们,最终形成一个系统,既阻止了良性请求,又让恶意用户早已找到了绕过方法。
护栏是正确性保证,而非安全性保证。一个有足够尝试次数的坚定对手总会找到绕过方法。护栏实际的作用是提高攻击成本,捕获不复杂的滥用行为,并让你了解正在尝试什么。这很有价值——但这与坚固的安全边界不同。
设计你的系统时要记住这一点:护栏加上限速、加上异常检测、加上模型级别约束,而不是仅仅依靠护栏。每一层都逐步降低风险。没有单一层可以完全消除风险。
- https://docs.nvidia.com/nemo/guardrails/
- https://genai.owasp.org/llmrisk/llm01-prompt-injection/
- https://huggingface.co/meta-llama/Llama-Guard-3-8B
- https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html
- https://www.datadoghq.com/blog/llm-guardrails-best-practices/
