DDR4内存条PCB设计:从原理图拓扑到等长布线的信号完整性解析
2026/10/20 5:17:23
从零构建AI智能客服系统:基于Python的代码实现与避坑指南
第一次做智能客服,我最大的误区是以为“能回消息”就等于“智能”。
真正跑起来才发现,如果技术栈没选对,用户多问两句机器人就“失忆”,后台日志全是“意图识别置信度 0.2”的尴尬。
核心模块就两块:
规则引擎 vs 机器学习——我踩过的坑:
结论:demo 阶段先上规则,收集 2k 条真实语料再切模型,别一上来就“端到端大模型”,预算会哭。
我画的这张草图把链路拆成三段,方便排错:
distilbert-base-multilingual微调,3 epoch 就能到 0.92 F1。代码仓库结构(PEP8 命名,已跑 pylint 检查):
ai_bot/ ├── app.py # Flask 入口 ├── intent/ │ ├── model.py # 加载 Transformer │ └── predict.py # 意图预测 ├── dm/ │ └── state_tracker.py # 对话状态机 └── tests/ └── load_test.py # 压测脚本# -*- coding: utf-8 -*- from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch MODEL_PATH = "models/intent_cls" tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH) model = AutoModelForSequenceClassification.from_pretrained(MODEL_PATH) model.eval() # 关闭 dropout,提速 def predict_intent(text: str, threshold=0.7): """ 返回置信度最高的意图,若低于阈值则 fallback 到 chatgpt """ inputs = tokenizer(text, return_tensors="pt", max_length=64, truncation=True) with torch.no_grad(): logits = model(**inputs).logits probs = torch.softmax(logits, dim=-1) score, idx = torch.max(probs, dim=-1) if score.item() < threshold: return "unknown", round(score.item(), 3) id2label = model.config.id2label return id2label[idx.item()], round(score.item(), 3)class StateTracker: """ 极简槽位管理,支持追问与重置 """ def __init__(self, redis_client): self.r = redis_client def get_slots(self, session_id): data = self.r.hgetall(session_id) return {k.decode(): v.decode() for k, v in data.items()} if data else {} def update_slot(self, session_id, key, value, ex=900): self.r.hset(session_id, key, value) self.r.expire(session_id, ex) # 15 min 过期from flask import Flask, request, jsonify from intent.predict import predict_intent from dm.state_tracker import StateTracker import redis, uuid app = Flask(__name__) r = redis.Redis(host="localhost", port=6379, decode_responses=False) st = StateTracker(r) @app.route("/chat", methods=["POST"]) def chat(): data = request.json text = data["text"] session_id = data.get("session_id") or str(uuid.uuid4()) intent, score = predict_intent(text) slots = st.get_slots(session_id) # 规则分支示例:查订单 if intent == "query_order": if "order_id" not in slots: st.update_slot(session_id, "await_slot", "order_id") return jsonify({"reply": "请问您的订单号是多少?", "session_id": session_id}) else: order_id = slots["order_id"] return jsonify({"reply": f"订单 {order_id} 状态:已发货", "session_id": session_id}) # 兜底 return jsonify({"reply": "我还在学习中,请换种说法试试~", "session_id": session_id}) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)python -m venv venv && source venv/bin/activate pip install flask transformers torch redis gunicorn gunicorn -w 2 -k gevent app:app写完代码我就丢给测试同学,结果 50 并发直接 502。定位发现:
model.eval()提前跑一次 dummy 输入,把权重常驻 GPU。压测脚本(tests/load_test.py)
import gevent, time, requests from gevent import monkey; monkey.patch_all() url = "http://127.0.0.1:5000/chat" def req(): r = requests.post(url, json={"text": "我的订单到哪了"}) assert r.status_code == 200 tasks = [gevent.spawn(req) for _ in range(1000)] start = time.time(); gevent.joinall(tasks); print("QPS", 1000/(time.time()-start))/metrics暴露的“意图分布、平均响应时间”。把这套骨架跑通后,你会发现机器人还是“知识有限”——用户问“超出 FAQ 的新业务”,它只能回“学习中”。
如果让你来迭代,你会:
欢迎 fork 代码后动手试试,把遇到的坑丢在评论区,一起把智能客服做成“不智障”的客服。