AI微信客服的对话状态机:多轮上下文怎么存
单轮问答不难,难的是多轮对话。用户先说"我要退货",机器人问"订单号",用户回"123456"——机器人要知道这个"123456"是订单号,而不是凭空理解。这就是对话状态机要解决的问题:记住用户当前在哪一步、收集了哪些信息、下一步该问什么。
参考资料WTAPI框架
接口路径与字段以api文档weiti.apifox.cn 为准。
一、为什么不能只靠LLM上下文
直接把所有历史消息丢给LLM让它自己理解,看似简单,实际有三个问题:token成本随对话轮数线性增长;LLM可能忘记或篡改早期收集的字段;无法精确控制业务流程(比如订单号必须收集齐才能退货)。
正确做法是用显式状态机管理业务流程,LLM只负责理解单轮输入。
二、状态机的数据结构
每个会话维护一个状态对象,按 instanceId:fromWxid 存储:
import json, time
def get_state(instance_id, from_wxid):
raw = redis.get(f"state:{instance_id}:{from_wxid}")
return json.loads(raw) if raw else None
def save_state(instance_id, from_wxid, state, ttl=1800):
state["updated_at"] = int(time.time())
redis.setex(
f"state:{instance_id}:{from_wxid}",
ttl,
json.dumps(state, ensure_ascii=False),
)
def init_state():
return {
"intent": None, # 当前意图,如 refund
"step": None, # 当前步骤,如 ask_order_id
"slots": {}, # 已收集的字段
"history": [], # 对话历史(供LLM参考)
}
三、状态流转逻辑
以退货流程为例,定义状态流转:
FLOWS = {
"refund": {
"steps": [
{"name": "ask_order_id", "slot": "order_id",
"prompt": "请提供订单号"},
{"name": "ask_reason", "slot": "reason",
"prompt": "请说明退货原因"},
{"name": "confirm", "slot": None,
"prompt": "信息已确认,是否提交?"},
]
}
}
def handle_message(instance_id, from_wxid, content):
state = get_state(instance_id, from_wxid)
# 首次对话:识别意图
if state is None:
intent = detect_intent(content) # 关键词或LLM分类
if intent in FLOWS:
state = init_state()
state["intent"] = intent
state["step"] = FLOWS(intent)["steps"][0]["name"]
save_state(instance_id, from_wxid, state)
return FLOWS[intent]["steps"][0]["prompt"]
return default_reply(content)
# 流程中:把当前输入填入槽位
flow = FLOWS[state["intent"]]
current_step = next(s for s in flow["steps"] if s["name"] == state["step"])
if current_step["slot"]:
state["slots"][current_step["slot"]] = content
# 推进到下一步
idx = flow["steps"].index(current_step)
if idx + 1 < len(flow["steps"]):
state["step"] = flow["steps"][idx + 1]["name"]
save_state(instance_id, from_wxid, state)
return flow["steps"][idx + 1]["prompt"]
else:
# 流程结束:调用业务接口
result = submit_refund(state["slots"])
redis.delete(f"state:{instance_id}:{from_wxid}")
return f"退货申请已提交,单号{result}"
四、三个工程细节
槽位抽取:用户可能在一条消息里给多个字段(“订单号123,因为质量差”),用LLM做一次槽位抽取比逐轮问更高效,但要校验抽取结果。
状态超时:状态设TTL(如30分钟),超时自动清空。避免用户中途离开后,隔几天回来机器人还在追问退货原因。
中断与切换:用户在流程中问了无关问题(“你们几点下班”),要能识别并临时跳出流程回答,回答完回到原步骤,不要把闲聊内容塞进槽位。
五、LLM的角色边界
状态机管流程,LLM管两件事:意图识别(用户想干什么)和槽位抽取(从这句话里提取字段)。业务推进、字段校验、接口调用全部由代码控制。这样既保留了自然语言理解的灵活性,又保证了业务流程的确定性。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)