AI Agent开始进入采购执行层后,企业要防的已经不只是模型答错。
它可能读取库存、寻找供应商、生成订单,也可能调用OA、ERP和付款接口。金杜律师事务所在《如何在AI智能体的部署中针对高风险动作设置审批节点》中指出,一旦智能体拥有写入、发送、删除、付款、部署、导出或提交能力,错误动作就可能带来财产损失、数据泄露、合同责任和监管责任。治理重点因此需要从内容审查转向动作控制。
安全内参对OpenClaw的报道提供了一个直观参照:该项目发布近4个月后,GitHub星标数超过24.8万。Agent正在从整理纪要、生成文本的辅助工具,进入能够调取数据、触发流程并跨系统连续执行任务的业务层。
采购是最容易暴露权限问题的场景之一。Agent接到一句“库存不够就补货”,后面可能连续完成查库存、选供应商、填订单和提交审批。只要其中一个接口默认信任Agent,原本的业务控制就可能被绕开。
金额合规,不能只检查单次请求
常见的网关规则是:订单金额超过企业设定的阈值,就转人工审批。这只能拦住直接超额的订单。
如果Agent把一笔采购拆成多次请求,每一笔都低于阈值,单笔校验仍会放行。网关需要同时记录会话、任务或采购需求维度的累计金额,并检查短时间内是否出现同类商品、同一供应商和相近用途的连续订单。
下面是一段示意代码。代码中的5000元、1500元和600秒沿用示例参数,正式上线时应替换为企业采购制度中的阈值,并明确累计范围究竟按会话、采购任务还是成本中心计算。
func CheckSplitOrder(req *http.Request) (bool, string) {
sessionID := req.Header.Get("X-Agent-Session")
amount := extractAmount(req.Body)
key := "agent:session:" + sessionID + ":amount"
cumulative := redis.Get(key)
if amount < 1500 && cumulative+amount > 5000 {
return false, "累计金额超限,疑似拆单"
}
if amount > 5000 {
return false, "单笔金额超限,需人工复核"
}
redis.IncrBy(key, amount)
redis.Expire(key, 600)
return true, ""
}
这里还有一个容易忽略的问题:X-Agent-Session不能由Agent随意填写。会话标识应由受信任的编排服务或网关签发,否则Agent可以不断更换Session ID,让累计金额重新归零。
金额规则也不宜只返回“允许”或“拒绝”。订单ID、Agent身份、采购任务、累计金额、命中的规则和请求时间都应进入审计日志,方便复核同一任务下的连续动作。
供应商名称不能成为授权凭证
Agent可以从聊天记录、邮件或检索结果里提取公司名称,但自然语言里出现过的供应商,并不等于采购系统已经准入的供应商。
网关应以供应商主数据中的唯一ID作为授权依据,并核对该ID绑定的注册名称、账户状态和可采购范围。模糊匹配可以用于发现错别字或疑似关联名称,不能据此自动放行。
from fuzzywuzzy import fuzz
WHITELIST = {
"SUP-1001": "华东电子科技有限公司",
"SUP-1002": "迅达供应链有限公司"
}
SIMILARITY_THRESHOLD = 85
def check_supplier(req):
supplier_id = req.json.get("supplier_id")
supplier_name = req.json.get("supplier_name")
if supplier_id not in WHITELIST:
return block("供应商不在白名单")
registered_name = WHITELIST[supplier_id]
if supplier_name != registered_name:
score = fuzz.ratio(supplier_name or "", registered_name)
return block(
f"供应商名称与主数据不一致,相似度为 {score},需人工核验"
)
return allow()
这段配置里,相似度85只是告警参数,不是授权门槛。即使两个名称高度相似,只要没有预先登记的别名映射,也不应让Agent自行判断它们属于同一主体。
更稳妥的做法是让Agent只提交采购需求和候选条件,供应商ID由采购主数据服务返回。这样可以避免模型从非结构化对话中抽取一个公司名,再直接把它写进下单接口。
“已审批”只能由审批系统写入
第三类风险来自请求体中的审批字段,例如:
{
"approval_status": "approved",
"reviewed_by": "manager",
"auto_approved": true
}
如果OA或ERP看到这些字段就默认放行,Agent实际上获得了修改审批结果的能力。无论提示词里写了多少遍“不得绕过审批”,都无法替代接口层校验。
审批结果应由审批系统通过签名回调写入。Agent可以发起审批、查询状态,但不能声明自己已经通过审批。
function checkApprovalBypass(req) {
const body = req.body;
const hasApprovalFlag =
body.approval_status === "approved" ||
body.reviewed_by !== undefined ||
body.auto_approved === true;
const approvalToken = req.headers["x-approval-token"];
const tokenValid = approvalToken &&
verifyHMAC(approvalToken, process.env.APPROVAL_SECRET);
if (hasApprovalFlag && !tokenValid) {
return {
block: true,
reason: "请求包含审批标记,但缺少有效的审批系统签名"
};
}
return { block: false };
}
实际部署时,签名还应绑定订单ID、金额、供应商和有效期。否则,一枚合法Token可能被复制到另一笔订单上重复使用。网关也要拒绝Agent直接写入approval_status、reviewed_by等保留字段,减少上下游系统误信请求体的可能。
为什么拦截点要放在工具调用前
在Prompt中加入“遵守采购政策”仍有价值,但它更适合约束Agent如何规划任务,不能承担最终授权职责。上下文变化、外部内容注入或工具参数生成错误,都可能让提示词约束失效。
API网关位于Agent和业务系统之间,能在请求真正进入ERP、OA或付款系统前检查参数。金额累计、供应商准入和审批签名都属于确定性规则,适合在这一层执行。被拦截的请求还可以统一记录,避免Agent日志与业务系统日志彼此割裂。
IDC在关于AI Agent与零信任网络访问的分析中提出,访问治理对象需要扩展到“人+设备+AI Agent”。这意味着每个采购Agent都应使用独立的Service Account,权限限定到具体接口、动作和数据范围,不能继承管理员账号,也不应与其他Agent共用长期凭证。
网关规则之外,还要补上几项基础控制:
- 将查询库存、创建草稿、提交订单、修改供应商和触发付款拆成不同权限;
- 对付款、删除、导出和正式提交等高风险动作设置人工审批节点;
- 给Agent签发独立身份,记录它调用了哪个接口、使用了什么参数;
- 把采购主数据与普通对话记忆隔离,避免聊天内容直接覆盖供应商和审批字段;
- 对拦截规则进行回放测试,确认拆单、字段改写和凭证复用都无法绕过。
钛媒体援引普华永道2025年5月一项涵盖1000名美国商业领袖的调查称,79%的受访组织表示已经在某种程度上采用AI Agent。随着Agent获得更多操作权限,企业不能再把它只当成一个会聊天的账号。
采购Agent可以继续自动比价、生成订单和跟踪物流,但金额是否超限、供应商是否准入、审批是否真实,必须由Agent无法自行修改的规则决定。网关的作用,就是在请求抵达业务系统前守住这条边界。
参考资料: