1. 从 PyTorch 导出到推理服务ONNX 模型部署到底卡在哪ONNXOpen Neural Network Exchange是一种开放的神经网络交换格式你可以把它理解成模型世界的“PDF”——不管模型是用 PyTorch、TensorFlow 还是 PaddlePaddle 训练的导出成 ONNX 之后就能在 ONNX Runtime 这个统一引擎上跑推理。它适合谁适合那些训练用一套框架、上线又要换另一套环境的开发者尤其是需要把模型塞进 C 服务、边缘设备或者浏览器里的场景。但真正动手做 ONNX 模型部署的人都知道导出只是第一步。模型文件拿到了接下来要面对的是ONNX Runtime 的 session 怎么配、输入输出名字怎么对齐、动态 batch 怎么处理、量化后精度掉了怎么办。更麻烦的是当你把推理服务封装成 HTTP API 之后鉴权、Key 管理、多模型路由这些“非模型”问题会迅速吃掉你的时间。我见过不少团队模型本身跑得挺好结果卡在 API Key 散落在各个脚本里、换一个模型就要改一次调用链。这篇指南聚焦 ONNX 模型从导出到上线推理服务的完整链路。我会先带你把 PyTorch 模型转成 ONNX 并验证结构然后用 ONNX Runtime 在 Python 里跑通推理接着把推理逻辑封装成 FastAPI 服务最后用 TaoToken 的统一 Key 来管理推理服务的鉴权与调用。整个过程你可以直接复制命令和代码跟做不需要额外买 GPU本地 CPU 就能验证。核心检索词先明确ONNX 模型部署、ONNX Runtime 推理、TaoToken 统一 Key、推理服务调用链。这四个词会贯穿全文。如果你现在手里有一个训练好的.pt文件或者只是想搞清楚 ONNX Runtime 到底怎么用下面的步骤可以直接照搬。2. 前置准备TaoToken 统一 Key 与 ONNX Runtime 环境搭建在开始写推理代码之前先把两件事搞定一是 ONNX Runtime 的运行环境二是推理服务对外调用时的鉴权方案。环境部分很简单Python 3.9 以上装三个包就够pip install onnx onnxruntime fastapi uvicorn python-multipart如果你需要做模型量化再加一个pip install onnxruntime-toolsCPU 版本的 onnxruntime 默认就支持大部分算子GPU 版本需要根据 CUDA 版本单独装onnxruntime-gpu。本地验证阶段用 CPU 版完全足够ResNet50 单张图片推理大概几十毫秒。接下来是鉴权。当你把 ONNX 推理服务封装成 API 之后如果不加任何保护任何人拿到地址就能调用。传统做法是在服务里硬编码一个 Key或者用环境变量传一个密钥但这样每接一个模型、每换一个环境就要重新配一次。TaoToken 的思路是提供一个统一的 Key 来管理多个模型服务的调用凭证你只需要在请求头里带上同一个 Key后端根据模型 ID 路由到对应的推理服务。TaoToken 的 API 地址是https://taotoken.net/api控制台里可以创建和管理 API Key。你需要在控制台生成一个 Key然后把它放到推理服务的环境变量里。注意这个 Key 是给调用方用的不是给 ONNX Runtime 用的——ONNX Runtime 本身不关心鉴权鉴权层是你自己封装的 FastAPI 中间件。具体操作登录 TaoToken 控制台进入 API Keys 页面创建一个新的 Key复制出来。然后在你项目的.env文件里写TAOTOKEN_API_KEYsk-你的实际key TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用的是 Claude Code 或者 Cline 这类编码工具来辅助写推理服务代码可以在工具的配置里把 Base URL 和 Key 填进去这样生成代码时能直接引用正确的环境变量名。Claude Code 的配置方式是在~/.claude/settings.json里加{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的实际key } }Cline 的 MCP 配置类似在cline_mcp_settings.json里指定 Base URL 和 Key。Codex 的话auth.json里填OPENAI_BASE_URL和OPENAI_API_KEY。这三件套——Base URL、Key、Model ID——在任何一个工具里都是必须的缺一个就连不上。环境准备好之后确认一下 onnxruntime 能正常导入import onnxruntime as ort print(ort.get_available_providers())输出里应该包含CPUExecutionProvider如果有 GPU 会显示CUDAExecutionProvider。到这里前置工作完成接下来进入模型导出和推理验证。3. 可复制配置PyTorch 导出 ONNX 与 FastAPI 推理服务封装这一节给出完整的可复制配置。先导出模型再写推理服务最后把 TaoToken 的鉴权中间件加进去。3.1 PyTorch 导出 ONNX 模型以 ResNet50 为例导出脚本export_onnx.pyimport torch import torchvision.models as models model models.resnet50(pretrainedTrue) model.eval() dummy_input torch.randn(1, 3, 224, 224) torch.onnx.export( model, dummy_input, resnet50.onnx, export_paramsTrue, opset_version11, do_constant_foldingTrue, input_names[input], output_names[output], dynamic_axes{ input: {0: batch_size}, output: {0: batch_size} } ) print(导出完成)运行python export_onnx.py当前目录会生成resnet50.onnx。验证模型结构import onnx model onnx.load(resnet50.onnx) onnx.checker.check_model(model) print(onnx.helper.printable_graph(model.graph))如果check_model没有报错说明模型文件是合法的。printable_graph会打印出计算图你可以看到输入节点叫input输出节点叫output和导出时指定的名字一致。3.2 ONNX Runtime 推理脚本写一个inference.py加载模型并对随机输入做推理import onnxruntime as ort import numpy as np session ort.InferenceSession(resnet50.onnx) input_name session.get_inputs()[0].name output_name session.get_outputs()[0].name input_data np.random.randn(1, 3, 224, 224).astype(np.float32) outputs session.run([output_name], {input_name: input_data}) print(输出形状:, outputs[0].shape) print(Top-1 类别:, np.argmax(outputs[0]))运行后应该看到输出形状(1, 1000)Top-1 类别是一个 0 到 999 之间的整数。这一步验证了 ONNX Runtime 能正常加载和推理。3.3 FastAPI 推理服务 TaoToken 鉴权把推理逻辑封装成 HTTP 服务文件app.pyimport os import io import numpy as np from PIL import Image from fastapi import FastAPI, File, UploadFile, Header, HTTPException import onnxruntime as ort app FastAPI() TAOTOKEN_API_KEY os.getenv(TAOTOKEN_API_KEY, ) session ort.InferenceSession(resnet50.onnx) input_name session.get_inputs()[0].name output_name session.get_outputs()[0].name def preprocess(image_bytes): img Image.open(io.BytesIO(image_bytes)).convert(RGB) img img.resize((224, 224)) arr np.array(img).astype(np.float32) / 255.0 arr arr.transpose(2, 0, 1) arr np.expand_dims(arr, axis0) return arr app.post(/predict) async def predict( file: UploadFile File(...), authorization: str Header(None) ): if not authorization or not authorization.startswith(Bearer ): raise HTTPException(status_code401, detail缺少 Bearer Token) token authorization.split( )[1] if token ! TAOTOKEN_API_KEY: raise HTTPException(status_code401, detailToken 无效) image_bytes await file.read() input_data preprocess(image_bytes) outputs session.run([output_name], {input_name: input_data}) class_id int(np.argmax(outputs[0])) confidence float(np.max(outputs[0])) return {class_id: class_id, confidence: confidence}启动服务export TAOTOKEN_API_KEYsk-你的实际key uvicorn app:app --host 0.0.0.0 --port 8000这个配置里TaoToken 的 Key 通过环境变量注入请求方需要在 Header 里带Authorization: Bearer sk-你的实际key。如果你有多个模型服务可以共用同一个 Key后端根据路径或模型 ID 路由这就是统一 Key 管理的意义——调用方只需要记一个 Key不用为每个模型单独申请。4. 验证请求用 curl 和 Python 确认推理服务部署成功服务启动后先确认端口监听正常curl http://127.0.0.1:8000/docs如果返回 Swagger UI 的 HTML说明 FastAPI 已经跑起来了。接下来发一个真实的推理请求。准备一张测试图片比如test.jpg然后curl -X POST http://127.0.0.1:8000/predict \ -H Authorization: Bearer sk-你的实际key \ -F filetest.jpg预期返回{class_id: 281, confidence: 12.34}class_id是 ImageNet 的类别索引confidence是 logits 最大值这里没有做 softmax所以数值可能比较大。如果你想要概率值可以在返回前加一层 softmax。再用 Python 脚本验证一次模拟调用方import requests url http://127.0.0.1:8000/predict headers {Authorization: Bearer sk-你的实际key} files {file: open(test.jpg, rb)} resp requests.post(url, headersheaders, filesfiles) print(resp.status_code) print(resp.json())如果返回 200 和正确的 JSON说明整条链路——ONNX Runtime 加载模型、FastAPI 接收请求、TaoToken Key 鉴权、推理返回结果——全部打通。再测一下鉴权失败的情况curl -X POST http://127.0.0.1:8000/predict \ -H Authorization: Bearer wrong-key \ -F filetest.jpg应该返回 401 和{detail: Token 无效}。这一步确认了鉴权中间件确实在生效不是摆设。如果你想把服务部署到云端只需要把uvicorn换成gunicorn加uvicorn.workers.UvicornWorker然后用 Nginx 做反向代理。TaoToken 的 Key 继续通过环境变量注入不需要改代码。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth部署过程中最容易遇到的几个报错这里逐一对照。401 Unauthorized请求头里没有带Authorization或者 Bearer Token 和 TaoToken 控制台里的 Key 不一致。检查.env文件是否被正确加载os.getenv(TAOTOKEN_API_KEY)是否返回了非空值。如果你用的是 Claude Code 或 Cline确认settings.json或cline_mcp_settings.json里的ANTHROPIC_API_KEY/OPENAI_API_KEY填的是 TaoToken 的 Key而不是其他平台的。local proxy failed这个报错通常出现在编码工具连接 TaoToken API 的时候。原因是 Base URL 配置错了。Claude Code 的ANTHROPIC_BASE_URL应该填https://taotoken.net/api不要多加/v1或者结尾斜杠。Cline 的 MCP 配置里Base URL 同样填https://taotoken.net/api。Codex 的auth.json里OPENAI_BASE_URL也是这个地址。三件套——Base URL、Key、Model ID——任何一个填错都会导致连接失败。reading choices 报错这个通常发生在调用模型对话接口时返回体里没有choices字段。原因可能是 Model ID 填错了或者请求体格式不对。检查你用的模型名称是否在 TaoToken 支持的列表里请求的 JSON 结构是否符合 OpenAI 兼容格式。如果是 ONNX 推理服务本身报这个错那说明你把模型对话的响应格式和推理服务的响应格式搞混了——ONNX 推理返回的是张量不是choices。OAuth 相关报错如果你在 Claude Code 里看到 OAuth 错误说明工具在尝试用 OAuth 流程认证而不是用 API Key。需要在配置里显式指定 API Key 模式把ANTHROPIC_API_KEY填上并且确保没有同时启用 OAuth 登录。Cline 和 Codex 同理优先用 Key 认证不要走 OAuth。还有一个容易忽略的点ONNX Runtime 的session.run返回的是一个列表即使你只请求了一个输出。取结果的时候要用outputs[0]不要直接当数组用。另外输入数据的 dtype 必须是float32如果你从 PIL 转 numpy 之后忘了.astype(np.float32)会报类型不匹配。6. 语义一致 CTA把 ONNX 推理服务接入统一调用链到这里你的 ONNX 模型已经能从 PyTorch 导出、用 ONNX Runtime 加载、通过 FastAPI 暴露成 HTTP 接口并且用 TaoToken 的统一 Key 做了鉴权。下一步取决于你的实际场景。如果你还在调试模型本身想快速验证不同 ONNX 模型的推理效果可以直接用 TaoToken 的模型对话功能做对比测试地址是https://taotoken.net/api对应的控制台入口。如果你需要长期跑编码任务或者构建 Agent 工作流Coding Plan 更适合Key 和 Base URL 的配置方式和上面完全一致。接入文档里有完整的 API 说明和示例API Keys 页面可以管理你的所有 Key。建议把推理服务的 Key 和编码工具的 Key 分开管理虽然 TaoToken 支持统一 Key但分环境使用不同 Key 更利于排查问题。最后提醒一点ONNX 模型部署不是一次性的工作。模型更新后需要重新导出、重新验证、重新部署。把导出脚本、推理服务代码、Dockerfile 都纳入版本管理每次更新走一遍验证请求确保class_id和confidence在预期范围内。这套流程跑顺之后换模型只是替换一个.onnx文件的事。