NLP从玩具到能打:我的性能调优血泪史
过去半年我基本活在Cursor里。真正让我从“用AI写代码”变成“离不开AI写代码”的,是公司接的一个智能客服项目——对电商售后工单做自动分类和情绪识别,日均80万条。
技术选型会上我拍胸脯说用GLM-4微调,一个礼拜出demo。结果推理延迟3.7秒一条,批处理80万条要跑6小时。那段时间我天天改代码,硬是把系统从“跑得动”调到“跑得爽”。今天重点聊性能优化这条线。
第一刀:不要一上来就微调
真实业务里微调成本极高。我一开始用GLM-4做LoRA微调,12万条标注数据,单卡A100跑一个epoch要40分钟,调参三天F1才从0.71提到0.78。后来我先用零样本推理跑测试集,把完全分错的样本拉出来看。
结果发现60%的错误集中在两类:“换货申请”和“退货申请”这种语义边界模糊的短文本,以及方言或错别字写的投诉。这不是模型能力问题,是数据分布问题。我后来只挑了三万条高置信度难例做继续预训练,剩下靠提示词工程和规则兜底。F1干到0.83,训练时间从三天缩到四小时。
教训:先搞清楚瓶颈在模型能力还是数据质量,别拿微调当万能药。
第二刀:推理延迟的三大杀手
微调完上线,3.7秒延迟拆解如下:
| 环节 | 优化前 | 优化后 |
|---|---|---|
| 预处理与分词 | 430ms | 85ms |
| 模型前向推理 | 2900ms | 420ms |
| 后处理与结构化输出 | 370ms | 90ms |
预处理原来用通用分词器,对SKU编码、emoji、URL处理稀烂。换成自定义tokenizer规则,用Kotlin重写预处理管线,正则全部预编译,延迟砍掉80%。
模型推理是大头。GLM-4默认FP32加载,换FP16延迟直接减半。然后上vLLM做推理引擎,开连续批处理。vLLM的PagedAttention把KV cache管理得明明白白,并发起来单条平均延迟降到400ms左右。坑:vLLM对GLM系支持早期有兼容问题,长文本下偶发CUDA OOM,靠限制max_model_len到2048、gpu_memory_utilization设0.85才稳定。
后处理原来用LangChain的OutputParser,每次跑完整解析逻辑。批处理场景下开销不小,直接换成自己写的Kotlin解析器,正则加状态机,90ms搞定。
第三刀:批处理的流水线设计
单条延迟降下来后,批处理80万条还是慢。核心思路是异步解耦。
原流程:读数据→预处理→推理→写结果,串行。改成:Kafka做缓冲,预处理和推理分开部署。预处理服务用Kotlin协程并发,单pod每秒处理3000条。推理服务用vLLM异步接口,batch size动态调整,GPU利用率从35%拉到85%以上。
LangChain在原型阶段好用,但性能敏感场景下抽象层就是累赘。生产环境只保留Prompt管理和少量工具调用,核心推理链路全部绕过LangChain直接调vLLM的HTTP接口。框架是给你省时间的,不是给你省性能的。
第四刀:AI Agent的引入与成本控制
产品经理加需求:自动生成回复建议。我用LangChain搭了ReAct Agent,让模型自己决定查订单数据库、调物流接口还是直接生成回复。
Agent的延迟和成本控制更难。最坑的是模型有时陷入循环调用,反复查同一接口。我加了max_iterations=5的硬限制,工具调用结果做缓存,同一订单号10分钟内不重复查询。Token消耗从平均4200降到1800。
成本方面,高频场景(查物流、申请退款)回复模板化,只有低置信度case走Agent推理。整体API成本降65%,延迟稳定在1.2秒以内。
总结:性能优化是分层的
最深的感受:性能优化不是调参,是架构决策。 每层优化空间有限,得知道瓶颈在哪:
- 数据层:清洗和难例挖掘比盲目扩充数据量更有效
- 模型层:量化、推理引擎、批处理策略是延迟大头
- 工程层:预处理管线、异步架构、缓存策略决定吞吐上限
- 产品层:规则兜底和模板化大幅降低不必要的模型调用
现在系统跑在阿里云ACK上,三个推理pod加两个预处理pod,日均处理120万条工单,单条平均延迟380ms,GPU成本每天400块以内。
如果你也在搞NLP落地,建议先把性能基准测出来再动手。别像我一样,demo做得飞起,上线被延迟教做人。Cursor再强,也救不了没想清楚的架构。

评论 0