
刚开始做 AI 应用落地那两年我踩过最大的坑不是模型效果不够好而是模型已经跑通了却迟迟没法交给业务方用。原因很简单模型在 Notebook 里能跑和它变成一个稳定、安全、成本可控的服务中间隔着一整条模型服务化与 API的路。没有服务化模型就只是一段代码有了服务化它才变成一个能计量、能治理、能持续演进的产品。这篇文章就围绕这个主题用我实际做项目的经验把大模型接入这件事拆开讲清楚适合那些已经跑通模型、正准备对外提供能力的团队参考。1. 为什么能跑通的模型离能上线还差一个服务化1.1 本地脚本调用与大模型服务的本质差别我相信很多团队和我早期一样都是这么用大模型的写个 Python 脚本本地把模型 load 进来或者直接调某个云端 API输入一句话得到一句话任务就算跑通了。这个阶段大家都觉得挺简单的啊。但一旦要把这个能力开放给多个业务方、多个系统同时用问题立刻暴露。最典型的是并发。本地脚本往往是单线程、单进程调用一次只处理一个请求。业务方同时来了十个人调用前面的人还没推理完后面的人就得排队甚至直接把内存或者显存打爆。这不是模型的问题是调用方式的问题——模型推理能力没有被服务化自然就没有并发承接的能力。再说隔离。一个模型服务如果每个调用方都直接连模型进程那任何一边的异常流量、超长请求、恶意调用都会直接压到模型本身上。我用过一个内部工具同事写了个死循环调用生成接口模型进程直接 OOM 崩掉所有人一起遭殃。没有统一的 API 接入层就没有办法在模型前面做隔离、限流和降级。还有版本和兼容。模型今天更新一版如果各业务方都是直接改代码调模型那版本切换就要所有调用方一起跟着改想想都累。服务化之后模型能力的变更被约束在 API 内部调用方只要接口格式不变底层换模型也好、换供应商也好都是服务端的事。1.2 服务化之后才有的三件事并发、版本、接入标准服务化本质上做的是这么一件事把模型推理从业务代码里的一个函数调用变成独立运维的一个服务单元。这个单元有独立的进程、独立的资源配额、独立的标准接口。做到这一点之后三件原来做不了的事就顺理成章了。一是并发可控。模型服务启动后请求先进入队列由服务框架统一调度能批处理的批处理不能批处理的排队等待。并发上限由显存和服务配置决定而不是由谁运气好先调到了决定。二是版本可管理。模型迭代不再是一次性的代码替换而是新起一个服务实例做好 API 兼容甚至可以做灰度——先让 10% 流量走新版本观察效果再逐步放量。这个能力对生产环境尤其重要。三是接入标准统一。现在的事实标准是 OpenAI 兼容接口/v1/chat/completions这种格式几乎成了行业通用语言。本地部署的模型、云厂商的 API、开源社区的框架大家都主动兼容这套接口。这意味着业务侧不需要关心模型部署在哪、底层是什么架构只需要面向标准接口开发。后面业务要接多个模型协同工作也只需要在 API 层做路由不需要改业务代码。2. 模型服务化的底座选型跑起来容易跑得久要提前想清楚2.1 主流模型服务框架怎么选模型服务化落地的第一步是选一个合适的服务底座。这里没有绝对的最好只有和你的场景最匹配的。我整理了一张对比表可以对着看。框架/方式易用性性能与吞吐适合场景需要什么样的团队Ollama极高几乎零配置中等适合轻量并发本地开发、内部工具、Demo几乎不需要运维vLLM较高一条命令可起服务高自带 PagedAttention 等优化生产环境开源模型部署熟悉 GPU 资源管理能做基础运维Triton Inference Server较低配置复杂很高支持多种框架大规模生产、多模型混合部署有经验的推理平台团队Ray Serve中等高Python 技术栈需要灵活路由的业务熟悉 Python 分布式生态云端 API 托管零运维按量付费取决于供应商起步期、波动大、不想管理基础设施不需要运维但要管 Key 和预算我的建议是如果你还在验证阶段Ollama 是上手最快的如果模型已经确定要长期对外服务vLLM 是目前开源社区综合性价比最高的选择如果业务是典型的互联网高并发场景、有多模型多框架部署需求Triton 或 Ray Serve 值得投入。另外现在很常见的一种方式是开源模型本地部署 云端 API 托管混用。比如核心敏感数据走本地私有化部署普通任务走云端 API。这种情况下选型时就要考虑两者能不能用同一套接口标准OpenAI 兼容格式几乎成了共识这也方便后续做统一路由。2.2 一个最小可用的 LLM API 服务是怎么搭起来的说再多不如实际操作一遍。这里我用 vLLM 作为例子因为它既能体现生产级部署的常见做法又足够简单。安装之后一条命令就能把模型起成服务。以 Qwen2.5-7B-Instruct 为例vllm serve Qwen/Qwen2.5-7B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9这条命令的含义很简单把模型跑在 8000 端口允许最长 8192 个 token 的上下文单卡显存利用率上限设为 90%。启动成功后你就可以用标准的 OpenAI 接口格式去请求了curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: Qwen/Qwen2.5-7B-Instruct, messages: [{role: user, content: 用一句话介绍什么是模型服务化}], max_tokens: 128 }响应会返回一个包含choices和usage字段的 JSONusage里会告诉你本次请求消耗了多少prompt_tokens和completion_tokens。别小看这两个数字后面做可计量全靠它们。如果你的模型文件是本地下载好的也可以用 Ollama 做极简起步ollama serve ollama run qwen2.5:7b然后同样用兼容接口调用http://localhost:11434/v1/chat/completions。从外部看接口风格和 vLLM 几乎一样这也是我强调接入标准统一的原因——底层怎么部署是你的选择业务侧感知不到差异。2.3 容易被低估的资源规划显存、并发与上下文长度服务化搭建本身不难真正容易翻车的是资源规划。我见过不少团队服务起得来一压测就崩问题基本都出在三个地方。第一个是显存估算。模型权重占一部分KV Cache 占一部分实际运行时还有激活层开销。一个经验是7B 级别模型做 8K 上下文时单请求的显存占用大约在几 GB 量级如果把--max-model-len拉到 32K显存占用会明显上升。所以--gpu-memory-utilization不建议设到 0.98 这种极限值给系统留点余量否则一个突发长请求就可能触发 OOM。第二个是并发设置。vLLM 中有--max-num-seqs参数控制最大同时处理的序列数它和显存、上下文长度直接相关。并发不是越高越好设太高会导致请求互相抢占显存引发频繁的排队和超时。正规做法是先设一个保守值用压测工具逐步加压找到吞吐和延迟的平衡点。第三个是上下文长度上限。这是很多生产事故的源头——用户发来的请求内容太长prompt_tokens max_tokens加起来超过了模型服务的max-model-len服务端直接返回 400 错误比如常见的 this models maximum context length is 1048576 tokens 这类报错。这种问题不该让用户去承担而应该在 API 接入层提前做长度校验或内容截断。关于这一点我后面踩坑部分还会详细讲。3. 可计量把 token 变成产品里的成本度量衡3.1 为什么大模型按 token 计费很多非技术背景的业务同事问过我一个问题大模型收费为什么按 token 算而不是按条数、按字数原因是 token 才是大模型真正的工作量单位。一段文本在模型内部并不是按字或按字符处理的而是被切分成 token 序列。模型每生成一个 token都意味着一次完整的前向推理计算消耗的算力和时间与 token 数量强相关。所以无论外部 API 还是自建服务最后都回到了 token 计量。一个请求的成本可以表示为成本 输入 token 数 × 输入单价 输出 token 数 × 输出单价单价因模型和部署方式而异外部托管 API 是明码标价自建部署则要自行折算 GPU 硬件折旧、电费、人力维护成本。但不管怎么折算没有 token 计量就没有成本意识。可计量的另一个好处是成本归因。当一个平台上有多个业务方接入模型能力时每个 Key 消耗了多少 token、花了多少钱只有计量清楚才能合理分摊和预算管控。我见过有的公司月底对账才发现某个测试应用白白烧掉了上万块的 API 费用就是因为当初没做计量。3.2 计量链路的四个环节从请求日志到成本分摊把一个模型的消耗算清楚不是简单地看一次请求的 usage 字段就够了。完整链路至少包含四个环节第一个环节是接入层记录。每一个 API 请求进来接入层就记下请求 ID、API Key、调用的模型、请求时间、状态码。这一层的日志是后续所有计量和问题排查的基础。第二个环节是模型层返回用量。如我前面所说OpenAI 兼容接口的响应里会带usage字段包含prompt_tokens、completion_tokens、total_tokens。自建部署同样会返回这是最权威的原始计量数据。第三个环节是日志汇聚与清洗。把接入层日志和 usage 数据关联起来按时间、按 Key、按模型维度做聚合。这一步通常落到 Elasticsearch、ClickHouse 或普通的关系型数据库里看数据规模。第四个环节是成本换算与分摊。根据单价表把 token 数换算成金额再按部门、项目、应用维度分摊。输出形式就是一张成本看板今天总消耗多少 token、哪个应用消耗最多、哪个时间段是高峰。计量指标设计方面下面几个是我认为必看的指标含义用途请求数 / QPS单位时间调用量评估服务压力和扩容需求Token 总数输入 输出 token 累计核算总体成本输入输出 token 比例生成量对比判断业务是重输入还是重输出平均延迟每次请求响应时间评估用户体验错误率4xx/5xx 占比发现接口异常单 Key 消耗占比按调用方汇总成本分摊和配额管理3.3 一个轻量 token 计量脚本的参考设计对于中小团队一开始不需要上很重的大数据平台。一个简单的 Python 脚本就能把计量跑起来。下面是我在项目里用过的思路。每次调用完成后解析响应里的 usage 字段把数据写入一张数据库表import requests import sqlite3 import datetime API_URL http://localhost:8000/v1/chat/completions MODEL_NAME Qwen/Qwen2.5-7B-Instruct def call_model(messages, api_keyinternal-test): resp requests.post(API_URL, json{ model: MODEL_NAME, messages: messages, max_tokens: 256, }, headers{Authorization: fBearer {api_key}}) resp.raise_for_status() data resp.json() usage data.get(usage, {}) # 记录计量数据 conn sqlite3.connect(token_usage.db) conn.execute( INSERT INTO usage_log(api_key, model, prompt_tokens, completion_tokens, total_tokens, created_at) VALUES (?,?,?,?,?,?), (api_key, MODEL_NAME, usage.get(prompt_tokens, 0), usage.get(completion_tokens, 0), usage.get(total_tokens, 0), datetime.datetime.now().isoformat()) ) conn.commit() conn.close() return data[choices][0][message][content]这个脚本的价值不在技术难度而在于培养了每次调用都要计量的习惯。等数据积累起来你再去做成本看板、配额控制都有据可依。否则治理就是空中楼阁。4. 可治理API Key 之外还要管住入口、出口和全程4.1 API Key产品身份的第一道门可计量的下一步是可治理。治理的第一道关就是 API Key 体系。没有 Key 就谈不上区分调用方更谈不上配额和审计。我建议每个接入方单独分配一个 Key命名上体现用途比如key-xxx-数据分析平台、key-xxx-内部客服工具。这样出了任何问题都能快速定位到具体是哪个调用方。Key 的创建、轮换、吊销要有流程。特别是吊销能力一旦某个 Key 疑似泄露必须能在几秒钟内禁用而不是去改代码重启服务。还有一条必须强调的安全红线API Key 绝对不允许出现在前端页面、移动端 App 或任何客户端代码里。客户端环境没有秘密可言Key 一旦被抓包提取别人就能拿着你的 Key 白嫖模型资源。正确做法是客户端请求自己的后端由后端持有 Key 去调用模型服务。这一点在我们这个行业已经是常识但我在实际项目里还是见过有人图省事把 Key 写死在前端结果上线当天就被爬走了。4.2 限流、配额与熔断三类治理策略的分工API Key 解决的是谁在调用的问题接下来要解决能调用多少和异常了怎么办的问题。这里有三类治理策略很多人容易混为一谈我分开讲。限流控制的是速率。比如单个 Key 每秒最多 10 次请求超过就报 429。限流保护的是服务本身不被突发流量冲垮常用算法有固定窗口、滑动窗口、令牌桶。内部系统用简单的计数就能实现生产环境建议在网关层配置。配额控制的是总量。比如单个 Key 每天最多消耗 100 万 token用完了当天就不能再调。配额和限流是两回事限流管瞬间的洪峰配额管长期的总额。配额对成本控制尤其重要可以防止某个业务方的代码 bug 或误操作导致费用失控。熔断是另一层保护。当上游模型服务出现故障比如显存溢出、响应超时比例过高时接入层应该主动熔断快速返回降级提示而不是让所有请求都堆在模型前面雪上加霜。熔断之后还要有恢复机制隔一段时间放少量请求试探服务正常了再逐步放开。策略控制维度典型配置触发响应限流瞬时速率单 Key 10 req/sHTTP 429配额时间段总量单 Key 每天 100 万 tokenHTTP 429 或降级熔断上游健康状态错误率超 50% 时熔断 30 秒快速失败 降级4.3 全链路审计每一次调用都要能追溯治理的最后一层是审计。所谓审计就是每一次调用都能回答谁、在什么时间、用了哪个模型、输入了多少 token、输出了多少 token、结果成功还是失败、耗了多少毫秒这几个问题。我之前遇到过一次线上事故排查某个业务方说模型回答质量突然下降怀疑是模型版本被改动了。因为没有审计日志排查只能靠猜。后来我们补齐了每次调用的日志发现其实是那个业务方的代码误传了一个很旧的 prompt 模板和模型版本没关系。这就是审计的价值——出了问题能快速定位而不是靠开会对齐。审计日志还要注意数据安全。大模型请求往往包含业务数据甚至个人信息日志存储时该脱敏的脱敏该加密的加密访问日志的权限也要收敛。这一点不展开多说但一定要在架构设计阶段就考虑进去否则后面补会很痛苦。5. 把可计量、可治理落到实处的三个进化阶段5.1 第一阶段内部 Demo 期最简方案如果你的团队还在做内部验证没有对外暴露给大量用户治理体系可以先从最简方案起步不必一上来就上企业级网关那是过度设计。最简方案是这么做的模型用 Ollama 或 vLLM 本地起服务接入层写一个轻量的 Python 中间服务所有请求统一走这个中间服务中间服务里做三件事——校验一个简单的 Header Token、把请求转发给模型服务、把 usage 记录写进本地数据库。这个 Token 可以先写死在环境变量里够内部用就行。我特别强调要保留中间服务这一层而不是让内部各个脚本直接连模型服务。因为治理是一层层长出来的如果一开始就没有接入层后面补的时候需要推动所有调用方改接入方式阻力会非常大。先有一个最简的中间层以后的一切治理能力都在这一层上叠加。5.2 第二阶段准生产环境的治理补全当业务方开始增加、调用量稳定增长时就要把治理体系补全到准生产标准了。这个阶段做几件事一是把接入层升级为正式的 API 网关能力至少具备多 Key 管理、基础限流、配额控制、请求日志全量记录。如果团队不想自己造轮子Kong、APISIX 这类开源网关都支持这些能力配置好就能用。二是建立监控告警。不是被动看日志而是主动告警单 Key 消耗超过预算的 80% 要告警服务错误率超过阈值要告警平均延迟劣化要告警。告警规则一定先少而精避免告警疲劳。三是明确治理责任人。计量和治理不是自动发生的要有人对整体成本、Key 生命周期、规则配置负责。建议由后端或平台团队的固定同学牵头业务方只负责使用。5.3 第三阶段多模型路由与成本精细化到了规模化阶段单一模型往往不够用这时候可治理的收益会进一步放大。我在项目里见过很典型的多模型协作场景先用一个便宜的小模型做意图识别把请求分类简单任务直接用小模型回答复杂任务才转给大模型。这样一来整体成本可能下降一大半而入口还是同一个 API。也有人把本地开源模型和高性能云端 API 混用。比如把离线批处理任务发给 DeepSeek 这类外部 API把实时高价值对话走本地私有化部署。到底怎么组合要看数据和成本诉求但这些都依赖一个前提你有一个统一的 API 接入层能在路由层做模型分发和计量。否则每接一个模型都要改一遍业务代码那就不是架构是打补丁。这个阶段还可以做灰度发布。新模型上线后先让 5% 的流量切过去通过计量数据对比质量和成本确认没问题再逐步放量。这在没有 API 层的架构里几乎无法安全实现。6. 我在实际接入过程中踩过的坑和补救方式6.1 上下文长度上限引发的 400 错误一次线上事故让我印象很深。用户反馈某个功能突然报错错误信息是 api error: 400 this models maximum context length is 1048576 tokens。排查过程花了不少时间因为链路长日志分散在网关和模型服务两端。最后原因其实很普通某个业务方在做文档问答把整篇长文档不加处理地塞进 messages 里再加上生成长度总 token 数量超过了模型服务的max-model-len配置请求直接被模型服务拒绝。用户的输入文档越写越长到了一个临界点就集中爆发。这个问题的补救措施有两层。第一层是在 API 接入层做请求长度预检拿 prompt 的 token 估算值加上max_tokens超限就直接返回友好提示而不是让用户看到底层报错。第二层是业务侧对长文档做切片或分段摘要控制单次请求的 token 量。这个坑的核心教训是上下文长度限制是用户无法感知的必须由服务端兜底。6.2 并发配置过高导致显存溢出的教训还有一次是服务压测时直接把 GPU 显存打满模型进程崩溃。当时我们把--max-num-seqs调得偏高想追求吞吐。压测数据量一上来多个请求的 KV Cache 同时占显存叠加长序列请求显存瞬间爆掉。补救方式是恢复保守的并发配置同时把--gpu-memory-utilization从 0.95 下调到 0.9给系统留出缓冲。然后再做渐进式压测从低并发开始观察显存占用和延迟曲线找到拐点再定最终配置。现在我把这个流程固化成了每次部署的必做动作不再凭感觉调参。经验就是一句话性能参数必须用压测数据说话不能靠估算。6.3 计量口径不统一缓存命中到底算不算钱最后说一个计量层面的坑。不同调用方对 token 消耗的统计口径一度不一致导致月底对账很麻烦。典型问题是某些场景走了缓存比如相同的问题直接返回缓存答案没有真实调用模型那么到底算不算消耗如果算怎么算我们的解决方案是一切以模型服务端返回的 usage 数据为唯一计量依据缓存命中的请求单独打标记、不计入模型消耗但计入网关访问量。这个口径明确之后成本看板和业务预期才对得上。计量这种事宁可一开始就把规则定细致也不要等账对不上再去解释。做到这一步之后你再回头看模型服务化与 API这件事会发现真正有价值的不只是把接口跑通而是从接入那一刻起就建立了计量和治理的骨架。模型本身会持续迭代服务框架也会推陈出新但可计量、可治理这个原则是所有大模型应用走向产品化的地基值得一开始就做对。