企业级 Agent 和个人玩具 Agent 的分水岭不在模型多强,而在敢不敢让它碰真实系统。企业落地必须解决五件事:老系统怎么接(集成层)、谁能让它做什么(权限域)、高危操作谁拍板(人工审批)、出了事怎么查(审计脱敏)、烧钱失控怎么办(成本护栏)。下面逐层给可运行代码。
企业系统往往API不统一:ERP是SOAP、CRM是REST、工单系统只有数据库视图。不要在Agent里直接调各系统,先做一层工具网关适配器,统一输入输出契约。
# gateway.py
import httpx
from abc import ABC, abstractmethod
class ToolAdapter(ABC):
@abstractmethod
def invoke(self, tenant_id: str, **kwargs) -> dict: ...
class CrmAdapter(ToolAdapter):
def invoke(self, tenant_id, customer_id, **kw):
r = httpx.get(f"https://crm.internal/api/customer/{customer_id}",
headers={"X-Tenant": tenant_id}, timeout=8)
r.raise_for_status()
return {"name": r.json()["name"], "level": r.json()["level"]}
class TicketAdapter(ToolAdapter):
def invoke(self, tenant_id, title, content, **kw):
# 老系统只有DB视图,走内部服务封装
r = httpx.post("http://ticket-svc/internal/create",
json={"tenant": tenant_id, "title": title, "content": content},
timeout=8)
return {"ticket_id": r.json()["id"], "status": "created"}
REGISTRY = {"get_customer": CrmAdapter(), "create_ticket": TicketAdapter()}工程约束:适配器必须透传tenant_id并带超时;输出统一为dict,Agent不感知底层是REST还是SOAP,换系统只换适配器。
企业最怕Agent越权:A租户的Agent查到B租户数据,普通员工Agent触发财务操作。权限校验必须放在工具网关入口,而不是靠prompt约束。
# authz.py
from functools import wraps
ROLE_PERMS = {
"support": {"get_customer", "create_ticket"},
"finance": {"get_customer", "refund"},
"admin": {"*"},
}
def authorize(tool_name):
def deco(fn):
@wraps(fn)
def wrapper(ctx, **kwargs):
role = ctx["role"]; tenant = ctx["tenant_id"]
perms = ROLE_PERMS.get(role, set())
if "*" not in perms and tool_name not in perms:
raise PermissionError(f"角色{role}无权调用{tool_name}")
# 数据域:强制注入租户过滤,模型无法绕过
kwargs["tenant_id"] = tenant
result = fn(ctx, **kwargs)
# 返回后做数据域二次校验(防越权读)
assert result.get("tenant_id", tenant) == tenant, "跨租户数据泄漏"
return result
return wrapper
return deco工程约束:tenant_id由服务端注入,绝不从模型参数里取;返回结果再校验归属,防止上游接口本身越权。权限矩阵要配置化,随组织架构变更而更新。
退款、删数据、发通知这类操作,Agent不能直接执行。用"中断-持久化-审批-恢复"模式,而不是同步阻塞等人工。
# approval.py
import json, uuid
def execute_with_approval(ctx, tool_name, args, db):
if tool_name in {"refund", "delete_user", "send_bulk_notice"}:
approval_id = str(uuid.uuid4())
db.approvals.insert_one({
"approval_id": approval_id, "tenant": ctx["tenant_id"],
"tool": tool_name, "args": args, "status": "PENDING",
"agent_state": ctx["serialized_state"], # 关键:保存Agent上下文
})
return {"status": "PENDING_APPROVAL", "approval_id": approval_id}
return REGISTRY[tool_name].invoke(**args) # 低危直接执行
def resume_after_approval(approval_id, approved, db):
rec = db.approvals.find_one({"approval_id": approval_id})
if rec["status"] != "PENDING": return
if not approved:
db.approvals.update_one({"approval_id": approval_id}, {"$set": {"status": "REJECTED"}})
return
REGISTRY[rec["tool"]].invoke(**rec["args"]) # 审批通过才执行
db.approvals.update_one({"approval_id": approval_id}, {"$set": {"status": "APPROVED"}})
# Agent从持久化状态恢复,继续后续步骤工程约束:审批期间Agent状态必须持久化,否则进程重启任务丢失;审批通过后执行前要二次校验幂等,防重复点击。
# audit.py
import re, hashlib
PII = [r"\d{17}[\dXx]", r"1[3-9]\d{9}", r"[\w.]+@[\w.]+"]
def mask(text: str) -> str:
for p in PII:
text = re.sub(p, lambda m: hashlib.sha256(m.group().encode()).hexdigest()[:8], text)
return text
def audit_log(span: dict):
# 每步落:租户、角色、工具、参数摘要(脱敏)、结果状态、耗时、token
span["args"] = mask(json.dumps(span.get("args", {}), ensure_ascii=False))
span["result_summary"] = mask(str(span.get("result"))[:200])
db.audit.insert_one(span)工程约束:审计日志要防篡改(追加写、定期归档到对象存储);脱敏在日志出口做,不能只在展示层做;原始敏感数据设保留期限,到期自动清理。
# cost.py
BUDGET = {"tenant_daily": 50.0} # 美元
PRICE = {"gpt-4o": 0.005, "gpt-4o-mini": 0.0005}
def route_model(tenant_id, task_complexity):
spent = db.usage.aggregate_today(tenant_id)
if spent > BUDGET["tenant_daily"] * 0.8: # 超80%降级
return "gpt-4o-mini"
return "gpt-4o" if task_complexity == "high" else "gpt-4o-mini"
def check_circuit(tenant_id):
fails = db.metrics.recent_fail_rate(tenant_id, window="5m")
if fails > 0.3:
raise RuntimeError("熔断:近期失败率过高,转人工")工程约束:预算按租户+日维度控制,超限降级而非直接拒绝;熔断要联动人工兜底队列,不能静默失败。
# eval_enterprise.py
CASES = [{"goal":"查客户C001等级","expect_tool":"get_customer","expect_kw":"VIP"}]
def evaluate(agent_fn, tenant):
hit = tool_ok = 0
for c in CASES:
ans, trace = agent_fn(c["goal"], tenant=tenant)
hit += c["expect_kw"] in ans
tool_ok += any(t.get("tool")==c["expect_tool"] for t in trace)
return {"answer_hit": hit/len(CASES), "tool_acc": tool_ok/len(CASES)}企业评测还要加越权测试集(故意诱导跨租户查询,必须全部拒绝)和审批绕过测试集(高危操作必须返回PENDING)。上线先跑影子模式:Agent只给建议不执行,与人工结果对比,达标再逐步放量。
总结:AI Agent 企业应用的专业度不在prompt,而在工具网关统一集成、权限域服务端强制注入、高危操作异步审批、全链路审计脱敏、预算熔断降级、越权与审批评测、影子灰度这七件事。能给别人讲清楚"为什么tenant_id绝不能从模型参数取""审批期间Agent状态为什么要持久化",你就抓住了企业落地的命门。觉得有用点赞收藏,需要完整工程目录留言。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。