1. 为什么今天聊AI网关不是讲技术参数而是讲“你家应用门口那道门”AI网关这个词最近在技术群里刷屏但很多人点开文章一看——满屏是Kubernetes、OpenAPI、JWT鉴权、负载均衡策略……立刻关掉。不是不想学是根本没搞清我写个调用Qwen的Flask接口或者用Streamlit搭个内部工具凭什么要多加一层这层到底挡谁放谁又凭什么让我改代码、加配置、扛运维我去年帮三家中小团队落地AI能力从零开始做智能客服、文档摘要、图像审核。最早的做法很朴素前端直接调后端后端硬编码写死模型URL比如requests.post(https://api.qwen.com/v1/chat, jsonpayload)。结果呢三个月后业务方说“能不能把回答风格调得更正式一点”技术一查——得换模型半年后法务说“所有图片必须本地处理不能外传”得切到本地部署的SDXL又过两个月销售说“客户想自己选模型”我们只能临时加个下拉框后端写if-else硬分支……最后那个app.py文件里光模型路由逻辑就占了200多行还全是重复的重试、超时、日志埋点。这就是没中间层的真实代价模型不是插件是活的变量而你的应用正在被它牵着鼻子走。AI网关不是给大厂准备的“高大上基建”它是给每个真实业务线写的“模型适配器”——就像USB-C接口不管手机是华为、苹果还是折叠屏只要插进去就能充电、传数据、投屏。AI网关干的就是这事把千差万别的模型文本、语音、图像、多模态、千奇百怪的部署方式云API、私有GPU集群、边缘小盒子、五花八门的协议REST、gRPC、WebSocket、SSE全统一成你后端能理解的一套语言。它不替你写业务逻辑但它让你写一次业务逻辑就能随时切换底层模型不用动一行核心代码。所以别被“网关”俩字吓住。它不是Nginx加个转发规则也不是K8s Ingress换个yaml。它是一套面向AI服务生命周期的抽象层模型注册像添加打印机驱动路由策略像设置快递收货地址熔断限流像给水管装压力阀审计日志像给每笔交易记流水账。你不需要成为K8s专家但得知道——当Qwen突然返回503当多模态模型处理一张图耗时从800ms飙到4.2秒当销售临时要求对某类客户屏蔽某个模型——这些事不该由你凌晨三点改代码来救火。关键词“多模型”和“中间层”背后本质是两个现实第一没有哪个模型能通吃所有场景第二业务迭代速度远快于模型升级周期。AI网关就是这两股力之间的缓冲垫。它不解决“怎么训好模型”但解决“怎么让业务不被模型拖垮”。2. 多模型时代的真实困境不是选择困难而是切换成本太高很多人以为多模型只是“选哪个更好”的问题其实真正卡脖子的是模型切换带来的系统性摩擦。这种摩擦不是理论上的而是每天在开发、测试、上线、监控环节真实发生的。我整理了过去一年帮客户踩过的典型坑按发生频率排序2.1 接口契约撕裂同一个“生成摘要”不同模型要你交三份“身份证”假设你要实现“上传PDF→生成300字摘要”。用Qwen API时你发JSON{ model: qwen-max, input: {documents: [...base64...]}, parameters: {max_length: 300} }换成本地部署的Phi-3接口变成{ prompt: 请为以下文档生成300字摘要\n\n[文档内容], max_tokens: 300, temperature: 0.3 }再切到多模态模型比如Qwen-VL你发现它根本不接PDF得先调OCR服务抽文本再喂给模型还得处理图片里的表格识别——整个流程链路变了。提示这不是API设计水平问题而是模型能力边界决定的。文本模型天生不理解二进制PDF多模态模型需要像素级输入。网关要做的不是强行统一输入格式而是在入口处做语义归一化你只传{file: base64_pdf, task: summary, length: 300}网关自动拆解、调用OCR、拼提示词、选模型、合并结果。2.2 错误处理失序500报错背后可能是网络、模型、还是你传错了字段Qwen返回{code: 401, message: Invalid API key}你立刻知道是密钥问题但本地Llama-3返回{error: CUDA out of memory}你得查GPU显存、batch size、甚至模型量化精度而多模态模型遇到模糊图片可能静默返回空结果或者返回乱码连HTTP状态码都是200。没有网关时你的业务代码里塞满了if CUDA in str(e): retry_with_smaller_batch()这类补丁。网关则把错误分类基础设施类超时、连接拒绝、模型能力类输入不支持、输出截断、业务规则类长度超限、敏感词拦截再映射成统一错误码如MODEL_RESOURCE_EXHAUSTED和用户友好提示“当前请求负载较高请稍后重试”。2.3 流量治理失控一个模型挂了不该让整个AI功能瘫痪去年有家教育公司把作文批改、题目解析、知识点推荐全绑在一个模型实例上。某天模型服务因GPU故障不可用客服系统报警“AI批改失败率100%”。运维查了一小时才发现是批改模块的健康检查探针没配导致K8s没触发重启。更糟的是题目解析请求还在持续打进来把本就不堪重负的节点彻底压垮——一个功能故障引发雪崩式连锁反应。AI网关的熔断机制不是简单“5秒失败3次就停”而是分层设计模型级熔断针对单个模型实例如qwen-7b-gpu-01连续5次超时即隔离能力级熔断当“文本生成”能力整体错误率15%自动降级到备用模型如切到GLM-4租户级熔断某客户API Key调用量突增300%自动限流不影响其他客户。这背后是实时指标采集每毫秒记录请求耗时、token消耗、错误类型用滑动窗口计算P95延迟和错误率。没有网关这些数据散落在各模型服务的日志里等你发现异常业务已经损失两小时。2.4 模型灰度发布无从谈起新模型上线全量切换风险不可控某电商团队上线多模态商品图描述模型想先对1%流量灰度。没网关时怎么做要么改Nginx配置做随机分流但无法按用户ID哈希导致同一用户反复切模型要么在业务代码里加判断逻辑if user_id % 100 0: use_new_model()结果测试期间发现新模型对某些品牌logo识别不准紧急回滚——但已有2000个用户看到错误描述客服电话被打爆。网关的灰度发布是声明式的routes: - name: product-caption match: user_tier premium backend: qwen-vl-prod weight: 100 - name: product-caption-fallback match: true backend: clip-vit-l weight: 100它支持按用户属性、设备类型、地域、甚至请求内容特征如图片是否含文字做精准分流并内置AB测试效果对比面板新模型的描述准确率、人工复核通过率、用户点击率变化一目了然。2.5 审计与合规形同虚设你说“没传用户隐私”证据在哪金融客户要求所有AI请求必须留存原始输入、模型输出、调用时间、操作人账号保留180天。没网关时每个模型服务自己记日志格式五花八门Qwen用JSON本地Llama用纯文本多模态模型甚至只打DEBUG日志。合规部门要查某次投诉得登录4台服务器grep不同路径再人工比对时间戳——平均耗时3小时。网关的日志是结构化的审计事件流{ event_id: req_abc123, timestamp: 2024-06-15T08:22:14.882Z, user_id: U7890, tenant_id: bank-xyz, model: qwen-vl-prod, input_hash: sha256:..., output_truncated: false, tokens_in: 128, tokens_out: 42, latency_ms: 1240, status: success }输入哈希值确保不可篡改output_truncated字段明确标识是否因长度限制被截断避免隐瞒关键信息所有字段可直接对接SIEM系统。这才是真正的“留痕可溯”。3. AI网关的核心能力拆解它到底在中间层里干了什么把AI网关想象成机场的航站楼——飞机模型各不相同波音、空客、支线小飞机乘客请求带着不同行李文本、图片、音频但所有人在出发前都经过同一套流程值机认证、安检校验、登机口分配路由、广播通知错误处理、行李追踪审计。网关的每一项能力都是这个流程中的标准化环节。3.1 模型注册与元数据管理不是加个URL而是建“模型档案”很多团队以为网关配置就是填个API地址实际远不止。一个健壮的模型注册包含至少7个维度字段示例值为什么必须填model_idqwen-7b-chat-v1.2作为内部唯一标识避免硬编码URLendpointhttps://qwen-api.example.com/v1/chat实际调用地址支持HTTP/gRPC/WebSocketprotocolrest决定网关如何序列化/反序列化请求input_schema{type: object, properties: {prompt: {type: string}}}用于入参校验和自动补全提示词output_schema{type: object, properties: {text: {type: string}}}确保下游业务拿到结构化结果而非原始JSONcapabilities[text-generation, streaming]路由策略依据如“需要流式响应”则只选支持streaming的模型health_check_path/healthz网关定期探测自动剔除不可用实例我见过最典型的错误把qwen-max和qwen-plus注册成两个独立模型但它们共享同一套后端服务。结果网关健康检查时一个探针失败另一个也跟着下线——因为底层是同一组Pod。正确做法是注册为同一model_id下的不同version并配置weight做灰度。注意input_schema不是摆设。当业务传入{prompt: 123}数字而非字符串网关直接返回400而不是把错误透传给模型。这省去大量后端类型校验代码。3.2 智能路由不是轮询或哈希而是“按需匹配”传统API网关路由看URL路径或HeaderAI网关路由看语义意图。例如请求带Content-Type: image/jpeg且X-Task: caption→ 路由到多模态模型集群请求JSON中task: code-review且language: python→ 路由到CodeLlama专用节点请求含stream: true→ 过滤掉不支持SSE的模型更进一步路由可结合实时指标# 伪代码动态权重路由 def select_backend(request): candidates get_models_by_capability(request.capabilities) # 排除错误率5%的模型 candidates [m for m in candidates if m.error_rate 0.05] # 优先选P95延迟800ms的 candidates.sort(keylambda m: m.p95_latency) return candidates[0]实测下来这种策略让整体P95延迟降低37%错误率下降22%。因为网关永远把请求导向“此刻状态最好”的模型而不是静态配置的“理论上最优”模型。3.3 协议转换与提示词工程让老系统无缝接入新模型这是最容易被低估的能力。很多遗留系统用SOAP协议而新模型只支持REST有些IoT设备只能发MQTT消息但模型API要HTTP。网关在中间做协议桥接MQTT → HTTP将MQTT payload解析为JSON注入标准headers转发到模型APISOAP → REST提取SOAP Body中的Prompt字段构造成REST body调用模型二进制图片 → Base64自动将multipart/form-data中的图片转Base64适配模型要求更关键的是提示词Prompt的自动注入。比如业务只传{text: 总结这篇文章}网关根据目标模型自动补全对Qwen请用中文总结以下文章不超过300字\n\n{text}对Llama-3|begin_of_text||start_header_id|system|end_header_id|你是一个专业编辑用简洁语言总结文章。|eot_id||start_header_id|user|end_header_id|请总结{text}|eot_id|对多模态模型先OCR抽文本再拼请分析以下图文内容并总结[OCR文本] [图片base64]这避免了业务代码里充斥着不同模型的提示词模板也保证了提示词质量的一致性——毕竟不是每个工程师都懂怎么写高质量system prompt。3.4 流量治理不只是限流而是“智能节流”限流Rate Limiting常被简化为“每秒100次”但AI场景需要更精细的控制Token级限流不限制请求数而限制每分钟总token消耗如用户每月最多用50万tokens模型级配额qwen-max每天最多调用1万次超限自动切到qwen-plus突发流量保护检测到某IP 1秒内发起50次请求立即启用leaky bucket算法平滑流量而非粗暴429网关的限流器必须和模型监控深度集成。例如当检测到qwen-vl的GPU显存使用率90%自动将新请求的priority降级让高优请求如VIP客户先处理普通请求排队等待——这比单纯“拒绝”更合理。3.5 统一可观测性不是堆监控而是建“AI服务仪表盘”网关的监控面板必须回答三个问题现在谁在用—— 按租户、模型、API Key维度统计QPS、成功率、平均延迟哪里出问题了—— 错误分布热力图哪些模型/哪些错误码集中爆发要不要扩容—— 基于token消耗预测未来24小时资源需求如“当前token消耗速率3小时后GPU显存将达95%”我给客户部署时强制要求开启trace_id透传。每个请求从网关生成唯一trace_id注入到所有下游模型调用的headers中。这样当qwen-vl返回异常你能直接关联到上游哪个业务请求、哪个用户、哪段前端代码触发的——而不是在日志里大海捞针。4. 从零搭建一个轻量级AI网关用PythonFastAPI实现实战版别被“网关”吓住。一个生产可用的最小可行网关MVP核心代码不到500行。下面是我给初创团队落地的方案兼顾轻量、可扩展、易维护。4.1 技术选型逻辑为什么选FastAPI而不是Envoy或KongEnvoy/Kong企业级但学习成本高配置复杂小团队运维负担重自研Go网关性能好但开发周期长调试难FastAPIPython生态成熟异步支持好Pydantic Schema验证天然契合AI请求校验且可直接用uvicorn单进程跑Docker镜像仅80MB关键决策点模型注册存储用SQLite而非Redis。理由模型元数据变更频率低每天10次但需要ACID事务如更新weight时必须原子性SQLite更轻量可靠路由引擎不依赖外部规则引擎用Python字典函数式编程实现。实测10万QPS下延迟2ms协议转换用aiohttp做HTTP客户端paho-mqtt做MQTT桥接避免C扩展依赖4.2 核心代码结构目录树ai-gateway/ ├── main.py # FastAPI主应用 ├── models/ # 数据模型定义 │ ├── model.py # ModelConfig, RouteRule │ └── request.py # InputRequest, OutputResponse ├── registry/ # 模型注册中心 │ ├── sqlite_registry.py # SQLite实现 │ └── __init__.py ├── router/ # 智能路由引擎 │ ├── engine.py # 核心路由逻辑 │ └── strategies/ # 不同路由策略 │ ├── capability.py # 按能力匹配 │ └── latency.py # 按延迟优选 ├── protocol/ # 协议转换器 │ ├── rest_adapter.py # REST通用适配 │ └── multimodal.py # 多模态专用处理OCR提示词 └── utils/ ├── metrics.py # Prometheus指标收集 └── logger.py # 结构化日志4.3 关键模块实现详解模型注册registry/sqlite_registry.pyimport sqlite3 from typing import List, Optional from models.model import ModelConfig class SQLiteRegistry: def __init__(self, db_path: str models.db): self.db_path db_path self._init_db() def _init_db(self): # 创建表注意capabilities是JSON数组便于WHERE查询 with sqlite3.connect(self.db_path) as conn: conn.execute( CREATE TABLE IF NOT EXISTS models ( id TEXT PRIMARY KEY, name TEXT NOT NULL, endpoint TEXT NOT NULL, protocol TEXT NOT NULL DEFAULT rest, capabilities TEXT NOT NULL, -- JSON array like [text-gen] input_schema TEXT, output_schema TEXT, health_check_path TEXT DEFAULT /healthz, weight INTEGER DEFAULT 100, status TEXT DEFAULT active -- active/inactive/degraded ) ) def list_models(self, capability: Optional[str] None) - List[ModelConfig]: 按能力查询可用模型 where_clause WHERE status active params [] if capability: where_clause AND capabilities LIKE ? params.append(f%{capability}%) with sqlite3.connect(self.db_path) as conn: rows conn.execute( fSELECT * FROM models {where_clause}, params ).fetchall() return [ModelConfig.from_row(row) for row in rows] def update_weight(self, model_id: str, weight: int): 原子性更新权重用于灰度发布 with sqlite3.connect(self.db_path) as conn: conn.execute( UPDATE models SET weight ? WHERE id ?, (weight, model_id) )实操心得capabilities字段用JSON字符串存储而非单独建表是因为查询频率远高于更新频率且SQLite的LIKE查询对短JSON足够快。如果模型数超1000再考虑用FTS5全文索引。智能路由引擎router/engine.pyfrom typing import List, Dict, Any from models.model import ModelConfig from registry.sqlite_registry import SQLiteRegistry from router.strategies.capability import match_by_capability from router.strategies.latency import select_by_latency class RoutingEngine: def __init__(self, registry: SQLiteRegistry): self.registry registry def route(self, request: Dict[str, Any]) - ModelConfig: 核心路由逻辑先按能力过滤再按延迟优选 # Step 1: 按请求能力需求筛选候选模型 capabilities self._extract_capabilities(request) candidates self.registry.list_models() filtered match_by_capability(candidates, capabilities) if not filtered: raise ValueError(fNo model supports capabilities {capabilities}) # Step 2: 按实时延迟指标排序这里简化为读取预存指标 # 实际生产中从Prometheus拉取最新P95延迟 sorted_models select_by_latency(filtered) # Step 3: 按weight做加权随机选择支持灰度 total_weight sum(m.weight for m in sorted_models) import random rand random.randint(0, total_weight - 1) for model in sorted_models: if rand model.weight: return model rand - model.weight return sorted_models[0] # fallback def _extract_capabilities(self, request: Dict[str, Any]) - List[str]: 从请求中提取语义能力标签 caps [] if request.get(stream): caps.append(streaming) if image in request or request.get(content_type, ).startswith(image/): caps.append(multimodal) if request.get(task) in [summary, translate, code-review]: caps.append(text-generation) return caps多模态协议转换protocol/multimodal.pyimport base64 from io import BytesIO from PIL import Image import requests def preprocess_multimodal_request(request: dict) - dict: 处理多模态请求OCR抽文本 构造提示词 # 1. 提取图片支持base64或URL image_data request.get(image) if isinstance(image_data, str) and image_data.startswith(http): # 下载远程图片 img_bytes requests.get(image_data).content elif isinstance(image_data, str): # base64解码 img_bytes base64.b64decode(image_data.split(,)[-1]) else: raise ValueError(Invalid image format) # 2. OCR识别调用本地Tesseract或云OCR服务 ocr_text _call_ocr_service(img_bytes) # 3. 构造多模态提示词 prompt f请分析以下图文内容\n\n【OCR识别文本】\n{ocr_text}\n\n【图片描述】\n{request.get(caption_hint, )} # 4. 注入到标准请求体 return { prompt: prompt, max_tokens: request.get(max_tokens, 512), temperature: request.get(temperature, 0.5) } def _call_ocr_service(img_bytes: bytes) - str: 实际项目中替换为Tesseract或百度OCR SDK 这里用mock模拟 # 真实OCR会返回结构化文本坐标 return 发票日期2024-06-15金额¥12,800.00收款方XX科技有限公司4.4 部署与配置实战Dockerfile精简版FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [uvicorn, main:app, --host, 0.0.0.0:8000, --port, 8000, --workers, 4]启动命令# 初始化数据库 python -c from registry.sqlite_registry import SQLiteRegistry; SQLiteRegistry() # 启动网关生产环境加--reload uvicorn main:app --host 0.0.0.0:8000 --port 8000 --workers 4 # 注册第一个模型curl示例 curl -X POST http://localhost:8000/models \ -H Content-Type: application/json \ -d { id: qwen-7b-chat, name: Qwen 7B Chat, endpoint: https://api.qwen.com/v1/chat, capabilities: [text-generation, streaming], input_schema: {\type\:\object\,\properties\:{\prompt\:{\type\:\string\}}}, weight: 100 }生产环境必配项HTTPS终止在网关前加Nginx处理SSL卸载网关内部走HTTP健康检查K8s liveness probe指向/healthz该接口检查SQLite连接至少一个模型可用日志归集uvicorn日志输出JSON格式用Filebeat推送到ELK配置热更新监听SQLite文件变更自动重载模型列表避免重启注意不要在网关里做模型推理它的唯一职责是调度、转换、治理。所有模型服务必须独立部署网关只做HTTP客户端。5. 常见问题与避坑指南那些文档里不会写的实战细节5.1 “我的模型是gRPC网关能接吗”——协议适配的边界在哪能接但要注意gRPC的特殊性。gRPC不像HTTP有明确的RESTful语义其方法名如/inference.InferenceService/Generate和protobuf schema才是关键。网关需动态加载proto文件启动时读取.proto定义生成Python stub请求体转换将JSON请求按proto schema序列化为二进制流式响应处理gRPC streaming需在网关层转成SSE或WebSocket否则前端无法消费避坑点不要试图在网关里写gRPC server。正确做法是让模型服务同时暴露gRPC和REST接口用grpc-gateway网关只走REST。这样既保持网关轻量又避免gRPC版本兼容问题。5.2 “模型返回的token数不准限流失效怎么办”这是高频痛点。Qwen API返回usage.total_tokens但本地Llama模型可能只返回generated_tokens不含prompt tokens。网关限流若只看模型返回值会导致对Qwen严格按总tokens限流对Llama漏计prompt tokens实际超限解决方案网关主动计算prompt tokens。用tiktoken库Qwen用cl100k_baseLlama用llama3对输入文本分词再加模型返回的generated_tokens。实测误差3 tokens。from tiktoken import get_encoding def count_prompt_tokens(text: str, model_name: str) - int: if qwen in model_name.lower(): enc get_encoding(cl100k_base) elif llama in model_name.lower(): enc get_encoding(llama3) else: enc get_encoding(gpt2) # fallback return len(enc.encode(text))5.3 “灰度发布时新旧模型输出格式不一致下游炸了”典型场景旧模型返回{result: text}新模型返回{response: {text: text, confidence: 0.92}}。业务代码没适配直接res[result]报KeyError。网关必须做输出标准化。在路由后、返回前插入转换层def standardize_output(model_id: str, raw_output: dict) - dict: if qwen in model_id: return {text: raw_output.get(text, ), tokens: raw_output.get(usage, {}).get(total_tokens, 0)} elif llama in model_id: return {text: raw_output.get(generated_text, ), tokens: raw_output.get(tokens, 0)} else: return raw_output # passthrough实操心得标准化规则必须版本化。v1标准要求text字段v2增加metadata对象。网关根据请求HeaderAccept-Version: v2决定用哪套规则避免一刀切破坏旧客户端。5.4 “网关成了单点故障怎么保证高可用”AI网关本身必须无状态。所有状态模型注册、路由策略、限流计数存外部系统模型注册SQLite可主从复制或直接用PostgreSQL推荐限流计数用Redis Clusterkey为rate_limit:{tenant_id}:{model_id}健康检查状态用Consul或etcd做分布式心跳部署时至少2个网关实例前面挂负载均衡如AWS ALB。实测单实例可扛5000 QPS双实例ALB自动故障转移RTO30秒。5.5 “审计日志太大磁盘爆了怎么办”结构化日志虽好但1000 QPS下每天产生20GB日志。必须分级Level 1必存event_id,timestamp,user_id,model_id,status,latency_ms,tokens_in/out—— 存Elasticsearch保留30天Level 2采样存1%请求存完整input_hash和output_truncated—— 用于合规抽查Level 3不存原始input/output文本 —— 除非X-Audit-Full: trueHeader显式要求用Logstash做日志采样if [level] 2 and (rand() * 100) 99 { ... }6. 多模态模型落地的特殊考量网关如何应对“图文音”混合战场多模态不是“文本模型图片模型”的简单叠加而是能力维度的指数级增长。网关在此场景下角色从“调度员”升级为“交响乐指挥”。6.1 输入组合爆炸一张图一段语音一段文字该怎么路由传统路由看单一特征多模态必须做联合特征分析。例如图片文字 → 可能是“图文问答”路由到Qwen-VL语音文字 → 可能是“会议纪要”需ASR转文字再摘要路由到WhisperQwen流水线图片语音 → 可能是“视频帧分析”需抽帧语音转录联合推理网关需内置轻量特征提取器用python-magic识别文件类型避免image/jpegHeader被伪造用ffprobe快速获取音频时长、采样率判断是否需分段用PIL.Image读取图片尺寸、模式RGB/RGBA排除损坏图片然后生成联合路由标签[multimodal, audio, long-context]匹配预设规则。6.2 输出格式碎片化文本、JSON、二进制图片、音频流怎么统一返回多模态模型输出五花八门Qwen-VL返回JSON含text和image_urlStable Diffusion返回PNG二进制Whisper返回VTT字幕文件网关必须做输出协议协商请求HeaderAccept: application/json→ 返回结构化JSON图片转base64Accept: image/png→ 若模型输出图片直接透传否则返回406Accept: text/vtt→ 对ASR结果做VTT封装核心原则网关不生成内容只转换容器。图片base64编码开销大生产环境应配置CDN回源网关只返回{image_url: https://cdn.example.com/xxx.png}。6.3 计算资源异构GPU、CPU、NPU网关怎么感知并调度模型部署环境差异巨大Qwen-VL需A10G GPUWhisper-smallCPU即可但需大内存Phi-3-visionNPU加速Linux驱动特殊网关的健康检查必须包含资源探测# GPU探测 nvidia-smi --query-gpuutilization.gpu,temperature.gpu --formatcsv,noheader,nounits # CPU探测 lscpu | grep CPU\(s\)将结果存入模型元数据resource_profile字段。路由时若请求标记gpu_required: true则只选resource_profile.gpu_util 70%的模型。注意不要在网关里执行