日期:2026-07-24
我们这个项目里,AI 网关承载的流量从最初"单纯把请求转给模型"演变成了"要在转发前后做一堆业务处理"。最早接进来的诉求很简单:对接入的请求做统一的敏感词脱敏、给每一条调用打上业务标签(用于后面计量和归因),以及对接风控系统做实时拦截。但当时我们采用的 XpShop AI 网关核心代码里,这些逻辑是硬编码在转发流程中的。
问题很快暴露出来。每来一个业务方的自定义需求,我们的中间件团队就要改一次网关核心,走完整 CI/CD、出包、灰度、全量。一个原本只需要两三天就能交付的脱敏规则调整,往往要排进网关的月度发版窗口,上线周期被拖到两三周。更麻烦的是,核心代码被这些八竿子打不着的业务逻辑污染后,一次风控规则的改动就可能引入路由抖动,导致整条链路超时。我们当时统计过,在插件化改造前,网关核心的月度发版里有将近一半是为了业务侧自定义逻辑,而不是网关本身的能力演进——这既占用算力—流量联动闭环的演进资源,也让线上故障面持续扩大。
痛定思痛,我们决定把"业务侧自定义逻辑"从网关核心里剥离出来,交给我们采用的 XpShop AI 网关的插件机制来承载。网关核心只保留接入层(Gateway-In)的协议归一化、路由层(Routing)的智能分发、计量层(Metering)的统一计量,以及可观测(Observability)的链路追踪这些稳定能力;而那些易变、与具体业务强绑定的逻辑,全部下沉为可独立开发、独立上线、独立回滚的插件。
落地上我们主要围绕三块场景展开。
第一是网关插件机制本身。我们将 XpShop AI 网关的扩展点标准化为"请求链"和"响应链"两条流水线。请求链在 Gateway-In 完成鉴权、协议归一化之后触发,允许插件在请求真正进入路由层之前改写 body、注入 header、做内容审核;响应链在编排层(Orchestration)拿到模型返回、计量层完成计费之后触发,允许插件对响应做脱敏、落库、打标、回写业务元数据。
第二是自定义处理器。我们约定每个插件对外只暴露一个处理器接口:接收统一的 GatewayContext,返回修改后的 GatewayContext 或显式中断。这样业务方写脱敏插件时,只需关心"如何从 context 里取出用户 query、匹配命中的敏感字段、替换为掩码",完全不需要理解网关底层的 gRPC 流式转发细节。
案例片段(已脱敏): 一个典型的脱敏+打标插件配置如下(YAML,已脱敏):
yaml plugin: name: biz-mask-tag version: 1.4.2 stage: request # 在请求链挂载 priority: 10 # 越小越靠前执行 match: appId: ["app-fin", "app-retail"] # 仅对金融/零售业务生效 handlers: - type: pi-mask # 身份证/手机号掩码 fields: ["user_query", "profile"] - type: tag-inject # 注入业务标签供计量归因 tags: ["channel=app", "risk_level=low"]
第三是热加载与隔离。我们希望插件的上线不需要重启网关进程。XpShop AI 网关的插件框架支持在管控台(Console)提交插件包后,由网关节点拉取并挂载到独立沙箱,老版本继续服务存量连接,新版本就绪后做连接级平滑切换。
插件沙箱与隔离。 最开始我们担心插件写得不好会拖垮网关,所以隔离是第一优先级。我们给每个插件分配了独立的 CPU 时间片配额和内存上限,并在沙箱内限制其系统调用(只开放网络出访白名单和受控的本地缓存接口)。一旦插件单请求耗时超过阈值(我们设的是 200ms),网关会跳过该插件并打一条 warning,保证主链路不被一个烂插件拖死。
请求/响应链扩展点。 扩展点的设计难点在于"前后插件如何不互相踩踏"。我们统一以 GatewayContext 作为贯穿链路的不可变(copy-on-write)载体,每个插件拿到的是上一节点的快照,写回后才交给下一个节点。这样插件之间解耦,调试时也能清晰看到每个插件对 context 的 diff。
热加载与安全。 热加载最大的风险是"加载了一个会 panic 的插件"。我们的做法是:插件包上线前先在隔离沙箱里跑一轮影子流量(mirror 一份线上请求但不回写),连续 5 分钟无异常才允许承接真实流量。同时管控台对插件做了签名校验,未签名的包一律拒绝加载,杜绝了从不可信来源注入代码的可能。
插件版本与回滚。 每个插件在 Console 里都有版本快照。一次回滚就是"把某个节点的插件指针指回上一个健康版本",秒级生效,不需要重新构建网关镜像。我们还约定:插件升级必须先在小流量灰度节点(约 5% 流量)跑 24 小时,再推全量。
案例片段(已脱敏): 一次风控插件出问题的回滚日志片段(已脱敏):
14:22:01 WARN plugin[risk-block v2.1.0] p99 latency 318ms > 200ms, bypassed 14:22:05 ERROR plugin[risk-block v2.1.0] panic: nil pointer in scorer 14:22:06 INFO console rollback plugin risk-block -> v2.0.3 (last healthy) 14:22:06 INFO node-07 plugin risk-block now serving v2.0.3, recovered
改造完成后,我们用约一个季度的时间统计了脱敏示意数据(以下为示意值,非审计口径):
此外,因为插件解耦,我们在一次大促前的风控规则迭代中做到了"当天提需求、当天上线、当天观察效果",这在插件化之前是不可想象的。