模型部署:Java 服务需要关心的那部分
原来那套「用 TorchServe 或 Flask 把模型包成 HTTP 接口」的做法已经过时了——TorchServe 的仓库在 2025 年 8 月被归档,官方明确说明不再有更新、缺陷修复和安全补丁。现在的问题变成了:选托管 API、自建 vLLM 还是本地 Ollama,以及 Java 侧要为此做哪些准备。
一、先说结论
- 对大多数 Java 团队,托管 API 是默认选择:没有 GPU 运维、按用量付费、接口通常是 OpenAI 兼容的 HTTP。
- 自建的主要理由是数据不能出网、或者用量大到自建更便宜,这时 vLLM 是当前的主流选择,它提供 OpenAI 兼容接口和连续批处理。
- 本地 Ollama 适合开发和评测:一条命令拉起模型,接口同样兼容,但吞吐和并发能力有限。
- 非 LLM 的传统模型(分类、排序、CV)仍然需要 Triton 这类推理服务框架,或者直接嵌入到 Python 服务里。
- 无论哪种形态,Java 侧要处理的都是同一组问题:超时与重试、流式响应、并发上限、成本与配额、降级。
二、四种形态
| 形态 | 谁负责扩缩容与显存 | 适合 | 主要代价 |
|---|---|---|---|
| 托管 API(云厂商或模型厂商) | 服务方 | 绝大多数业务场景 | 按 token 计费;数据出网;速率限制 |
| 自建 vLLM | 自己 | 数据不能出网、用量大、需要特定模型 | GPU 成本与运维;容量规划 |
| 本地 Ollama | 自己(单机) | 开发、演示、离线评测 | 并发与吞吐有限 |
| Triton 等推理框架 | 自己 | 非 LLM 模型、多框架混合部署 | 配置复杂,运维成本最高 |
2.1 关于 TorchServe
PyTorch 官方仓库的说明是「Limited Maintenance——不再积极维护,没有计划中的更新、缺陷修复、新功能和安全补丁」,仓库已于 2025 年 8 月 7 日归档为只读。已有部署可以继续跑,但新项目不应该再选它;如果现有系统依赖它,要把迁移列进计划,至少要评估安全补丁缺失的风险。
2.2 为什么 vLLM 成了默认
它解决的是 LLM 推理特有的两个问题:KV 缓存的内存管理(PagedAttention)和连续批处理(不同长度的请求动态组批)。对使用方来说,最直接的好处是暴露 OpenAI 兼容的 /v1/chat/completions 接口——Java 侧的客户端代码不需要为自建和托管写两套。
# 典型启动方式(参数按显存与模型调整)
vllm serve <model> --max-model-len 8192 --gpu-memory-utilization 0.9自建之前要算清楚三件事:显存够不够(模型权重 + KV 缓存)、并发上限是多少(超过就排队)、谁值班(GPU 节点故障、驱动升级、模型更新)。
三、Java 侧的接入要点
无论后端是哪种形态,这些问题都要在 Java 服务里解决。
3.1 超时与重试
模型调用的耗时分布与普通接口完全不同:p50 可能 1 秒,p99 可能 30 秒,长文本生成更久。
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(3)) // 连接快速失败
.build();
HttpRequest request = HttpRequest.newBuilder(uri)
.timeout(Duration.ofSeconds(60)) // 读超时要按生成长度设置
.POST(...)
.build();重试要非常克制:生成类请求不是幂等的,重试会产生两次计费和两份不同的结果。可以重试的只有明确的网络错误和 429(限流),并且要用指数退避。
3.2 流式响应
用户体验上,流式(SSE)几乎是必需的——首字延迟远小于整段生成时间。Java 侧要注意:
- 响应是长连接,占用的是连接而不是线程(用异步或虚拟线程),见 虚拟线程迁移;
- 中途断开要能取消上游请求,否则会白白消耗 token;
- 网关、负载均衡器的缓冲和超时配置要允许长连接与分块传输。
3.3 并发与成本
- 给模型调用单独的线程池或信号量,不要和普通业务共用,避免慢调用拖垮整个服务。
- 设置输入与输出的长度上限,这是成本控制最有效的手段。
- 按用户或租户限流,防止单个调用方耗尽配额。
- 记录每次调用的 token 数,成本要能按业务维度归因。
3.4 降级
模型服务不可用或超时的时候,业务要能继续:返回兜底文案、跳过智能环节走原有流程、或者把请求放进队列稍后处理。不要让一个「智能摘要」功能挂掉整个页面。
3.5 评测与灰度
换模型、改提示词都相当于一次发布,需要:
- 固定的评测集:几十到几百条真实样例加期望结果,每次变更跑一遍;
- 灰度:先放一小部分流量,对比关键指标(准确率、人工修正率、成本);
- 可回滚:模型和提示词都应该是配置,不是硬编码。
四、常见误区
- 「先选个框架把模型包成接口」:TorchServe 已归档;LLM 直接用 vLLM 或托管 API,自己写包装层的理由越来越少。
- 「自建一定更便宜」:要算上 GPU 常驻成本、运维投入和闲置率,低用量时托管通常更划算。
- 「把超时设长一点就不会失败」:长超时会占满连接与线程,要配合流式与取消。
- 「失败就重试」:生成类请求不幂等,重试意味着双倍成本和不一致的结果。
- 「模型部署是算法团队的事」:接入层的超时、限流、降级、成本归因都在服务端这一侧。
小结
模型部署对 Java 服务而言,本质上就是一个延迟高、成本按量计、偶尔不可用的下游依赖。选形态先看数据合规与用量:能用托管就用托管,必须自建就用 vLLM,本地开发用 Ollama。接入时把超时、流式、并发上限、成本归因和降级这五件事做全,剩下的模型细节可以交给算法侧。
Java 侧的工具调用与可控性设计,见 给 Java 服务接一个可控的 Agent。
参考资料