当 AI 模型从“回答一次问题”转向持续数小时甚至更久地规划、调用工具和修正行动时,安全工程的对象也发生了变化。OpenAI 在长期运行模型的部署经验中强调:更长的任务周期会带来新的安全风险,真实运行中暴露的失败需要通过迭代部署转化为更可靠的防护措施。
这意味着,团队不能只检查模型的单次输出是否合规,还要控制它在整个任务生命周期里能做什么、做了多少次,以及偏离目标后能否被及时停止。
风险来自行动的累积,而不只是某一句回答
短对话中的错误通常容易定位:输入、输出以及中间上下文都比较有限。长时程模型则可能经历“制定计划、调用工具、读取结果、修改计划、再次执行”的循环。每一步看起来都合理,累积起来却可能越过原本的授权边界。
可以把这类风险拆成几个工程问题:
- 目标漂移:模型在反复规划后逐渐偏离用户最初的意图。
- 错误放大:早期的错误假设进入后续上下文,驱动更多错误操作。
- 权限累积:多个低风险操作组合后产生高风险结果。
- 监督疲劳:运行时间越长,人工逐步检查每次工具调用越不现实。
- 停止失效:系统虽然有超时设置,却没有限制调用次数、成本或外部副作用。
这些分类是面向工程落地的一种分析方式,并不代表来源摘要列出的具体故障清单。关键变化在于:长时程系统的安全性不能仅靠提示词约束,而要由运行时控制共同保证。
把安全策略放到模型循环之外
模型可以提出下一步行动,但不应自行决定所有行动是否获准。更稳妥的架构是在模型与工具之间增加策略执行层,由确定性代码检查预算、权限和审批状态。
一套最小控制面通常包括:
- 多维预算:同时限制墙钟时间、推理轮数、工具调用次数和费用。
- 分级授权:读取、写入、删除、付款和对外通信使用不同权限。
- 高风险审批:不可逆操作必须由人或独立策略服务确认。
- 完整审计:记录模型请求的动作、策略判定、执行结果和关联任务 ID。
- 外部停止机制:停止信号由模型进程之外的组件管理。
- 受控回滚:写操作优先进入暂存区、草稿或事务,而不是直接影响生产环境。
这里有一个重要边界:让模型“自我反思是否安全”可以增加一层信号,但不能替代外部策略。模型可能在同一个错误上下文中同时生成行动与安全判断,二者并不独立。
可以这样实践:为代理循环增加预算、审批和审计
下面是一个可直接运行的最小 Python 示例。它不依赖真实模型 API,而是模拟代理连续提出动作,重点展示如何在执行器一侧设置控制边界。接入实际系统时,将 propose_action() 替换为模型调用,并将 execute() 替换为受限工具适配器。
from __future__ import annotations
import json
import time
from dataclasses import asdict, dataclass
from pathlib import Path
@dataclass
class Action:
name: str
target: str
irreversible: bool = False
class SafetyController:
def __init__(self, max_steps: int = 5, max_seconds: int = 10):
self.max_steps = max_steps
self.deadline = time.monotonic() + max_seconds
self.steps = 0
def authorize(self, action: Action) -> tuple[bool, str]:
if time.monotonic() > self.deadline:
return False, 'time budget exceeded'
if self.steps >= self.max_steps:
return False, 'step budget exceeded'
if action.irreversible:
return False, 'human approval required'
if action.name not in {'read', 'draft'}:
return False, 'tool is not allowlisted'
self.steps += 1
return True, 'approved'
def propose_action(step: int) -> Action:
plan = [
Action('read', 'requirements.md'),
Action('draft', 'change.patch'),
Action('read', 'test-results.txt'),
Action('delete', 'production.db', irreversible=True),
]
return plan[min(step, len(plan) - 1)]
def execute(action: Action) -> str:
return f'simulated {action.name} on {action.target}'
def append_audit(record: dict) -> None:
with Path('agent-audit.jsonl').open('a', encoding='utf-8') as file:
file.write(json.dumps(record, ensure_ascii=False) + '\n')
def main() -> None:
controller = SafetyController(max_steps=5, max_seconds=10)
for step in range(10):
action = propose_action(step)
allowed, reason = controller.authorize(action)
record = {
'task_id': 'demo-001',
'step': step,
'action': asdict(action),
'allowed': allowed,
'reason': reason,
}
if not allowed:
append_audit(record)
print(f'STOP: {reason}: {action}')
break
record['result'] = execute(action)
append_audit(record)
print(record['result'])
if __name__ == '__main__':
main()
运行方式:
python safety_controller.py
cat agent-audit.jsonl
程序执行到不可逆的 delete 动作时会停止,并在审计日志中写入拒绝原因。真实接入时还应做三项改造:不要允许模型直接构造任意 shell 命令;将审批令牌与具体动作参数绑定;把审计日志发送到模型无法修改的外部存储。
迭代部署不是降低标准,而是缩小未知风险的暴露面
长期运行模型的失败模式很难仅靠上线前测试穷举。来源摘要强调从实际部署中观察失败,并持续改进防护措施。工程上的合理做法,是让部署本身具备可控范围和快速反馈能力。
可以按以下顺序扩大权限:
- 在离线回放环境中运行,不允许产生外部副作用。
- 进入影子模式,只记录模型想执行的动作,不真正执行。
- 向少量内部用户开放,只允许读取和生成草稿。
- 开放受限写操作,但要求事务、回滚和抽样复核。
- 只有在故障率、越权率和人工接管率达到预设阈值后,才扩大任务时长与工具权限。
评估指标也要从“答案是否正确”扩展到过程指标,例如每个任务的工具调用数、被策略拒绝的动作比例、目标变更次数、人工接管原因、预算耗尽率,以及停止信号生效所需时间。
上线前检查清单
长时程能力越强,越需要明确的运行边界。团队在开放真实工具之前,至少应确认以下事项:
- 每个任务都有时间、步骤、成本和调用次数上限。
- 工具默认无权限,权限按任务和参数显式授予。
- 删除、付款、发布和对外通信需要独立审批。
- 模型无法关闭监控、修改审计记录或延长自己的预算。
- 中断后可以恢复到已知状态,而不是盲目继续旧计划。
- 失败样本会进入回放测试集,并在下一轮部署前验证修复效果。
长时程模型的价值来自持续行动,但风险也来自同一个能力。真正可靠的方案不是要求模型永远不犯错,而是让错误尽早暴露、限制影响范围,并把每次失败转化为下一轮部署中的可执行防护规则。