
最近折腾 AI Agent 管道,踩了几个差点删库的坑,这篇把问题说清楚。
生产环境里的 AI Agent 能把你的数据库删个干净。不是因为模型有恶意,是因为它根本不知道自己不知道什么。它看到个解析不了的弹窗,猜了个错误操作,然后这个猜测就在生产系统上执行了。
这个问题我见过的项目够多了,知道它不是理论风险。问题不是你的 Agent 会不会犯错,而是你的架构能不能在犯错时活下来。
下面是我在生产环境搭 LLM 管道、浏览器自动化 Agent、RAG 系统学到的东西。真正管用的安全模式。
每个 AI Agent 的操作都应该在无法直接访问生产数据的环境里运行。这听起来是废话,但我见过团队跳过这一步,因为"模型只是生成文字,干不了什么危险的事"。
生成文字的模型可以调用函数。函数可以请求 API。API 可以删除数据行。
我之前做的招聘平台,LLM 评分管道批量处理职位信息。架构很严格:模型从不直接碰数据库。它接收结构化输入,返回结构化输出,然后中间件层在数据接触任何一行之前验证每个字段。
// Agent 永远得不到直接的数据库访问权限
// 它通过验证中间件进行通信
async function processAgentAction(action: AgentAction): Promise<ActionResult> { // 步骤 1: 根据允许的操作列表验证操作 const validation = validateAction(action, ALLOWED_ACTIONS); if (!validation.valid) { return { status: 'rejected', reason: validation.error }; } // 步骤 2: 在沙箱事务中执行 // Agent 只能执行 READ 操作 // 任何 WRITE 都需要明确的、人工审批 if (action.type === 'write') { return { status: 'pending_approval', action }; } // 步骤 3: 记录所有操作用于审计 await auditLog.create({ agent: action.agentId, action: action.type, timestamp: new Date(), approved: action.type === 'read' // 读取操作自动审批 }); return executeRead(action);
} 规则很简单:Agent 提议,系统执行。没有审批门控就不存在写路径。
假设你在做一个自动投递简历的模块。Agent 浏览职位、填写表单、提交申请。听起来很自动化,但问题来了——Agent 用错误的简历投了错误的职位。
有效的做法是逐个操作审批。候选人看到每个匹配结果,审查摘要,然后在 Agent 执行前明确审批。这不是点一次就忘的复选框。每次都是深思熟虑的决定。
这个模式很关键,因为审批疲劳是真实存在的。如果你让人审批 100 个操作,他们就不看了。点几下就过了。这比没有审批更糟糕,因为它制造了虚假的安全感。
有效的做法是按人类注意力跨度来批量审批。一次展示 5-10 个匹配结果,配上清晰的操作预览。候选人看看职位名称、公司、短摘要,然后审批。Agent 处理剩下的。
对于支付或账户变更这类高风险操作,审批门控需要明确。单独的确认弹窗。要求输入文字。必须让用户真正参与进来。
我见过的最危险的 AI Agent bug 不是做错了事的那种。是反复做错事的那种。
幂等操作不管调用多少次都产生相同的结果。如果你的 Agent 发送"创建线索"的 API 调用,而 API 每次都创建重复的线索,重试循环或者困惑的 Agent 就会把你的系统灌满垃圾数据。
在招聘平台上,每个管道步骤都是按幂等设计的:
// 幂等的职位处理
// 运行 10 次的结果和运行 1 次相同
async function processJobListing(jobId: string, source: string): Promise<void> { // 使用唯一约束防止重复 // 数据库拒绝具有相同 externalId 的第二次插入 await db.jobListing.upsert({ where: { externalId: `${source}_${jobId}` }, create: { externalId: `${source}_${jobId}`, title: rawData.title, company: rawData.company, // ... 其他字段 }, update: { // 只更新应该变化的字段 lastSeenAt: new Date(), status: rawData.status, } });
} upsert 模式是你的好朋友。它说"新数据就插入,已存在就更新"。不会有重复。不管管道运行多少次。
对于浏览器自动化 Agent,幂等性意味着操作前先检查状态。"这个按钮已经点过了吗?这个表单已经提交了吗?这个弹窗已经关闭了吗?"Agent 应该先读取,再行动。
每个 AI Agent 操作都应该要么可逆,要么记录得足够详细可以手动回滚。
对于自动投递模块,意思是代理邮箱收件箱。每份申请都通过一个唯一的邮箱地址发送。如果出了问题,候选人可以看到发送了什么内容、发给了谁、什么时候发的。他们可以手动跟进。系统记录了提交的每个字段。
对于数据库操作,回滚意味着事务。如果 Agent 要写入数据库,应该在事务内进行,如果下一步验证失败就回滚。
// 用事务包装 Agent 的写操作
// 如果任何步骤失败,全部回滚
async function executeAgentActionWithRollback(action: AgentAction): Promise<void> { const transaction = await db.$transaction(async (tx) => { // 步骤 1: 执行操作 const result = await tx[action.table].create({ data: action.data }); // 步骤 2: 用单独进程验证结果 const validation = await validateResult(result); if (!validation.passed) { // 抛出异常触发回滚 throw new Error(`Validation failed: ${validation.reason}`); } return result; }); // 只有验证通过才会提交 return transaction;
} 事务边界划出了一条清晰的界限。如果 Agent 产生了幻觉,数据库保持干净。你用修正后的 prompt 重试,而不是用数据清理脚本。
我现在做每个 AI Agent 管道都用的模式:
隔离层:Agent 从不直接接触生产数据。它通过受限 API 读取,通过验证中间件写入。
逐操作审批:每个写操作都需要明确的人工确认。读取操作自动审批但记录日志。
幂等操作:每个操作重试时产生相同结果。用 upsert,不用 insert。状态变更前先检查状态。
事务边界:所有写操作都在事务内进行。验证门控放在写入和提交之间。
完整审计日志:每个操作都记录 Agent ID、时间戳、输入、输出、审批状态。你可以重放任何会话。
终止开关:一个 API 调用停止所有 Agent 活动。不是限速,是硬停止。
这些模式适用于 LLM 评分管道、浏览器自动化 Agent 还是 RAG 系统。具体实现会变,原则不变。
如果你的团队正在评估 AI Agent 集成,想知道怎么快速上线又不搞出大新闻,可以聊聊。什么管用、什么踩坑,交流一下经验。