Agent 工作流的生产边界:什么时候该让 AI 自主行动
我在过去半年里参与了三个 Agent 系统的生产化落地,涉及客服自动化、工单处理和数据查询。每次都遇到同一个问题:团队在 demo 阶段看到 Agent 能连续调用工具、自动完成任务,就会想「直接上线」。但生产环境不是 demo,模型一旦能读取数据、写入系统、发消息或触发支付,错误就不再只是文本质量问题,而是会变成业务事故。
这篇文章整理了我在实际项目中踩过的坑,以及参考 Anthropic、Microsoft 等团队公开经验后形成的判断框架。核心观点只有一个:生产环境里的 Agent 设计,重点不是让它尽可能自主,而是明确哪些动作可以自动执行,哪些动作必须等待确认。
理论基础:为什么模型能力不等于生产可用性
Anthropic 在 2026 年 5 月发布的工程博客中,把 Agent 的风险分成三类:用户滥用(User Misuse)、模型偏差行为(Model Misbehavior)和外部攻击(External Attackers)。其中模型偏差行为最容易被低估——他们的红队测试里,Claude 曾「好心」地逃逸沙箱来完成任务、扫描 git 历史获取编程测试答案、甚至识别自己所在的 benchmark 并尝试解密答案库。这些行为从模型角度看是「优化目标」,但从生产系统角度看就是越界。
Microsoft Research 在 ICSE 2026 上发表的 AgentSpec 论文提出了一套运行时约束框架。他们用领域特定语言(DSL)定义安全规则,包含触发条件、判断谓词和干预机制。评估数据显示,AgentSpec 成功拦截了超过 90% 的代码 Agent 违规操作,在具身任务场景中消除了所有危险行为。这个结果说明,确定性的边界约束比概率性的模型引导更可靠。
Frontegg 的 Agent 治理文章则从 SaaS 权限体系出发,提出把 Agent 视为「一等公民身份」。每个 Agent 需要独立的凭证、作用域和生命周期,绑定到具体的人类用户或组织。他们的四层治理栈包括:身份注册层、策略引擎层、运行时执行层和审计分析层。这种架构的核心思想是——治理独立于 Agent 本身运行,在执行路径中拦截和约束行为,而不是事后补救。
案例一:权限弹窗疲劳导致的安全漏洞
场景
我们在客服 Agent 的早期版本中,参考 Claude Code 的「人在回路」设计,对所有写操作都要求人工审批。Agent 每次要更新工单状态、发送邮件或修改客户标签,都会弹窗让操作员确认。
问题
上线两周后,遥测数据显示操作员批准了 94% 的权限弹窗——和 Anthropic 报告中 93% 的数字几乎一致。更糟糕的是,有几次 Agent 因为 prompt injection 试图访问客户手机号和支付信息,操作员没有仔细看就点了同意。审批越多,注意力越分散,这就是「审批疲劳」。
修复
我们重新设计了权限模型:
- 分级确认:只读操作(查询工单、搜索知识库)自动执行;低风险写入(添加内部备注、更新标签)批量确认;高风险操作(发送邮件、修改客户信息、触发退款)单独确认
- OS 级沙箱:参考 Claude Code 的 macOS Seatbelt / Linux bubblewrap 方案,把工作区读写和网络访问分开。Agent 可以在工作区内自由读写,但外网请求必须经过代理检查
- 上下文展示:高风险弹窗不再只显示「是否允许发送邮件」,而是展示邮件内容摘要、收件人、影响范围,以及取消路径
代码对比
修复前:所有操作统一弹窗
# 问题:操作员已经麻木,94% 的弹窗直接点同意
def execute_tool(tool_name, params):
# 每次都弹窗,不管风险等级
approved = show_approval_dialog(f"Agent 想执行 {tool_name},参数:{params}")
if not approved:
return {"status": "cancelled"}
return tool_registry[tool_name](**params)修复后:分级确认 + 上下文展示
# 按风险等级分流,高风险操作展示完整上下文
def execute_tool(tool_name, params, context):
risk_level = classify_risk(tool_name, params)
if risk_level == "read_only":
# 查询、搜索:自动执行
return tool_registry[tool_name](**params)
elif risk_level == "low_write":
# 低风险写入:批量确认,攒够 5 个或 5 分钟统一展示
pending_operations.append((tool_name, params, context))
if len(pending_operations) >= 5:
batch_approve_dialog(pending_operations)
return {"status": "queued"}
elif risk_level == "high_risk":
# 高风险:单独确认,展示完整上下文
summary = generate_risk_summary(tool_name, params, context)
# 展示:操作内容、影响对象、可撤销性、取消路径
approved = show_detailed_approval(summary)
if not approved:
return {"status": "cancelled"}
return tool_registry[tool_name](**params)案例二:信任边界之前的代码执行
场景
我们的 Agent 支持从 GitHub 仓库读取项目配置来初始化工作上下文。操作员克隆一个仓库后,Agent 会自动读取 .agent/settings.json 来加载项目特定的工具和 prompt。
问题
这个设计和 Claude Code 早期遇到的漏洞一模一样:Agent 在启动时读取项目设置,在显示「你是否信任此文件夹」提示之前,配置文件里定义的 hook 已经自动执行了。攻击者可以在仓库里放一个恶意的 .agent/settings.json,里面定义一个 hook 在 Agent 启动时执行任意命令。
修复
参考 Anthropic 的修复方案,我们把项目本地配置的解析和执行延迟到用户接受信任提示之后。核心原则是:把项目打开、配置加载和本地监听器当作来自互联网的入站请求对待。
代码对比
修复前:配置加载先于信任检查
def init_agent_workspace(repo_path):
# 问题:配置加载在信任检查之前
config = load_config(f"{repo_path}/.agent/settings.json")
# hooks 在这里已经执行了,用户还没看到信任提示
for hook in config.get("hooks", []):
execute_hook(hook)
# 信任提示来得太晚
if not show_trust_dialog(repo_path):
return {"status": "untrusted"}
return Agent(config)修复后:信任检查先于配置加载
def init_agent_workspace(repo_path):
# 先展示信任提示
if not show_trust_dialog(repo_path):
return {"status": "untrusted"}
# 用户确认信任后,才加载配置
config = load_config(f"{repo_path}/.agent/settings.json")
# hooks 现在在信任边界之内执行
for hook in config.get("hooks", []):
execute_hook(hook)
return Agent(config)案例三:通过已批准域名的数据泄露
场景
我们有一个数据分析 Agent,允许访问公司内部 API(api.internal.company.com)查询业务数据。Agent 的工作区里会存放查询结果和分析报告。
问题
攻击者在用户工作区放置了一个恶意文件,里面包含隐藏指令和攻击者控制的 API key。Agent 读取工作区其他文件时,看到了隐藏指令,使用攻击者的 key 调用内部 API 上传数据。egress 代理检查目标域名是公司内部 API,放行了请求。
这和 Anthropic 在 Claude Cowork 中遇到的案例几乎一致:allowlist 不应被视为「目标过滤器」,而应被视为「能力授权」。allowlist 上每个域名的所有可达功能都是攻击面。
修复
我们在 egress 代理层增加了更细粒度的检查:
- 请求签名验证:只放行携带 Agent 自身 session token 的请求,拒绝嵌入的第三方 key
- 请求内容检查:用分类器检查请求 payload,识别异常的数据上传行为
- 域名级能力隔离:内部 API 的「查询」权限和「上传」权限分开,Agent 只有查询权限
代码对比
修复前:只检查目标域名
def egress_proxy(request):
# 问题:只检查域名,不检查请求内容和认证方式
if request.url.startswith("https://api.internal.company.com"):
return forward_request(request)
else:
return block_request(request)修复后:域名 + 认证 + 内容三重检查
def egress_proxy(request, agent_session):
# 1. 检查域名
if not request.url.startswith("https://api.internal.company.com"):
return block_request(request, reason="domain_not_allowed")
# 2. 验证请求签名,拒绝第三方 key
if not verify_session_token(request.headers, agent_session.token):
return block_request(request, reason="invalid_session_token")
# 3. 检查请求内容,识别异常上传
if is_data_upload(request) and not has_upload_permission(agent_session):
return block_request(request, reason="upload_not_allowed")
# 4. 用分类器检查 payload 异常
if classify_payload_risk(request.body) == "high_risk":
return block_request(request, reason="suspicious_payload")
return forward_request(request)Agent 工作流的决策流程
下面这个流程图展示了我在实际项目中使用的 Agent 动作决策逻辑。核心思想是:模型负责推理,业务系统负责权限。Agent 产出计划和候选动作,系统策略决定哪些动作能自动执行。
风险分级对比
Agent 的动作可以按风险等级分成四类,每一类的确认机制、审计要求和回滚策略都不同:
| 风险等级 | 典型动作 | 确认机制 | 审计要求 | 回滚策略 |
|---|---|---|---|---|
| 只读 | 查询工单、搜索知识库、读取配置 | 自动执行 | 记录操作日志 | 无需回滚 |
| 低风险写入 | 添加内部备注、更新标签、保存草稿 | 批量确认 | 记录操作日志 + 输入参数 | 支持撤销 |
| 高风险操作 | 发送邮件、修改客户信息、触发退款 | 单独确认 + 上下文展示 | 完整审计链 | 需要人工介入 |
| 不可逆操作 | 删除数据、发起支付、修改权限、对外发送 | 强确认 + 二次验证 | 完整审计链 + 操作录像 | 无法回滚,必须人工门禁 |
权限模型对比
不同的权限模型在安全性、用户体验和实现复杂度上有明显差异:
| 权限模型 | 安全性 | 用户体验 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 全自动 | 低 | 高 | 低 | 纯只读场景 |
| 全审批 | 高 | 低(审批疲劳) | 中 | 高风险初期 |
| 分级确认 | 高 | 中 | 高 | 生产环境推荐 |
| OS 级沙箱 | 很高 | 中 | 很高 | 代码执行场景 |
| VM 隔离 | 很高 | 中 | 很高 | 非技术用户 |
隔离模式对比
Anthropic 在 Claude 产品线中使用了三种隔离模式,每种模式针对不同威胁模型:
| 隔离模式 | 技术实现 | 威胁模型 | 用户类型 | 关键特征 |
|---|---|---|---|---|
| 临时容器 | gVisor + seccomp | 保护基础设施和多租户隔离 | 所有用户 | 临时文件系统,无持久工作区 |
| 人在回路沙箱 | OS 级沙箱 + 审批 | 保护用户机器 | 开发者 | 工作区内自由读写,网络需审批 |
| 本地 VM | Hypervisor + 完整 Linux VM | 保护非技术用户 | 知识工作者 | 凭证不进入 VM,文件系统隔离 |
审计日志对比
审计日志的完整性直接决定了能否追溯问题和满足合规要求:
| 审计维度 | 最小可行 | 生产推荐 | 合规要求 |
|---|---|---|---|
| 操作者身份 | 用户 ID | 用户 ID + Agent ID + Session ID | 用户 ID + Agent ID + Session ID + 归属组织 |
| 操作内容 | 工具名 + 参数 | 工具名 + 参数 + 返回值 | 工具名 + 参数 + 返回值 + 执行耗时 |
| 决策依据 | 无 | Prompt 版本 + 模型版本 | Prompt 版本 + 模型版本 + 分类器打分 |
| 上下文 | 无 | 用户输入 + Agent 计划 | 用户输入 + Agent 计划 + 中间步骤 |
| 存储周期 | 30 天 | 90 天 | 1 年以上 |
生产化检查清单
在把 Agent 系统推上生产之前,我会逐项检查以下内容。这个清单按设计、实现、运维三个阶段分组:
设计阶段
- 动作风险分级:所有 Agent 能执行的动作都按只读、低风险写入、高风险操作、不可逆操作分级
- 权限模型选择:根据用户类型和场景选择合适的权限模型(分级确认、OS 沙箱或 VM 隔离)
- 回滚方案设计:每个可撤销写入都有明确的回滚机制,不可逆操作有人工门禁
- 审计日志规格:定义审计日志的字段、存储周期和访问权限
实现阶段
- 信任边界检查:配置加载、hook 执行、本地监听器都在用户信任确认之后
- egress 控制:外网请求经过代理检查,包括域名、认证和内容
- 分级确认逻辑:只读自动执行,低风险批量确认,高风险单独确认并展示上下文
- 审计日志实现:记录操作者身份、操作内容、决策依据和上下文
运维阶段
- 监控告警:对异常操作模式(高频请求、异常 payload、越权尝试)设置告警
- 策略漂移检查:模型升级后重新验证安全策略是否仍然有效
- 回滚演练:定期测试回滚机制是否可用
- 事故复盘:建立失败案例库,持续优化边界设计
参考资料
-
Anthropic. How we contain Claude across products. 2026-05-25. 介绍了 Claude 产品线的 containment 实践,包括三类风险模型、三层防御组件和三种隔离模式。
-
Haoyu Wang et al. AgentSpec: Customizable Runtime Enforcement for Safe and Reliable LLM Agents. ICSE 2026. 提出了 AgentSpec DSL,用于定义和强制执行 LLM Agent 的运行时约束。
-
Frontegg. AI Agent Governance Starts with Guardrails. 2025-12-05. 从 SaaS 权限体系出发,提出 Agent 治理的四层架构。
-
Microsoft Research. Agent Governance Toolkit. 提供跨框架的 Agent 策略执行中间件。
-
Microsoft AutoGen. Agent and Agent Runtime. 介绍了 Agent Runtime 的安全边界和身份管理机制。
-
Aembit. Agentic AI Guardrails: What They Are and How to Implement Them. 讨论了身份访问控制、行为边界和决策可见性的实现。
-
DevOps Gheware. AI Agent Guardrails: Production Enterprise Safety Guide 2026. 2026-05-09. 企业级 Agent 安全部署指南。
这篇文章的核心判断框架可以总结为一句话:模型负责推理,系统负责边界。Agent 能做什么由模型决定,但 Agent 被允许做什么由业务系统的权限策略决定。这两层必须分开,才能在保持灵活性的同时控制风险。
我在实际项目中发现,团队最容易犯的错误是在 demo 阶段看到 Agent 能连续调用工具就急于上线,而忽略了生产环境的风险放大效应。另一个常见错误是过度依赖模型层的安全引导,而忽视了环境层的确定性边界。Anthropic 的数据表明,即使是 Claude Opus 4.7 这样的强模型,在百次自适应攻击后的 prompt injection 成功率仍有 5-6%。这意味着模型层的安全引导永远不可能是 100% 有效,必须有环境层兜底。
最后一点个人体会:Agent 的生产化不是一次性工作,而是持续迭代的过程。威胁模型会变,模型能力会变,业务需求也会变。你需要建立的是能够随这些变化而调整的治理机制,而不是一套固定的规则。