Agent 能诊断、能开工单,但如果它突然说「建议立即停机」呢?工业场景下,Agent 的每个「动作」都可能影响生产线。三层护栏------输入过滤、输出审核、操作拦截------是 Agent 上产线的安全底线。
问题:Agent 的输出不可预测
LLM 的本质是概率模型------你无法保证它的输出 100% 安全。在工业场景下:
- 输入注入------恶意用户构造特殊提示词,让 Agent 执行危险操作
- 输出泄露------Agent 可能在回复中暴露 API Key、数据库密码
- 操作越权------Agent 建议「立即停机」,但它不应该有停机权限
护栏不是限制 Agent 的能力,而是限制它犯错的半径。
三层护栏架构
css
用户输入 → [InputGuard] → Agent 推理 → [OutputGuard] → [ActionGuard] → 最终输出
↓
L3/L4 → 需人工审批
L0-L2 → 直接执行
| 层 | 职责 | 拦截什么 |
|---|---|---|
| InputGuard | 输入过滤 | 危险指令、超长输入、SQL 注入 |
| OutputGuard | 输出审核 | 敏感信息泄露、危险 SQL |
| ActionGuard | 操作分级 | 高风险操作需审批 |
第一层:InputGuard
java
@Component
public class InputGuard {
private static final List<Pattern> BLOCKED = List.of(
Pattern.compile("(?i)(删除|drop|truncate).*数据库"),
Pattern.compile("(?i)(rm\\s+-rf|format|fdisk)"),
Pattern.compile("(?i)ignore.*safety|bypass.*guard")
);
public GuardResult check(String input) {
if (input.length() > 2000) return GuardResult.blocked("输入超长");
for (Pattern p : BLOCKED) {
if (p.matcher(input).find()) return GuardResult.blocked("危险指令");
}
return GuardResult.passed();
}
}
拦截原则:宁可误拦,不可漏放。 误拦了用户可以重新表述,漏放了可能损坏设备。
第二层:OutputGuard
java
@Component
public class OutputGuard {
private static final List<Pattern> SENSITIVE = List.of(
Pattern.compile("(?i)(api.?key|密码|password|secret)\\s*[:=]\\s*\\S+"),
Pattern.compile("(?i)(DROP\\s+TABLE|DELETE\\s+FROM)")
);
public GuardResult check(String output) {
for (Pattern p : SENSITIVE) {
if (p.matcher(output).find()) return GuardResult.blocked("输出含敏感信息");
}
return GuardResult.passed();
}
}
LLM 有时会在回复中输出训练数据中的敏感信息。OutputGuard 在回复发给用户之前做最后一道检查。
第三层:ActionGuard
java
@Component
public class ActionGuard {
public RiskLevel classifyRisk(String action) {
if (action.matches(".*停机|关机|shutdown.*")) return RiskLevel.L3;
if (action.matches(".*修改参数|调整阈值.*")) return RiskLevel.L3;
if (action.matches(".*创建工单.*")) return RiskLevel.L2;
if (action.matches(".*诊断|分析.*")) return RiskLevel.L1;
return RiskLevel.L0;
}
}
风险分级:
| 级别 | 操作 | 处理 |
|---|---|---|
| L0 | 查询数据、告警 | 直接执行 |
| L1 | 诊断分析 | 直接执行 |
| L2 | 创建工单 | 执行后通知 |
| L3 | 停机、修改参数 | 需人工审批 |
| L4 | 紧急停机 | 需双人审批 |
熔断器:连续失败时降级
Agent 连续 3 次出错(工具调用失败、LLM 超时等),熔断器开启,暂时阻止新请求:
java
@Component
public class CircuitBreaker {
enum State { CLOSED, OPEN, HALF_OPEN }
private static final int FAILURE_THRESHOLD = 3;
private static final long RECOVERY_MS = 60_000; // 1 分钟后尝试恢复
public boolean isAllowed() {
if (state == CLOSED) return true;
if (state == OPEN && elapsed > RECOVERY_MS) {
state = HALF_OPEN; // 允许一个测试请求
return true;
}
return state == HALF_OPEN;
}
}
状态流转:
objectivec
CLOSED(正常)→ 连续3次失败 → OPEN(熔断)→ 60s后 → HALF_OPEN → 成功 → CLOSED
→ 失败 → OPEN
熔断期间返回:「Agent 暂时不可用,请稍后重试或联系值班工程师」。
GuardrailChain:串联三层护栏
java
@Component
public class GuardrailChain {
public GuardResult checkInput(String input) {
if (!circuitBreaker.isAllowed()) {
return GuardResult.blocked("熔断器开启,Agent 暂时不可用");
}
return inputGuard.check(input);
}
public GuardResult checkOutput(String output) {
return outputGuard.check(output);
}
public GuardResult checkAction(String action) {
return actionGuard.check(action);
}
}
每次检查都写审计日志(谁、什么时间、什么操作、通过/拦截),事后可追溯。
API 接口
bash
# 检查输入安全性
POST /api/guardrail/check-input
{"input": "删除数据库所有记录"}
→ {"passed": false, "reason": "检测到危险指令"}
# 检查操作风险等级
POST /api/guardrail/check-action
{"action": "CNC-001 立即停机"}
→ {"passed": false, "riskLevel": "L3", "reason": "高风险操作需人工审批"}
# 查看护栏状态
GET /api/guardrail/status
→ {"circuitBreaker": "CLOSED", "auditLogSize": 15}
# 审计日志
GET /api/guardrail/audit
护栏 vs 提示词约束
| 提示词约束 | 代码护栏 | |
|---|---|---|
| 实现 | SystemMessage 中写「不要...」 | Java 正则 + 规则 |
| 可靠性 | LLM 可能忽略 | 100% 执行 |
| 可审计 | 不可 | 每次拦截有日志 |
| 适合 | 软性引导 | 硬性安全底线 |
两者互补,不能互替。 提示词约束是「建议」,代码护栏是「法律」。
代码仓库:github.com/LaoLiang-ag...
本文由 LaoLiang 原创,首发于掘金/知乎/微信公众号。转载请联系作者。