乐于分享
好东西不私藏

Ai智能客服系统架构实现

Ai智能客服系统架构实现

一次从"让 LLM 自由发挥"到"用状态机精确控制"的架构重构实践

最近我对自研的 AI 智能客服系统做了一次比较彻底的架构重构——V4 版本。这次重构的核心变化是:从向量记忆驱动转向了状态机驱动。

V4架构图:

简单说就是:以前每个环节都丢给 LLM 去"自由发挥",现在用结构化状态 + 显式规则来控制流程。效果很直接——Token 消耗大幅降低、流程完全可控、可观测性也好了很多。

这篇文章分享一下这次重构的思路、做法和一些具体的代码实现。


一、回顾:前三代的演进

先快速回顾一下这个系统的演化路径:

V1:开天辟地

  • • 基于 LangChain + LangGraph + FAISS
  • • LLM 分析对话阶段,ReAct Agent 自动查知识库
  • • 多模型路由(简单任务 Haiku,复杂任务 Sonnet)
  • • Prompt Caching + 会话持久化

V2:记忆升级

  • • 引入 ChromaDB 向量数据库
  • • 更丰富的销售工具链

V3:全面能力

  • • 每次对话全量向量检索 + 全量写入
  • • 完整的情感分析(共情/推进/信息提供策略)
  • • MCP 协议集成企业系统(订单/库存/CRM/试驾)
  • • Redis 三级缓存、多模态记忆

V3 已经是一个功能相对完整的系统了,但也暴露出一些问题。

V3 的痛点

在实际使用中,V3 有几个比较突出的问题:

  1. 1. 每轮都调 LLM 做阶段分析 — 一个简单的"你好"也要走一遍 stage_chain
  2. 2. 每轮都做向量检索 — 即使客户只是在打招呼,也要查一遍向量库
  3. 3. 向量数据库持续膨胀 — 每轮对话都全量写入,存储和检索成本越来越高
  4. 4. 上下文不可控 — 随着对话进行,prompt 越来越长
  5. 5. 情感影响流程决策 — 情感分析结果参与策略选择,增加了不确定性

这些问题本质上都是一个根源:过度依赖 LLM + 向量记忆,缺乏结构化的状态管理。


二、V4 架构:状态机驱动的核心设计

V4 的核心理念很简单:关键信息进槽位,流程控制靠规则,向量检索只在需要时调用。

整个架构由五个新模块支撑:

SessionMemory(结构化信息)+ StateMachine(可预测流程)+ PromptBuilder(紧凑上下文)+ 按需向量检索(节省 60%+ 调用)+ 零 token 规则节点(slot 抽取 + 阶段决策)

1. SessionMemory:结构化会话内存

替代了 V3 中扁平的 dict 状态管理,将会话状态分为三层:

  • • intent:当前轮用户意图
  • • slots:关键信息槽位(车型、手机号、预算等)
  • • stage:当前对话阶段(由 StateMachine 驱动)
class SessionMemory:    def __init__(self, session_id: str, store=None):        self.session_id = session_id        self.intent: str = "chat"        self.slots: Dict[str, Any] = {}        self.stage: str = "start"        # 支持 Redis 持久化        if store:            stored = store.get(session_id)            if stored:                self.intent = stored.get("intent", "chat")                self.slots = stored.get("slots", {})                self.stage = stored.get("stage", "start")    def update_slot(self, key: str, value: Any):        self.slots[key] = value        self.save()  # 自动持久化到 Redis

每个方法的返回值都是清晰的结构化数据,不再需要从一大段对话历史中去"猜测"当前状态。

2. StateMachine:显式规则替代 LLM 阶段分析

V3 中每个用户输入都要调 LLM 来分析当前处于哪个阶段,V4 直接用规则搞定:

class StateMachine:    def transition(self, intent: str, slots: Dict) -> str:        if intent == "chat":            return self.stage  # 闲聊不改变阶段        if intent in ("product", "compare"):            return "recommend" if "model" in slots else "collect_info"        if intent == "test_drive":            required = ["name", "phone", "date", "model"]            return "end" if all(k in slots for k in required) else "collect_info"        if intent == "quote":            return "quote" if "model" in slots else "collect_info"        if intent == "closing":            return "end"        # 默认按阶段顺序推进        stage_order = {            "start": "collect_info",            "collect_info": "recommend",            "recommend": "quote",            "quote": "end",        }        return stage_order.get(self.stage, "collect_info")

五个阶段构成完整销售流程:

start → collect_info → recommend → quote → end

每个阶段有明确的进入条件和推进规则,100% 可预测,零 token 消耗。

3. PromptBuilder:严格控制上下文

V3 中 prompt 是内联拼接的,随着对话进行越来越长。V4 用结构化构建器来严格控制:

def build_prompt(user_input, session_state, retrieved_docs=None,                 recent_history=None, system_prompt=""):    # 1. 系统角色    # 2. 当前阶段指示(含 slots 信息)    # 3. 对话历史 — 最多 5 轮(V4 限制)    # 4. 知识检索结果 — 最多 3 条(V4 限制)    # 5. 当前用户输入    # 6. 回复要求

每个部分都有限制上限,prompt 不会无限膨胀。

4. 按需向量检索

V4 最关键的一个变化:只有在 recommend / quote 阶段才触发向量检索。

def need_retrieval(self, stage: str = None) -> bool:    return stage in ("recommend", "quote")

这意味着:

  • • 客户说"你好" → 不检索(开场对话)
  • • 客户自我介绍 → 不检索(直接提取 slots)
  • • 客户问"M7 智驾版多少钱" → 检索(quote 阶段)
  • • 客户对比 M9 和 M7 → 检索(recommend 阶段)

减少了约 60%+ 的向量检索调用。

5. Slot 抽取:零 token 规则匹配

用正则规则替代 LLM 提取关键信息,纯规则匹配,零消耗:

槽位
规则
示例
model
`r'\b(M5
M7
phone
r'1[3-9]\d{9}'
"电话 13800138000"
name
r'(?:我[叫是])(\S{2,4})'
"我叫张三"
budget
r'(\d+)\s*万'
"预算 30 万"
date
日期格式 + 今天/明天/后天
"明天试驾"

三、V4 的完整对话流程

一个完整的 V4 对话处理流程如下:

用户输入    ↓1️⃣ 意图分类(Haiku)           → intent = "compare"    ↓2️⃣ Slot 抽取(规则,零 token)  → model: M7, concern: 智驾    ↓3️⃣ 更新 SessionMemory          → intent + slots + stage    ↓4️⃣ StateMachine 决策(规则)    → stage = "recommend"    ↓5️⃣ 情感分析(简化)            → 仅记录标签    ↓6️⃣ 按需向量检索(仅此阶段触发)→ 检索 M7 智驾相关知识    ↓7️⃣ 历史摘要压缩(Haiku)    ↓8️⃣ PromptBuilder 构建 prompt   → 5 轮历史 + 3 条文档    ↓9️⃣ 回复生成(Sonnet + 工具)    ↓🔟 更新客户画像(Haiku)    ↓返回回复

关键节点模型分布:

  • • 9 个节点中,5 个用规则(零 token)
  • • 2 个用 Haiku(意图分类、历史摘要、客户画像)
  • • 仅 1 个用 Sonnet(回复生成 + 工具调用)

四、效果对比

Token 消耗

操作
V3
V4
阶段分析
每轮 Haiku(~50 tokens)
零 token(规则)
Slot 抽取
LLM 提取
零 token(规则)
向量检索
每轮 1 次
仅 2 个阶段触发,省 60%+
情感策略
每轮 LLM 参与
零 token(固定 normal)
上下文大小
不可控,持续增长
PromptBuilder 限制 ≤ 5 轮

流程控制

维度
V3(LLM 自由决策)
V4(状态机控制)
阶段跳转
黑盒,LLM 自行决定
规则精确跳转,100% 可预测
信息收集
依赖 LLM 记住
slots 结构化存储
知识检索
全部检索
仅 need_knowledge=True
错误率
不可预测
0%(规则不出错)

五、MCP 集成:连接企业业务系统

V3 开始集成的 MCP(Model Context Protocol)在 V4 中继续发挥作用,让 AI 客服能直接调用企业现成的业务 API:

例如客户问"帮我查一下订单 ORD20240515001",系统自动调用 MCP 工具实时查询订单状态并回复。整个过程对客户透明,对开发者来说就是配置一个 MCP Server 地址的事。


六、总结与思考

V4 重构的核心哲学变化是:

V3:所有记忆进向量库,LLM 自由发挥V4:结构化状态控制流程,向量检索仅作补充

这个思路其实不只在 AI 客服场景有用,任何依赖 LLM 做多轮交互的系统都可以借鉴:

  1. 1. 能结构化的就不要丢给 LLM — 状态、信息、流程控制,能写规则的就别让 LLM 猜
  2. 2. LLM 适合做人做不到的事 — 理解意图、生成自然回复,而不是做状态管理
  3. 3. 按需使用资源 — 向量检索很贵,只在真正需要的时候调用
  4. 4. 可观测性比"智能"更重要 — 一个你能看懂它在干什么的系统,比一个黑盒但偶尔惊艳的系统更有价值

项目地址:Ai 智能客服系统 V4 大升级/

如果你也在做类似的 AI 客服或对话系统,欢迎交流讨论。下篇可以聊聊具体的使用效果和一些踩坑记录。

相关学习资料