LangGraph开发-多轮对话问答机器人

发布时间:2026-04-09 22:58:16编辑:123阅读(8)

    LangGraph中多轮对话实现方法

    将大模型接入到LangGraph工作流程中,并允许动态消息处理以及与模型的交互。

    大模型应用都是接受消息列表作为输入,就像LangChain中的ChatModel,需要接收Message对象列表作为输入。这些消息有多种形式,例如HumanMessage(用户输入)或AIMessage(大模型响应)。这种消息格式其实就与我们之前介绍的StateGraph(dict)结构有一些区别。


    因此对于消息序列格式的state,一种更简单的方法就是使用LangGraph预构建的add_messages函数,这个更高级的状态所实现的是:对于全新的消息,它会附加到现有列表,同时它也会正确处理现有消息的更新。

    代码如下:

    from typing import Annotated
    from typing_extensions import TypedDict
    from langgraph.graph import StateGraph,START,END
    from langgraph.graph.message import add_messages
    from langchain_ollama import ChatOllama
    
    class State(TypedDict):
        messages: Annotated[list, add_messages]
    
    graph_builder = StateGraph(State)
    
    model = ChatOllama(
        model="qwen3:8b",
        temperature=0,
        top_p=0.95,
    )
    
    def chat_bot(state: State):
        response = model.invoke(state["messages"])
        return {"messages": [response]}
    
    # 添加节点
    graph_builder.add_node("chat_bot", chat_bot)
    
    # 添加边
    graph_builder.add_edge(START, 'chat_bot')
    graph_builder.add_edge( 'chat_bot', END)
    
    graph = graph_builder.compile()
    
    final_state = graph.invoke({"messages": ["你好,你是谁"]})
    print(final_state['messages'][-1].content)
    
    with open("graph4.png", "wb") as f:
        f.write(graph.get_graph(xray=True).draw_mermaid_png())

    运行结果:

    你好!我是通义千问,由通义实验室研发的超大规模语言模型。我能够帮助你回答问题、创作文字、编程、分析数据等等。如果你有任何需要帮助的地方,欢迎随时告诉我!😊


    结构图:

    image.png

    这个图的基本逻辑是:第一个节点调用大模型并生成一个输出,该输出是一个AIMessage对象类型,然后,第二个节点直接将前一个节点的AIMessage提取为具体的JSON格式,完成JSON的解析。


    langgraph多消息请求:

    from typing import Annotated
    from typing_extensions import TypedDict
    from langgraph.graph import StateGraph,START,END
    from langgraph.graph.message import add_messages
    from langchain_ollama import ChatOllama
    from langchain_core.messages import AIMessage,HumanMessage
    
    class State(TypedDict):
        messages: Annotated[list, add_messages]
    
    graph_builder = StateGraph(State)
    
    model = ChatOllama(
        model="qwen3:8b",
        temperature=0,
        top_p=0.95,
    )
    
    def chat_bot(state: State):
        response = model.invoke(state["messages"])
        return {"messages": [response]}
    
    # 添加节点
    graph_builder.add_node("chat_bot", chat_bot)
    
    # 添加边
    graph_builder.add_edge(START, 'chat_bot')
    graph_builder.add_edge( 'chat_bot', END)
    
    graph = graph_builder.compile()
    
    messages_list = [
        HumanMessage(content="你好,我叫张三,好久不见"),
        AIMessage(content="你好呀,我是CC,一名乐于助人的AI助手,很高兴认识你"),
        HumanMessage(content="你还记得我叫什么名字吗?")
    ]
    
    final_state = graph.invoke({"messages": messages_list})
    print(final_state['messages'][-1].content)
    
    with open("graph4.png", "wb") as f:
        f.write(graph.get_graph(xray=True).draw_mermaid_png())

    运行结果

    当然记得!你叫张三,上次见面已经很久了,真是想念啊!最近过得怎么样呀?有什么我可以帮你的吗?


    langgraph多轮对话输入请求

    from typing import Annotated
    from typing_extensions import TypedDict
    from langgraph.graph import StateGraph,START,END
    from langgraph.graph.message import add_messages
    from langchain_ollama import ChatOllama
    from langchain_core.messages import AIMessage,HumanMessage
    
    class State(TypedDict):
        messages: Annotated[list, add_messages]
    
    graph_builder = StateGraph(State)
    
    model = ChatOllama(
        model="qwen3:8b",
        temperature=0,
        top_p=0.95,
    )
    
    def chat_bot(state: State):
        response = model.invoke(state["messages"])
        return {"messages": [response]}
    
    # 添加节点
    graph_builder.add_node("chat_bot", chat_bot)
    
    # 添加边
    graph_builder.add_edge(START, 'chat_bot')
    graph_builder.add_edge( 'chat_bot', END)
    
    graph = graph_builder.compile()
    
    messages_list = [
    ]
    
    while True:
        try:
            user_input = input("用户提问:")
            if user_input.lower() in ['exit']:
                print("退出,下次再见!")
                break
            messages_list.append(HumanMessage(content=user_input))
            final_state = graph.invoke({"messages": messages_list})
            print("小智:", final_state["messages"][-1].content)
            messages_list.append(final_state["messages"][-1])
            messages_list = messages_list[-50:]
        except:
            break

    运行结果:

    用户提问:我是张三

    小智: 哦,张三啊!很高兴认识你!今天有什么想聊的吗?或者需要帮忙的?我在这里陪着你呢~

    用户提问:你能做什么

    小智: 我是一个大型语言模型,可以帮你做很多事情!以下是一些我擅长的领域:


    1. **知识问答**:解答各种学科、文化、科技等方面的问题。

    2. **创作辅助**:帮你写故事、诗歌、剧本、邮件、文案等。

    3. **逻辑推理**:解决数学题、编程问题、谜题等需要逻辑思考的任务。

    4. **多语言翻译**:支持中英日韩等多国语言的互译。

    5. **学习辅导**:提供学习建议、知识点总结、考试复习等帮助。

    6. **日常对话**:陪你聊天、分享观点、讨论感兴趣的话题。

    7. **代码生成**:根据需求生成或解释编程代码(如Python、Java等)。

    8. **娱乐互动**:玩文字游戏、猜谜、讲故事等。


    如果你有具体需求,可以告诉我,我会尽力帮你! 😊

    用户提问:我叫什么

    小智: 你叫张三!😊 之前你已经告诉我了,我这边都记着呢~ 有什么需要帮忙的吗?或者想聊点什么?

    用户提问:exit

    退出,下次再见!


    借助MemorySaver高效搭建多轮对话机器人

    MemorySaver的核心功能

    1 短期记忆(线程级记忆)MemorySaver为每个thread_id保存和恢复对话状态(State),实现在同一会话中历史上下文记忆。

    2 状态持久化   在每个节点运行后,State会自动存储;再次调用时,如果使用相同的thread_id,MemorySaver会恢复此前保存的状态,无需手动传递历史信息。

    3 多会话隔离    通过不同的thread_id可实现会话隔离,允许多个用户并发交互且各自的对话互不干扰。

    4 图状态快照与恢复   不仅包括对话历史,还保存整个工作流状态,可用于错误恢复、时间旅行、断点续跑、Human-in-the-loop等高级场景。

    示例代码:

    from typing import Annotated
    from typing_extensions import TypedDict
    from langgraph.graph import StateGraph,START,END
    from langgraph.graph.message import add_messages
    from langchain_ollama import ChatOllama
    from langgraph.checkpoint.memory import MemorySaver
    
    # 定义状态类(会自动合并messages)
    class State(TypedDict):
        messages: Annotated[list, add_messages]
    
    # 初始化模型
    model = ChatOllama(
        model="qwen3:8b",
        temperature=0,
        top_p=0.95,
    )
    
    # 定义聊天节点
    def chatbot(state: State) -> State:
        reply = model.invoke(state["messages"])
        return {'messages': [reply]}
    
    # 构建带MemorySaver的图
    builder = StateGraph(State)
    builder.add_node('chatbot', chatbot)
    builder.add_edge(START, 'chatbot')
    builder.add_edge('chatbot', END)
    memory = MemorySaver()
    graph = builder.compile(checkpointer=memory)
    
    # 运行多轮对话,使用相同thread_id实现记忆
    thread_config = {"configurable":{"thread_id":"session_10"}}
    
    # 第一轮对话
    state1 = graph.invoke({"messages":[{"role":"user", "content":"我叫张三"}]}, config=thread_config)
    print(state1["messages"][-1].content)
    
    # 第二轮对话
    state2 = graph.invoke({"messages":[{"role":"user", "content":"我叫什么"}]}, config=thread_config)
    print(state2["messages"][-1].content)
    
    # 使用不同的thread_id,会开启全新对话
    state3 = graph.invoke({"messages":[{"role":"user", "content":"我叫什么"}]}, 
    config={"configurable":{"thread_id":"session_2"}})
    print(state3["messages"][-1].content)
    
    # 查看记忆
    latest = graph.get_state(thread_config)
    print(latest.values['messages']) # 包含全部轮次对话

    运行结果:

    你好,张三!很高兴认识你。有什么我可以帮你的吗?是想讨论某个话题,还是需要解决某个问题?随时告诉我哦! 😊

    你叫张三!😊 有什么我可以帮你的吗?

    你好!我是通义千问,你可以叫我Qwen。有什么问题或需要帮助的地方吗?😊

    [HumanMessage(content='我叫张三', additional_kwargs={}, response_metadata={}, id='e0301ee9-3630-41d5-a177-0ebb241bc923'), AIMessage(content='你好,张三!很高兴认识你。有什么我可以帮你的吗?是想讨论某个话题,还是需要解决某个问题?随时告诉我哦! 😊', additional_kwargs={}, response_metadata={'model': 'qwen3:8b', 'created_at': '2026-04-09T14:55:36.262431513Z', 'done': True, 'done_reason': 'stop', 'total_duration': 7435033223, 'load_duration': 3240815798, 'prompt_eval_count': 14, 'prompt_eval_duration': 37374857, 'eval_count': 169, 'eval_duration': 4069471189, 'logprobs': None, 'model_name': 'qwen3:8b', 'model_provider': 'ollama'}, id='lc_run--019d72bd-bd4c-79a1-bf8c-2abd404751c3-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 14, 'output_tokens': 169, 'total_tokens': 183}), HumanMessage(content='我叫什么', additional_kwargs={}, response_metadata={}, id='df1a725d-ddbc-4d1b-8ca1-eb0850d1f26c'), AIMessage(content='你叫张三!😊 有什么我可以帮你的吗?', additional_kwargs={}, response_metadata={'model': 'qwen3:8b', 'created_at': '2026-04-09T14:55:41.274219069Z', 'done': True, 'done_reason': 'stop', 'total_duration': 5006213719, 'load_duration': 82059554, 'prompt_eval_count': 60, 'prompt_eval_duration': 50574398, 'eval_count': 201, 'eval_duration': 4812387113, 'logprobs': None, 'model_name': 'qwen3:8b', 'model_provider': 'ollama'}, id='lc_run--019d72bd-d824-77b2-84c4-4e7b4c34b6f3-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 60, 'output_tokens': 201, 'total_tokens': 261})]

关键字

上一篇: LangGraph开发-条件分支/循环图实战

下一篇: 没有了