一次从"让 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. 每轮都调 LLM 做阶段分析 — 一个简单的"你好"也要走一遍 stage_chain 2. 每轮都做向量检索 — 即使客户只是在打招呼,也要查一遍向量库 3. 向量数据库持续膨胀 — 每轮对话都全量写入,存储和检索成本越来越高 4. 上下文不可控 — 随着对话进行,prompt 越来越长 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 提取关键信息,纯规则匹配,零消耗:
r'1[3-9]\d{9}' | ||
r'(?:我[叫是])(\S{2,4})' | ||
r'(\d+)\s*万' | ||
三、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 消耗
流程控制
五、MCP 集成:连接企业业务系统
V3 开始集成的 MCP(Model Context Protocol)在 V4 中继续发挥作用,让 AI 客服能直接调用企业现成的业务 API:

例如客户问"帮我查一下订单 ORD20240515001",系统自动调用 MCP 工具实时查询订单状态并回复。整个过程对客户透明,对开发者来说就是配置一个 MCP Server 地址的事。
六、总结与思考
V4 重构的核心哲学变化是:
V3:所有记忆进向量库,LLM 自由发挥V4:结构化状态控制流程,向量检索仅作补充
这个思路其实不只在 AI 客服场景有用,任何依赖 LLM 做多轮交互的系统都可以借鉴:
1. 能结构化的就不要丢给 LLM — 状态、信息、流程控制,能写规则的就别让 LLM 猜 2. LLM 适合做人做不到的事 — 理解意图、生成自然回复,而不是做状态管理 3. 按需使用资源 — 向量检索很贵,只在真正需要的时候调用 4. 可观测性比"智能"更重要 — 一个你能看懂它在干什么的系统,比一个黑盒但偶尔惊艳的系统更有价值
项目地址:Ai 智能客服系统 V4 大升级/
如果你也在做类似的 AI 客服或对话系统,欢迎交流讨论。下篇可以聊聊具体的使用效果和一些踩坑记录。
夜雨聆风