核心摘要
LLM Guardrails 不是一个过滤器,也不是“模型已经安全”的承诺。它是一组部署在信任边界上的版本化控制:不可信数据进入上下文前要检查,模型输出交给用户或下游系统前要验证,工具调用和外部副作用发生前要完成鉴权与审批。生产系统必须把概率性检测信号和可信代码执行分开,落实最小权限、完整中介、超时与故障语义,并同时度量误放行和误拦截。
核心要点
- 从资产、参与方、威胁与 Protected Sink 出发,不从厂商功能列表倒推架构。
- 用户输入、检索文档、模型输出、Tool Definition 与 Tool Result 都是不可信数据。
- Classifier 和 LLM Judge 负责提供 Signal,可信代码与下游服务负责 Enforcement。
- 每条到达私有数据或外部副作用的路径都要经过控制,包括子 Agent、Handoff、Retry 和直连 Adapter。
- 安全与效用必须一起评测;把正常请求全部拦掉不算有效护栏。
- Policy、Detector、Threshold、Routing 与 Fail Mode 应作为同一个发布单元版本化。
LLM Guardrails 是什么
LLM Guardrails 是在明确边界检测、约束、转换、阻断、升级或记录 AI 系统行为的一组控制。真正有用的控制单元不是“一个安全模型”,而是一条包含 Actor、Resource、Operation、Evidence、Decision 与 Audit Record 的策略决定。
AI Guardrails 术语页 负责简明定义;本文重点回答工程问题:检查应该放在哪里,哪些决定必须由确定性代码执行,怎样防止绕过,以及如何证明一次 Guardrail Release 适合真实 Workflow。
Guardrails 与模型对齐、安全软件工程和治理体系相互补充:
| 机制 | 主要职责 | 无法保证的事情 |
|---|---|---|
| System Prompt | 塑造模型行为 | 鉴权、数据隔离与副作用控制 |
| 模型对齐 | 改善训练分布内的行为 | 应用专属策略与完全抗攻击 |
| Classifier / LLM Judge | 产生风险信号 | 对每个对抗输入都判断正确 |
| Schema Validation | 约束结构与局部不变量 | 事实正确、权限正确或业务意图正确 |
| Authorization | 判断 Actor 能否访问 Resource 或执行 Operation | 生成内容是否有用或无害 |
| Approval Gate | 把可追责同意绑定到具体 Proposal | Proposal 变化后仍可安全执行 |
| Guardrail System | 跨边界编排控制与故障处置 | 零风险 |
一个模型可以输出 Schema 完全合法、但要求向未授权账户转账的 JSON;也可以返回看似无害的文字,同时通过 Tool Call 泄露私有数据。格式、内容、权限与副作用是不同的控制问题。
先做威胁建模,再设计护栏
Guardrail 架构首先要回答“必须阻止什么后果”。OWASP 的 LLM 应用风险覆盖 Prompt Injection、Sensitive Information Disclosure、Improper Output Handling、Excessive Agency 与 Unbounded Consumption。NIST Generative AI Profile 则把风险管理放在设计、开发、部署、使用和评测的完整生命周期中。两者都不能被简化成“接一个运行时分类器”。
为每个 Workflow 明确五类信息:
- 资产: 私有文档、Credential、Tenant Data、资金、生产系统、发布渠道与人身安全。
- 参与方: 最终用户、Operator、Administrator、外部内容作者、Tool Provider、Peer Agent 与被攻陷的依赖。
- 不可信输入: Prompt、文件、图像、Retrieval Chunk、Memory、Tool Description、Tool Output 与历史 Agent Message。
- Protected Sink: 模型 Context、用户可见输出、数据库查询、网络 Egress、文件写入、账户变更与不可逆操作。
- 不变量: Tenant Isolation、Read-only、预算上限、来源可追溯、高风险副作用前审批,以及输出中不得出现 Secret。
然后把不变量映射到边界:
| 边界 | 典型威胁 | 必要控制 |
|---|---|---|
| Ingestion | 被投毒文件、隐藏指令 | Type、Size、Malware、Provenance 与 Trust Label |
| Context Assembly | 跨租户检索、指令与数据混淆 | 检索前鉴权、Tenant Filter、来源标签 |
| Model Input | 直接注入、越界任务 | Scope Check、Risk Signal、Budget |
| Model Output | Secret 泄露、无证据结论 | Schema、Policy、Evidence、按目的地编码 |
| Tool Input | 危险或畸形参数 | Typed Schema、Allowlist、对象级鉴权、审批 |
| Tool Execution | 功能或权限过大 | 窄 Credential、Sandbox、Rate / Egress Limit |
| Tool Output | 恶意 Observation、敏感数据 | 再校验、Provenance、脱敏、Context Limit |
| External Effect | 转账、删除、发布、发送 | Proposal Digest、审批、幂等、下游鉴权 |
Prompt Injection 无法只靠关键词根治,因为模型通过同一套学习机制处理“指令”和“数据”。OWASP 因此强调输出校验、最小权限、高风险动作人工确认、外部内容隔离与对抗测试。关键词规则能识别已知句式,却不能证明输入安全。
护栏必须覆盖完整执行路径
完整中介(Complete Mediation)意味着:任何到达 Protected Sink 的路径都必须经过对应控制。只检查首个 Prompt 和最终 Answer,会遗漏检索、子 Agent、Tool Call 与服务直连路径。
Ingestion 与 Context Control
Ingestion Control 要在内容进入 Retrieval 或 Memory 前建立 Artifact 身份。至少保存 Provenance、Tenant、Owner、Sensitivity、Media Type、Parser Revision 与 Trust Level,并让这些标签贯穿 Chunking 和 Indexing。不要先检索全量结果,再期待模型遵守一句自然语言访问警告。
数据进入模型 Context 前就必须完成鉴权。输出过滤无法撤回已经发送给外部模型 Endpoint 的私有信息,Citation 也不能证明来源经过授权或值得信任。
Model Input 与 Output Control
Input Control 可以拒绝不支持的任务、统一编码、识别已知攻击模式,或把不确定请求路由到更强检查。返回值应包含结构化 Reason Code 与 Policy Version,而不是一个无法解释的 Boolean。
Output Control 必须匹配最终目的地。返回给用户的 Plain Text、浏览器渲染的 Markdown、数据库执行的 SQL,以及发给支付服务的 JSON Argument,需要不同的 Validation 与 Encoding。OWASP 把未校验模型输出直接交给下游称为 Improper Output Handling;工程上应把模型输出视为另一种不可信用户输入。
Tool 与 Effect Control
Tool Control 约束的是能力,不只是文本。优先提供 getOrder(customerID),而不是 runSQL(query);优先提供 createDraft(message),而不是 sendEmail(rawMessage)。即便安全 Classifier 给出低风险结论,Tool Service 仍然必须针对当前 Actor 和当前 Object 重新鉴权。
对于删除、转账、发布、发信和账户变更,应先暂停在一个具体 Proposal 上。审批必须绑定 Tool Name、Argument、Actor、Tenant、Target Resource 和 Policy Revision 的摘要;任一字段变化,原审批立即失效。
这也是 Prompt Injection 检测与 Approval Gate 的边界:前者提供“可能被操纵”的证据,后者在有责任主体批准精确副作用前阻止执行。
把检测信号与执行决定分开
Rule、Moderation Model、Anomaly Detector 和 LLM Judge 都有价值,因为不存在覆盖所有攻击形态的单一 Detector。但它们仍然只是 Signal,可能误判、不可用、延迟返回,也可能受到被检查内容的对抗影响。
一条 Decision Record 应显式保留这种不确定性:
{
"policyVersion": "payments-v7",
"boundary": "before_tool_effect",
"proposalDigest": "sha256:...",
"signals": [
{"source": "injection-detector-r4", "label": "suspicious", "score": 0.71},
{"source": "schema-v3", "label": "valid"}
],
"decision": "review",
"failureMode": "fail_closed",
"reasonCodes": ["HIGH_IMPACT", "UNCERTAIN_INPUT"]
}
Policy Engine 把证据转换成 allow、deny、review、redact 或 degrade,再由下游代码强制执行。这样设计有五个直接收益:
- 替换 Detector 时,不需要改变 Authorization 语义。
- 新 Threshold 可以先跑 Shadow Mode,不立即阻断流量。
- Detector Outage 与 Policy Denial 可以被准确区分。
- 历史 Evidence 可以在新 Policy 下重放。
- 审计时不依赖保存模型隐藏推理,也能解释为什么执行或拒绝。
不要使用一个全局 Risk Score 淹没语义。高置信度 Toxicity Signal 与 Authorization 缺失不是同一种风险,必须保留按控制分类的 Evidence 和 Reason Code。
用 Go 实现确定性的副作用门禁
下面的程序演示 Tool Proposal 的最终 Enforcement Boundary。它不试图识别所有危险 Prompt,而是检查 Tenant Scope、Tool Capability、金额上限、Proposal 完整性与审批绑定,然后才允许 Dispatch。示例只依赖 Go 标准库,控制契约可以直接运行和审阅。
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"sort"
"strconv"
)
type Proposal struct {
ActorID string `json:"actorId"`
Tenant string `json:"tenant"`
Tool string `json:"tool"`
Args map[string]string `json:"args"`
}
type Approval struct {
ProposalDigest string
ApproverID string
}
type Decision struct {
Action string
Reason string
Digest string
}
type Policy struct {
Tenant string
AllowedTools map[string]bool
MaxAmount int
}
func digestProposal(p Proposal) (string, error) {
keys := make([]string, 0, len(p.Args))
for key := range p.Args {
keys = append(keys, key)
}
sort.Strings(keys)
canonicalArgs := make(map[string]string, len(keys))
for _, key := range keys {
canonicalArgs[key] = p.Args[key]
}
p.Args = canonicalArgs
payload, err := json.Marshal(p)
if err != nil {
return "", fmt.Errorf("marshal proposal: %w", err)
}
sum := sha256.Sum256(payload)
return hex.EncodeToString(sum[:]), nil
}
func evaluate(policy Policy, p Proposal, approval *Approval) (Decision, error) {
digest, err := digestProposal(p)
if err != nil {
return Decision{}, err
}
if p.ActorID == "" || p.Tenant == "" {
return Decision{Action: "deny", Reason: "missing_identity", Digest: digest}, nil
}
if p.Tenant != policy.Tenant {
return Decision{Action: "deny", Reason: "tenant_mismatch", Digest: digest}, nil
}
if !policy.AllowedTools[p.Tool] {
return Decision{Action: "deny", Reason: "tool_not_allowed", Digest: digest}, nil
}
if p.Tool == "issue_refund" {
amount, err := strconv.Atoi(p.Args["amount"])
if err != nil {
return Decision{Action: "deny", Reason: "invalid_amount", Digest: digest}, nil
}
if amount <= 0 || amount > policy.MaxAmount {
return Decision{Action: "deny", Reason: "amount_out_of_policy", Digest: digest}, nil
}
if approval == nil {
return Decision{Action: "review", Reason: "approval_required", Digest: digest}, nil
}
if approval.ApproverID == "" || approval.ProposalDigest != digest {
return Decision{Action: "deny", Reason: "approval_not_bound", Digest: digest}, nil
}
}
return Decision{Action: "allow", Reason: "policy_satisfied", Digest: digest}, nil
}
func main() {
policy := Policy{
Tenant: "acme",
AllowedTools: map[string]bool{"lookup_order": true, "issue_refund": true},
MaxAmount: 500,
}
proposal := Proposal{
ActorID: "user-42",
Tenant: "acme",
Tool: "issue_refund",
Args: map[string]string{"orderId": "ORD-7", "amount": "120"},
}
first, err := evaluate(policy, proposal, nil)
if err != nil {
panic(err)
}
fmt.Printf("%s: %s\n", first.Action, first.Reason)
approval := Approval{ProposalDigest: first.Digest, ApproverID: "reviewer-9"}
second, err := evaluate(policy, proposal, &approval)
if err != nil {
panic(err)
}
fmt.Printf("%s: %s\n", second.Action, second.Reason)
proposal.Args["amount"] = "900"
third, err := evaluate(policy, proposal, &approval)
if err != nil {
panic(err)
}
fmt.Printf("%s: %s\n", third.Action, third.Reason)
}
预期输出:
review: approval_required
allow: policy_satisfied
deny: amount_out_of_policy
真实服务应使用最小货币单位的整数表示金额,从签名 Release 加载 Policy,验证 Approver 权限,一次性消费 Approval,持久化 Idempotency Key,并让支付服务再次执行 Authorization。核心原则不变:模型只负责 Proposal,可信系统负责 Decision 与 Execution。
上线前定义故障语义
任何 Guardrail 依赖都会超时、返回畸形数据或不可用。生产 Policy 必须提前说明系统下一步做什么。
| 边界 | 常见安全故障策略 | 原因 |
|---|---|---|
| 公共 FAQ Topic Classifier | 降级为窄回答或转人工 | 低影响不确定性下可优先保证可用性 |
| 私有 Retrieval Authorization | Fail Closed | Context 泄露不可逆 |
| Output PII Detector | Buffer、Fail Closed 或转 Review | 已泄露输出无法可靠召回 |
| Read-only Search Tool | 在预算内降级或重试 | 副作用有界 |
| Transfer、Delete、Publish、Send | Fail Closed 并保留 Proposal | 外部副作用后果重大 |
| Telemetry Exporter | 合规前提下本地持久缓冲 | 可观测故障不能静默取消 Enforcement |
并行执行可以降低延迟,但会改变安全语义。OpenAI Agents SDK 官方文档明确说明:并行 Input Guardrail 返回前,Agent 可能已经消耗 Token 或执行 Tool。只要失败检查必须阻止副作用,就应使用 Blocking Mode。Concurrency 是架构取舍,不是免费优化。
Retry 同样需要清晰语义。Detector 只能在 Deadline 内重试,绝不能把 unknown 自动解释成 safe。如果系统重写或重新生成结果,新的 Artifact 必须重新校验。应在受控访问范围内记录原始受限 Artifact、Transformation 与最终 Release Result。
流式输出不能假装可以撤回
Streaming 能改善感知延迟,但每个释放的 Chunk 都已经跨越 Trust Boundary。后续 Detector 无法删除浏览器已渲染、Client 已记录或 Integration 已转发的 Secret。
可以选择三种模式:
- Precheck 后 Streaming: 先完成必需的 Input / Policy Check,只在输出敏感度较低时直接流式返回。
- Buffered Streaming: 累积一个语义窗口,校验通过后释放;Buffer、Overlap 与 Final Flush 规则必须显式配置。
- Full-response Validation: 对高风险内容、受监管 Workflow 或会触发动作的输出,完整缓冲后再放行。
Chunk-level Classifier 会在切分边界丢失上下文。测试集需要覆盖被拆开的 Secret、敏感短语、多 Chunk 指令、Unicode Normalization、多语言内容,以及含义在后续 Chunk 才发生变化的句子。Buffer Policy 还要声明最大保留长度、Timeout、Cancellation 和校验依赖不可用时的用户体验。
把 Guardrails 当成系统评测
Guardrail Evaluation 必须同时度量 Security、Safety、Utility、Coverage 与 Operation。单一 Accuracy 或 F1 会隐藏误放行和误拦截的非对称成本。
先建立版本化 Evaluation Manifest:
release: guardrails-2026-09
model: support-model-revision
prompt: support-prompt-v12
policy: support-policy-v7
detectors:
- [email protected]
- [email protected]
tools:
- lookup-order-v3
- issue-refund-v2
datasets:
benign: support-benign-v5
adversarial: support-attacks-v8
outage: dependency-failures-v2
至少覆盖这些 Slice:
- 正常请求,包括困难但允许的内容。
- Direct / Indirect Prompt Injection。
- 多语言、编码、混淆与 Unicode Normalization 变体。
- 被投毒的 Retrieval Content 与恶意 Tool Output。
- Cross-tenant 与 Object-level Authorization 攻击。
- 子 Agent、Handoff、Retry 与 Direct-adapter Bypass。
- Detector Timeout、部分故障、Malformed Response 与 Stale Policy。
- 跨 Chunk 拆分的 Streaming Attack。
- 已知 Detector Threshold 后生成的 Adaptive Attack。
指标必须按 Control 与 Consequence 分开报告:
| 指标 | 回答的问题 |
|---|---|
| False Allow Rate | 禁止行为有多少被放行? |
| False Block Rate | 合法任务有多少被拒绝? |
| Safe Completion Rate | 允许任务有多少安全完成? |
| Unauthorized Effect Rate | 是否发生未授权外部操作? |
| Leakage Severity | 什么受保护数据跨越了边界? |
| Coverage | 哪些执行路径确实运行了必需控制? |
| Transformation Accuracy | 脱敏或重写是否保留合法语义? |
| Latency / Cost | 每条 Rail 在不同路由和分位数上的开销是多少? |
| Outage Behavior | 系统是否遵循声明的 Fail Mode? |
| Appeal Outcome | 哪些拒绝被推翻,原因是什么? |
后果允许时,新 Policy 应先运行 Shadow Mode,把 Would-block Decision 与人工判断比较,再按 Tenant 或 Workflow 做 Canary。False Block、False Allow、Latency 或 Incident 超过阈值时,Policy、Detector 与 Routing 必须作为一个 Release 整体回滚。
更完整的发布治理可以接入 企业级 LLMOps 架构。设计对抗测试时,可参考 提示词注入防御指南 与 AI 红队测试。
按控制契约选择组件
不要根据静态功能表或延迟表选择 Guardrail Framework。API、模型、部署方式与 Benchmark 都会变化,应先定义 Workflow 需要的控制契约。
评估候选组件时重点检查:
- Boundary Coverage: Input、Retrieval、Output、Tool Input、Tool Output 与 External Effect。
- Enforcement Ownership: 只返回 Signal,还是能够可靠阻止执行。
- Policy Identity: 版本、签名配置、Tenant Override 与 Rollback。
- Failure Semantics: Timeout、依赖不可用、Malformed Result 与 Stale Cache。
- Streaming Behavior: Buffer、Overlap、Final Flush 与 Cancellation。
- Evidence: Reason Code、Trace、Redaction、Privacy Control 与 Replay。
- Evaluation: 正常 / 对抗 Dataset、Threshold Calibration 与 Drift Monitoring。
- Deployment: Data Residency、Isolation、Scaling、Cost 与运维责任。
框架提供的 Hook 不一定覆盖每条路径。OpenAI Agents SDK 文档说明 Agent Input Rail 运行在第一个 Agent,Output Rail 运行在最终 Agent,Tool Rail 包围受支持的 Function Tool;Hosted Tool、Handoff 与直连 Adapter 可能具有不同覆盖范围。NVIDIA NeMo Guardrails 则提供 Input、Retrieval、Dialog、Execution 与 Output Rail。这些是有价值的 Integration Surface,但都不能自动证明你的应用实现了 Complete Mediation。
常见失败模式
把 System Prompt 当成 Authorization
Prompt 可以告诉模型不要访问其他 Tenant,却无法阻止高权限数据库 Credential 执行查询。Actor、Tenant、Resource 与 Operation 必须由下游服务强制校验。
只拦截词句,不约束能力
攻击者可以改写、编码、拆分、翻译指令,也可以把指令放进文档和图像。Detection 只应作为一个 Signal,Tool、Credential、Network Access 与 Effect 必须独立最小化。
过度信任 Structured Output
通过 Schema 的输出仍可能包含未授权 Resource ID、危险 URL、无证据事实或违反业务规则的字段。Parse 之后仍要执行语义和权限校验。
Mandatory Check 完成前就开始 Streaming
停止后续 Chunk 无法撤回前面的 Chunk。敏感输出必须 Buffer,并明确 Release Boundary。
只验证 Happy Path
Manager、Specialist、Handoff、Retry、Cached Result、Local MCP Server、Hosted Tool 与 Direct SDK Call 可能绕过挂在单个 Agent 上的 Rail。应测试执行路径覆盖率,而不只测试 Classifier Accuracy。
只优化 Attack Recall
过度激进的 Rail 会让产品无法使用。按语言、Tenant、Topic 与用户群体跟踪 Safe Completion 与 False Block;拒绝会产生实际影响时,还要提供 Appeal 或 Escalation Path。
常见问题
LLM Guardrails 等于内容审核吗?
不等于。Content Moderation 负责分类或过滤内容类别;Guardrail System 还可以执行 Schema、Tenant Isolation、Tool Permission、Approval、Budget、Egress Policy、Rate Limit 与 Rollback。Moderation 只是其中一种 Signal。
Guardrails 能消除模型幻觉吗?
不能。Guardrails 可以要求 Citation、把 Claim 与授权 Evidence 比较、限制无证据动作,或在证据不足时拒答。这些控制能降低影响,但不能把概率生成器变成绝对正确的数据源。完整事实边界参见 大模型幻觉指南。
每个 Detector 都应该检查所有请求吗?
不应该。根据 Threat Model 和后果运行必要控制。确定性 Authorization 与 Schema Check 通常是 Mandatory;昂贵的语义检查可以按 Workflow、Sensitivity、Uncertainty 路由或抽样监控,但 Routing 本身必须版本化并接受评测。
LLM Judge 足以执行安全策略吗?
LLM Judge 可以提供语义 Evidence,但仍然是概率性的,也会受 Distribution Shift 与对抗输入影响。可信代码必须解析它的结构化结果,应用 Threshold 与 Fail Mode,并执行有后果的 Decision。
最小可用 Guardrail 架构包括什么?
低风险助手至少需要授权后的 Context Assembly、明确 Task Scope、按目的地处理输出、Rate / Token Budget 与 Audit Log。一旦系统能访问私有数据或产生外部副作用,就应加入 Tool Allowlist、Object-level Authorization、Approval、Sandbox 与 Buffered Output。
总结
可靠的 LLM Guardrails 是应用架构,不是模型功能。先定义 Threat 与 Protected Sink,再保留 Trust Label、分离 Signal 与 Enforcement、完整中介所有数据和副作用路径,并在上线前声明故障行为。最后把 False Allow、False Block、Safe Completion、Coverage、Latency、Outage 与 Incident 纳入同一个 Release Contract。