2026/4/18 7:16:40
网站建设
项目流程
行业门户网站解决方案,网站建设 教程,沈阳网站制作公司和服务器,携程旅行的网站建设背景痛点#xff1a;电商客服接口的三座大山
电商大促 0 点瞬间流量是日常的 30 倍#xff0c;智能客服接口必须在 500 ms 内返回#xff0c;否则用户直接转人工#xff0c;成本翻倍。
SLA 99 %#xff1a;大促 1 h 内不可用时间 ≤ 36 s#xff0c;任何一次 Full GC 或…背景痛点电商客服接口的三座大山电商大促 0 点瞬间流量是日常的 30 倍智能客服接口必须在 500 ms 内返回否则用户直接转人工成本翻倍。SLA 99 %大促 1 h 内不可用时间 ≤ 36 s任何一次 Full GC 或慢 SQL 都会超标。多轮状态保持用户问“优惠券”→“退货”→“优惠券还能用吗”对话 ID 跨 3 次请求状态不能丢。突发流量秒杀入口 5 s 内涌入 10 w 并发线程池被打爆后整站雪崩。技术对比同步、异步、长连接怎么选方案优点缺点适用场景同步 REST开发简单调试直观线程阻塞高并发下 CPU 空转低频后台查询异步队列Celery/Kafka削峰填谷可重试链路长排障难订单、物流等可延迟回答长连接 WebSocket全双工低延迟连接管理复杂内存占用高网页端实时对话短连接 HTTP/2多路复用兼容 CDN仍有 TLS 握手开销App 端主流方案结论C 端问答用短连接 异步队列兜底B 端坐席后台用 WebSocket 推送减少轮询。核心实现FastAPI Redis 状态管理以下示例基于 Python 3.11单文件即可跑通含 JWT 鉴权、异步推理、状态缓存。1. 项目结构ai-service/ ├─ main.py # FastAPI 入口 ├─ model.py # 业务模型 ├─ redis_pool.py # 连接池 └─ settings.py # 配置2. 依赖安装pip install fastapi[all] redis httpx python-jose3. JWT 鉴权工具时间复杂度 O(1)# settings.py from datetime import datetime, timedelta from jose import jwt SECRET dev_secret ALG HS256 def create_token(uid: str) - str: payload {sub: uid, exp: datetime.utcnow() timedelta(hours2)} return jwt.encode(payload, SECRET, algorithmALG)4. Redis 连接池全局复用# redis_pool.py import aioredis from contextlib import asynccontextmanager POOL aioredis.ConnectionPool.from_url( redis://127.0.0.1:6379/0, max_connections50, # 根据容器规格调整 retry_on_timeoutTrue ) asynccontextmanager async def get_redis(): redis aioredis.Redis(connection_poolPOOL) try: yield redis finally: await redis.close() # 归还连接池非断开5. 对话状态模型# model.py from pydantic import BaseModel, Field from typing import List, Optional class Message(BaseModel): role: str # user / bot content: str class ChatReq(BaseModel): uid: str text: str dialog_id: Optional[str] Field(None, description为空时后端生成) class ChatResp(BaseModel): dialog_id: str answer: str cost_ms: int6. FastAPI 异步接口# main.py import uuid, time, httpx from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from model import ChatReq, ChatResp from redis_pool import get_redis from settings import create_token app FastAPI(titleE-commerce AI-CS) security HTTPBearer() async def verify_token(cred: HTTPAuthorizationCredentials Depends(security)): from jose import jwt try: payload jwt.decode(cred.credentials, settings.SECRET, algorithms[settings.ALG]) return payload[sub] except Exception: raise HTTPException(status_code401, detailInvalid token) app.post(/chat, response_modelChatResp) async def chat(req: ChatReq, uid: str Depends(verify_token)): start time.time() dialog_id req.dialog_id or uuid.uuid4().hex # 冲突概率 2^-122可忽略 async with get_redis() as redis: # 拉取历史 key fdlg:{dialog_id} history: List[Message] [] raw await redis.lrange(key, 0, -1) for item in raw: history.append(Message.parse_raw(item)) # 调第三方大模型异步 answer await call_llm(req.text, history) # 见下 # 写回缓存设置 30 min 过期 pipe redis.pipeline() pipe.lpush(key, Message(roleuser, contentreq.text).json()) pipe.lpush(key, Message(rolebot, contentanswer).json()) pipe.expire(key, 1800) await pipe.execute() cost int((time.time() - start) * 1000) return ChatResp(dialog_iddialog_id, answeranswer, cost_mscost) async def call_llm(text: str, history: List[Message]) - str: 调用外部大模型带重试 url https://api.llm.vendor/v1/completions headers {Authorization: Bearer YOUR_KEY} payload { prompt: format_prompt(text, history), max_tokens: 200, temperature: 0.3 } async with httpx.AsyncClient(timeout5) as client: for attempt in range(1, 4): # 最多 3 次 try: r await client.post(url, jsonpayload) r.raise_for_status() return r.json()[choices][0][text].strip() except Exception as e: if attempt 3: return 系统繁忙请稍后再试 await asyncio.sleep(0.5 * attempt)7. 运行uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4性能优化把 QPS 从 500 拉到 3000压测环境4C8G 容器单副本FastAPI workers4。使用 locust200 并发用户持续 5 min。优化前后对比阶段平均 RTP99 RTQPSCPU初始同步 短连接380 ms1.2 s52095 %① 连接池复用220 ms600 ms110080 %② 异步 LLM150 ms400 ms180075 %③ Redis Pipeline 本地缓存热点答案90 ms220 ms320065 %关键参数# httpx 连接池 limits httpx.Limits(max_keepalive20, max_connections100) # Redis 池见上文max_connections50 # FastAPI 层开启 gzip from fastapi.middleware.gzip import GZipMiddleware app.add_middleware(GZipMiddleware, minimum_size500)本地缓存对“发货时间”“会员等级”等命中率 5 % 的 query直接缓存 JSONTTL 60 s减少 30 % Redis 流量。避坑指南三个血与泪的教训对话 ID 冲突uuid.uuid4 重复概率极低但日志里仍出现“串号”。根因是 Nginx 转发时丢失了大小写导致前端生成 ID 被截断。→ 统一后端生成前端只读ID 限长 32 位十六进制正则校验^[0-9a-f]{32}$。第三方重试策略指数退避容易把瞬时故障拖成长尾。→ 采用“线性退避 熔断”失败 3 次熔断 10 s同时返回兜底文案避免用户空等。敏感信息过滤用户会上传订单截图含手机号模型可能原样返回。→ 接入正则脱敏 人名库命中即替换为*并记录审计日志正则耗时 ≤ 1 ms对 RT 影响可忽略。生产 checklist日志统一 trace-id方便跨 Redis、LLM 链路追踪。限流令牌桶 500/s超量返回 429前端弹“客服繁忙”。监控Prometheus 采集chat_qps、chat_latency_p99告警阈值 P99 500 ms。灰度按 UID 尾号灰度 5 %观察 30 min 无异常再全量。思考题如何设计分级降级策略当 LLM 侧 503 大面积报错时你会先降级到检索式 FAQ还是直接返回“人工客服稍后联系”欢迎分享你的分级条件、开关实现与数据回流方案。