AI编程助手Codex的Record and Replay插件:从“演示一遍”到自动化脚本的实践与思考
2026/7/28 6:01:05
去年双十一,我们给某电商客户做智能客服升级,峰值 QPS 飙到 2800,老系统直接“罢工”:
一句话:传统“同步阻塞 + 重量级模型”的流水线,扛不住企业级高并发。
我们把同一台 16 核 32G 机器分别部署两套架构,用 wrk 压测 200 并发连接,结果如下:
| 指标 | 同步阻塞(SpringBoot+Tomcat) | 异步微服务(FastAPI+Uvicorn) |
|---|---|---|
| 峰值 QPS | 420 | 1 350 |
| P99 延迟 | 2.1 s | 0.38 s |
| CPU 利用率 | 35% | 78% |
| 内存占用 | 2.4 GB | 1.1 GB |
结论:异步事件循环 + 微服务拆分,能把 I/O 等待时间吃满,硬件利用率直接翻倍。
再看模型侧:BERT-base 与 DistilBERT 在 ONNX Runtime 下的实测(batch=8,seq_len=128):
| 模型 | 推理耗时 | 内存 | 准确率(客户 DS) |
|---|---|---|---|
| BERT-base | 87 ms | 1.3 GB | 98.4% |
| DistilBERT | 31 ms | 0.6 GB | 97.9% |
0.5% 的精度换 3 倍速度,业务方当场拍板:“上!”
# quantize.py from pathlib import Path from onnxruntime.quantization import quantize_dynamic, QuantType def quantize_onnx(src: Path, dst: Path) -> None: """ 动态量化:仅权重量化到 int8,激活保持 fp32,精度损失最小。 时间复杂度:O(N) 逐层遍历,N 为参数量。 """ quantize_dynamic( model_input=str(src), model_output=str(dst), weight_type=QuantType.QInt8, optimize_model=True ) print(f"量化完成:{src.name} -> {dst.name}") if __name__ == "__main__": quantize_onnx(Path("distilbert.onnx"), Path("distilbert.q8.onnx"))量化后模型体积 330 MB,推理耗时 31 ms -> 17 ms,GPU 直接下岗。
# cache.py import hashlib import json from typing import Optional import redis r = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True) INTENT_TTL = 360预热阶段先给 5 分钟,后续根据 LRU 调优。 def intent_key(text: str) -> str: return "intent:" + hashlib.md5(text.encode()).hexdigest() def get_or_cache(text: str, infer_func) -> str: key = intent_key(text) val = r.get(key) if val is None: # 双重校验锁,防缓存击穿 lock_key = f"lock:{key}" if r.set(lock_key, 1, nx=True, ex=5): val = infer_func(text) r.set(key, json.dumps(val), ex=INTENT_TTL) r.delete(lock_key) else: # 等待 50ms 后重试 import time time.sleep(0.05) return get_or_cache(text, infer_func) else: val = json.loads(val) return val上线首日缓存命中率 42%,P99 再降 120 ms。
# tasks.py from celery import Celery from pydantic import BaseModel app = Celery("nlp", broker="redis://127.0.0.1:6379/0") class QARequest(BaseModel): uid: str query: str @app.task(bind=True) def async_infer(self, req: dict) -> dict: try: ans = onnx_model(req["query"]) return {"uid": req["uid"], "answer": ans} except Exception as exc: # 失败自动重试,最多 3 次 raise self.retry(exc=exc, countdown=3, max_retries=3)FastAPI 网关层直接返回“处理中”,前端轮班轮询,用户体验丝滑。
从图里可以直观看到:
asyncio.Lock()里,避免多协程同时写 Redis Hash。-> Nonetry/except并打日志当用户一次甩 2k 字说明书提问,Transformer 的 O(n²) 注意力仍是瓶颈。可继续探索:
欢迎你在评论区聊聊自己踩过的长文本优化坑,一起把智能客服做得又快又准。
把代码拉到本地,跑通quantize.py只需 5 分钟;再配个缓存,QPS 翻倍的快乐你也能拥有。祝调优顺利,少掉几根头发。