我在开发客服机器人和多轮对话系统时,最头疼的问题就是状态丢失。用户聊到一半换了个话题,回来之后系统完全不认识他了。这种体验糟糕透顶。后来我深入研究了LangGraph的状态管理机制,终于解决了这个痛点。今天我就手把手教大家如何用LangGraph构建一个能够"记住一切"的智能对话系统。

什么是LangGraph状态管理?

想象你在和一个人类客服对话。你说"我想查一下订单",他问"请问订单号是多少",你回答"刚才那个",他立刻就明白了。这就是状态管理的魔力——上下文被保留下来,对话是连续的、有记忆的。

传统的AI对话API每次请求都是独立的,就像问完一个问题就失忆了。而LangGraph通过状态管理,让AI能够记住之前的对话内容、用户信息、正在处理的任务进度等等。

实战项目:构建一个会"记住"你的智能助手

我们今天要构建的对话系统能够:

第一步:安装必要的库

我们先安装LangGraph和相关依赖。我推荐使用HolySheep AI作为后端API,原因后面会说。

pip install langgraph langchain-core langchain-holysheep

如果提示没有langchain-holysheep,用这个替代

pip install langchain-openai # 稍后配置base_url即可

第二步:配置HolySheep API

HolySheep AI的优势非常明显:人民币直付、汇率1:1无损兑换、国内直连延迟小于50ms。对于我们这种需要频繁调试的开发者来说,光是充值不用换汇这点就太省心了。

import os
from langchain_openai import ChatOpenAI

配置HolySheep API

os.environ["OPENAI_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY" os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"

初始化模型

llm = ChatOpenAI( model="gpt-4o-mini", # 性价比之选,输入$0.15/MTok,输出$0.60/MTok temperature=0.7 ) print("HolySheep API配置成功!当前模型:", llm.model_name)

第三步:定义状态结构

这是LangGraph最核心的概念。我们需要定义一个"状态字典",用来存放对话过程中所有需要记住的信息。

from typing import TypedDict, Annotated, Sequence
from langgraph.graph import StateGraph, END
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

定义我们对话系统的状态结构

class ConversationState(TypedDict): """对话系统的状态定义""" messages: Sequence[HumanMessage | AIMessage] # 对话历史 user_name: str | None # 用户名字 user_preferences: dict # 用户偏好设置 current_task: str | None # 当前正在处理的任务 task_history: list # 任务完成历史 # 下面这两个用于实现"短时记忆"功能 recent_entities: dict # 最近提到的实体(订单号、产品名等) context_summary: str # 对话上下文的摘要

创建状态图

workflow = StateGraph(ConversationState)

初始化状态的方法

def initialize_state(state: ConversationState, user_id: str) -> ConversationState: """为新用户创建初始状态""" return { "messages": [], "user_name": None, "user_preferences": {"language": "中文", "notifications": True}, "current_task": None, "task_history": [], "recent_entities": {}, "context_summary": f"用户 {user_id} 的新对话" } print("状态结构定义完成!这就是我们对话系统的'大脑'。")

第四步:构建核心处理节点

现在我们需要定义几个处理节点。每个节点负责特定的任务,状态在节点之间流转。这就是LangGraph的核心思想——用图的结构管理对话流程。

# 节点1:理解用户意图
def understand_intent(state: ConversationState) -> ConversationState:
    """分析用户消息,判断意图"""
    messages = state["messages"]
    last_message = messages[-1].content
    
    # 使用AI分析意图
    intent_prompt = f"""分析用户消息的意图:
    当前消息:{last_message}
    
    可选意图:
    - introduce: 用户想介绍自己(告诉名字)
    - query: 用户想查询信息
    - task: 用户想完成任务
    - greeting: 用户在打招呼
    - unclear: 无法判断
    
    只返回意图类型,不要其他内容。"""
    
    # 简单规则判断,实际项目中用更复杂的AI分析
    if "叫" in last_message or "名字" in last_message:
        intent = "introduce"
    elif "查" in last_message or "问" in last_message:
        intent = "query"
    else:
        intent = "greeting"
    
    # 提取关键实体
    if intent == "introduce" and "叫" in last_message:
        import re
        name_match = re.search(r'叫(\w+)', last_message)
        if name_match:
            name = name_match.group(1)
            state["user_name"] = name
            state["context_summary"] += f"\n用户介绍自己叫{name}"
    
    state["current_task"] = intent
    return state

节点2:生成回复

def generate_response(state: ConversationState) -> ConversationState: """根据当前状态生成AI回复""" messages = list(state["messages"]) # 构建系统提示 user_name = state.get("user_name") or "朋友" system_prompt = f"""你是一个友善的AI助手。 当前用户名叫{user_name}。 用户偏好:{state.get('user_preferences')} 当前任务:{state.get('current_task')} """ # 更新消息列表 messages.insert(0, SystemMessage(content=system_prompt)) # 调用AI生成回复 response = llm.invoke(messages) # 将AI回复加入历史 state["messages"] = state["messages"] + [response] # 更新上下文摘要 state["context_summary"] += f"\n最后AI回复:{response.content[:50]}..." return state

节点3:记忆整合

def consolidate_memory(state: ConversationState) -> ConversationState: """定期整合对话记忆,避免上下文过长""" if len(state["messages"]) > 20: # 简化消息历史,保留关键信息 recent = state["messages"][-10:] state["messages"] = recent state["context_summary"] += "\n[记忆已整合,保留最近10条对话]" return state print("三个核心节点已定义!它们会按顺序处理用户的每条消息。")

第五步:组装工作流

# 添加节点到工作流
workflow.add_node("understand", understand_intent)
workflow.add_node("respond", generate_response)
workflow.add_node("consolidate", consolidate_memory)

定义边(流程控制)

workflow.set_entry_point("understand") workflow.add_edge("understand", "respond") workflow.add_edge("respond", "consolidate") workflow.add_edge("consolidate", END)

编译工作流

app = workflow.compile() print("工作流编译成功!现在可以开始对话了。")

启动对话的辅助函数

def chat(user_id: str, user_message: str): """简单的对话函数""" # 初始化或获取用户状态 if user_id not in chat.sessions: chat.sessions[user_id] = initialize_state({}, user_id) state = chat.sessions[user_id] state["messages"] = state["messages"] + [HumanMessage(content=user_message)] # 运行工作流 result = app.invoke(state) chat.sessions[user_id] = result return result["messages"][-1].content

存储会话(实际项目用数据库)

chat.sessions = {}

测试对话

print("\n=== 第一次对话 ===") print("用户: 你好") print("AI:", chat("user001", "你好")) print("\n=== 第二次对话 - 介绍自己 ===") print("用户: 我叫小明") print("AI:", chat("user001", "我叫小明")) print("\n=== 第三次对话 - AI记住了吗?===") print("用户: 你还记得我叫什么吗?") print("AI:", chat("user001", "你还记得我叫什么吗?"))

常见报错排查

错误1:状态更新后数据丢失

# ❌ 错误写法:直接修改列表
state["messages"].append(new_message)  # 可能不生效

✅ 正确写法:重新赋值

state["messages"] = state["messages"] + [new_message]

或者使用LangGraph提供的Operator

from langgraph.constants import AddableUpdates def update_messages(state: ConversationState) -> ConversationState: return {"messages": [{"$add": [state["messages"], [new_message]]}]}

错误2:上下文长度超出限制

# ❌ 错误:无限累积消息
state["messages"] = state["messages"] + [new_message]  # 最终爆内存

✅ 正确:设置上限并摘要

MAX_MESSAGES = 50 if len(state["messages"]) > MAX_MESSAGES: # 调用AI生成摘要 summary_prompt = "用一句话总结以下对话:\n" + "\n".join([m.content for m in state["messages"][-20:]]) summary = llm.invoke([HumanMessage(content=summary_prompt)]) # 只保留系统消息和摘要 state["messages"] = [SystemMessage(content=f"对话摘要:{summary.content}")] state["context_summary"] = summary.content

错误3:API调用超时或连接失败

# ❌ 问题:使用默认超时设置
llm = ChatOpenAI(model="gpt-4o")

✅ 正确:配置合理的超时和重试

from langchain_openai import ChatOpenAI from langchain_core.callbacks import CallbackManager import time def create_robust_llm(): for attempt in range(3): try: return ChatOpenAI( model="gpt-4o-mini", timeout=30, # 30秒超时 max_retries=2, request_timeout=30 ) except Exception as e: if attempt < 2: wait = 2 ** attempt # 指数退避 time.sleep(wait) else: raise e

使用HolyShehe API的另一个好处:国内直连,延迟<50ms,超时很少见

错误4:状态条件判断逻辑错误

# ❌ 错误:直接修改传入的状态字典
def bad_node(state):
    if state["user_name"] is None:  # 第一次调用
        state["user_name"] = "新用户"  # 直接修改
    return state  # 返回的仍是同一个对象

✅ 正确:返回新字典或使用条件更新

def good_node(state): updates = {} if state.get("user_name") is None: updates["user_name"] = "新用户" # 在主逻辑中统一处理更新 return updates # 返回更新指令

或者在图定义中使用条件边

from langgraph.graph import START workflow.add_edge(START, "check_user") workflow.add_conditional_edges( "check_user", lambda state: "known_user" if state.get("user_name") else "new_user" )

进阶技巧:实现持久化状态存储

上面我们的状态存储在内存中,服务器重启就丢了。实际项目需要持久化存储。

# 使用Redis实现状态持久化
import redis
import json

redis_client = redis.Redis(host='localhost', port=6379, db=0)

def save_state(user_id: str, state: dict):
    """保存用户状态到Redis"""
    # 序列化时需要转换消息对象
    serializable_state = {
        "user_name": state.get("user_name"),
        "user_preferences": state.get("user_preferences"),
        "current_task": state.get("current_task"),
        "task_history": state.get("task_history", []),
        "recent_entities": state.get("recent_entities", {}),
        "context_summary": state.get("context_summary", "")
    }
    redis_client.setex(f"chat_state:{user_id}", 86400, json.dumps(serializable_state))

def load_state(user_id: str) -> dict:
    """从Redis加载用户状态"""
    data = redis_client.get(f"chat_state:{user_id}")
    if data:
        return json.loads(data)
    return None

在对话函数中使用

def chat_persistent(user_id: str, message: str): # 尝试加载已有状态 saved_state = load_state(user_id) if saved_state: state = saved_state else: state = initialize_state({}, user_id) state["messages"] = state.get("messages", []) + [HumanMessage(content=message)] result = app.invoke(state) # 保存更新后的状态 save_state(user_id, result) return result["messages"][-1].content

总结与实战建议

我自己在生产环境中用这套架构跑了半年多,最大感受是:状态管理做好了,对话系统的体验能提升好几个档次。用户不再需要反复解释自己的背景,系统能记住三个月前的偏好。

关键经验总结:

最后再推荐一下HolyShehe AI,我用它替代OpenAI官方API后,成本直接降了85%以上。GPT-4o-mini这个模型性价比很高,响应速度快,对于状态管理这种高频调用场景特别合适。

👉 免费注册 HolyShehe AI,获取首月赠额度

如果有任何问题,欢迎在评论区留言,我会尽力解答。下一期我们讲如何给对话系统添加工具调用能力,敬请期待!