目录
3.1 环境准备
对于这一部分,我们需要使用langchain_tavily.Tavily搜索工具类来获取实时/联网信息,以及使用langgraph.checkpoint.memory模块中的MemorySaver类来实现记忆功能。
1. 核心依赖安装
本案例机器人的工具功能依赖LangChain官方集成包langchain-tavily,记忆功能依赖的是LangGraph框架本身,而Qwen-plus的调用可借助LangChain的兼容层实现,无须额外安装专属依赖,只需安装以下核心包即可完成环境搭建(兼容Qwen-plus调用与记忆功能):
# 安装核心依赖(LangGraph+Qwen-plus调用+环境变量管理)
pip install langgraph langchain-openai langchain-tavily python-dotenv
2. 环境配置(Qwen-plus专属)
Qwen-plus的调用需要配置阿里云通义千问的API密钥,为保证密钥安全,我们采用`.env`文件进行环境变量配置,避免密钥硬编码在代码中,具体步骤如下:
(1)在项目根目录新建.env文件。
(2)在.env文件中添加Qwen-plus的API密钥配置,内容如下:
# 通义千问Qwen-plus API密钥(从阿里云控制台获取)
DASHSCOPE_API_KEY=你的通义千问API密钥
补充说明一下Qwen-plus API密钥获取路径—登录阿里云通义千问控制台→进入“API-KEY管理”→创建并复制DASHSCOPE_API_KEY(注意区分个人版与企业版密钥,个人版可满足开发调试需求)。
3. 核心概念前置(重构适配Qwen-plus)
为了理解本章案例围绕机器人的工具、记忆与Qwen-plus大模型调用的协同逻辑,需先明确以下核心概念,避免混淆技术边界。
- TavilySearch(Tavily搜索):TavilySearch 本质上是一个专为 AI Agent 和大模型(LLM)设计的搜索引擎 API。它不像 Google 那样直接给人看网页,而是把网络信息“清洗”成结构化的数据(JSON),方便 AI 读取和引用,从而解决大模型“知识过时”和“胡编乱造”的问题。
- ToolNode:LangGraph预构建的工具节点(这里是TavilySearch),自动处理工具调用的解析、执行、结果封装,无需手动写逻辑。
- Checkpointer(检查点):LangGraph中状态的快照,是记忆功能的核心载体,MemorySaver负责将检查点存储在内存中,与所使用的大模型(Qwen-plus)无关,仅负责状态持久化。
- MemorySaver:LangGraph官方提供的内存版检查点存储器,轻量无外部依赖(无须数据库),适合开发、调试场景,其核心作用是保存对话状态,不参与大模型调用逻辑,因此切换Qwen-plus后,记忆功能无须任何修改。
- thread_id(线程/会话):用于区分不同用户/对话的唯一标识,实现多会话隔离记忆,确保多个用户同时使用时,记忆不混淆,该机制与Qwen-plus调用完全独立。
- Qwen-plus适配逻辑:借助LangChain的ChatOpenAI类兼容Qwen-plus的API接口,通过配置Qwen-plus专属的base_url和model参数,实现大模型调用与LangGraph的无缝衔接,不影响记忆功能的正常工作。
这里需要注意,MemorySaver的记忆功能与大模型类型无关,无论切换为Qwen-plus、ChatGLM等国产大模型,还是保留OpenAI,记忆的加载、保存、会话隔离逻辑完全不变,只需修改大模型的调用配置即可。
3.2 实战案例:使用工具和记忆增强聊天机器人
让我们创建一个名为Memory-Tool-Chatbots.py的文件,实现一个具有工具调用与记忆功能的聊天机器人。本案例已完成Qwen-plus适配,无须修改代码,完整可运行代码如下。
【示例4.1】Memory-Tool-Chatbots.py实现工具调用与记忆功能的聊天机器人。核心效果为:Qwen-plus大模型结合LangGraph的工具与记忆功能,实现搜索工具调用、跨轮次上下文记忆,记住用户姓名、年龄等关键信息,同时多会话隔离功能正常生效。
# -*- coding: utf-8 -*-
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_tavily import TavilySearch
from langgraph.graph import MessagesState, StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import ToolNode, tools_condition
import os
load_dotenv()
llm = ChatOpenAI(
model="qwen-plus",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.7
)
search_tool = TavilySearch(max_results=2)
tools = [search_tool]
llm_with_tools = llm.bind_tools(tools)
state = MessagesState
workflow = StateGraph(state)
workflow.add_node("chat", lambda state: {"messages": llm_with_tools.invoke(state["messages"])})
workflow.add_node("tools", ToolNode(tools=tools))
workflow.add_conditional_edges("chat", tools_condition)
workflow.add_edge("tools", "chat")
workflow.set_entry_point("chat")
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
def chat_with_memory():
print("智能对话机器人(支持记忆和搜索)")
print("输入 exit 退出对话")
thread_id = "user_session_1"
config = {"configurable": {"thread_id": thread_id}}
while True:
try:
user_input = input("\n你:").strip()
if not user_input:
continue
if user_input.lower() in ["exit", "quit", "退出"]:
print("机器人:再见!")
break
result = app.invoke(
{"messages": [("user", user_input)]},
config=config
)
if result["messages"]:
last_message = result["messages"][-1]
print("机器人:", last_message.content)
except KeyboardInterrupt:
print("\n对话已结束")
break
except Exception as e:
print(f"出错:{str(e)}")
if __name__ == "__main__":
chat_with_memory()
运行输出:
智能对话机器人(支持记忆和搜索)
输入 exit 退出对话
你:你好,我叫小明
机器人: 你好,小明!很高兴认识你。有什么问题或需要帮助的地方吗?😊
你:我今年25岁了
机器人: 恭喜你25岁!这是充满活力、成长与可能性的年纪 🌟
如果你愿意分享,我很乐意帮你:
- 制定职业或学习规划
- 探讨健康生活方式(比如睡眠、运动、饮食)
- 理财入门建议(如储蓄、基金、保险)
- 心理调适或时间管理小技巧
- 或者只是聊聊兴趣、目标、最近让你开心/困惑的一件事 😊
需要哪方面的支持呢?
你:你还记得我的名字和年龄么?
机器人: 当然记得!😊
你叫**小明**,今年**25岁**。
我会把这一点记在心里,让后续的交流更亲切、更贴合你的阶段和需求~
如果以后你想聊职业发展、生活规划、兴趣探索,或者只是想轻松聊聊,我都在这里 🌟
需要现在开始聊点什么吗?
你:什么是LangGraph的核心组件?
机器人: 是的!根据最新资料,**LangGraph**(由 LangChain 团队开发的用于构建状态化、多步骤 AI 代理和工作流的框架)的核心组件主要包括以下四类,它们共同构成一个可循环、可中断、可调试的图状执行结构:
---
### ✅ 1. **State(状态)**
- 是整个工作流的**共享内存与数据载体**,通常定义为一个 Pydantic `BaseModel` 类。
- 所有节点(Nodes)读取和更新的是同一个 `State` 实例(支持异步/并发安全操作)。
- 示例:
```python
from pydantic import BaseModel
from typing import List, Dict
class ChatState(BaseModel):
messages: List[Dict[str, str]] = []
current_input: str = ""
should_continue: bool = True
```
---
### ✅ 2. **Nodes(节点)**
- 表示**可执行的逻辑单元**(如调用 LLM、运行工具、执行条件判断等)。
- 每个 Node 是一个**异步函数**,接收 `State` 并返回更新后的 `State`(或部分字段)。
- 支持多种内置节点类型,例如:
- `ToolNode`(自动调用工具)
- 自定义函数节点(如 `process_user_input`, `generate_ai_response`)
- LLM 调用节点、记忆节点、验证节点等。
---
### ✅ 3. **Edges(边)**
- 定义节点之间的**执行流向**,分为两类:
- **Fixed edges**:无条件跳转(如 `workflow.add_edge("node_a", "node_b")`)
- **Conditional edges**:基于 `State` 的当前值动态路由(通过 `add_conditional_edges` + 路由函数实现),例如:
```python
def route(state: ChatState) -> str:
return "generate_response" if state.should_continue else END
workflow.add_conditional_edges("process_input", route)
```
---
### ✅ 4. **Graph(图)—— StateGraph**
- 使用 `StateGraph(StateType)` 创建图对象,是编排 Nodes 和 Edges 的**核心容器**。
- 最终通过 `.compile()` 生成可执行的 `CompiledGraph`(支持 `.invoke()`, `.stream()`, `.astream_events()` 等)。
- 支持中断恢复、检查点(checkpoints)、human-in-the-loop 交互等高级能力。
---
🔍 **补充关键支撑技术**(虽非“组件”本身,但深度集成):
- **LangChain Core**:提供 LLM、Tool、Prompt、Message 等基础抽象;
- **LangSmith**:用于追踪、评估、调试 LangGraph 工作流(日志、trace、性能分析);
- **RAG 集成能力**:可自然嵌入检索节点(如 `RetrieverNode`)实现检索增强;
- **APIs & Tool Calling**:原生支持 OpenAI-style function calling 和自定义工具链。
---
需要我为你:
- 🧩 画一个简明架构图(文字版)?
- 🐍 提供一个可运行的「带记忆的问答机器人」完整代码示例?
- 📚 对比 LangGraph 与 AutoGen / LlamaIndex / CrewAI 的定位差异?
欢迎随时告诉我 😊
你:
3.3 案例代码解析
本节重点解析ToolNode工具功能、MemorySaver记忆功能与Qwen-plus调用配置的协同逻辑,拆解核心代码模块,明确三者的职责边界,重点说明Qwen-plus适配的关键细节。
1. 核心模块导入解析
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI # 兼容Qwen-plus调用
from langchain_tavily import TavilySearch
from langgraph.graph import MessagesState, StateGraph, END # 状态与工作流
from langgraph.checkpoint.memory import MemorySaver # 记忆功能核心
from langgraph.prebuilt import ToolNode, tools_condition
import os # 读取环境变量
ChatOpenAI类此处并非用于调用OpenAI服务,而是利用其API调用规范,适配Qwen-plus的OpenAI兼容接口,这是LangChain生态的优势—无须修改核心逻辑,即可切换不同大模型。
2. Qwen-plus调用配置
llm = ChatOpenAI(
model="qwen-plus", # 固定为Qwen-plus模型名
api_key=os.getenv("DASHSCOPE_API_KEY"), # 从.env读取密钥,安全无硬编码
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
# Qwen-plus专属兼容地址
temperature=0 # 生成内容确定性,适合聊天场景
)
该配置仅影响大模型的调用,方便独立调用Tavily搜索工具与MemorySaver记忆功能,保留工具与记忆功能的逻辑实现与大模型调用的分离。核心说明(与OpenAI调用的区别)如下:
- model参数:替换为Qwen-plus专属模型名(固定为"qwen-plus"),无须修改其他逻辑。
- api_key参数:使用阿里云通义千问的DASHSCOPE_API_KEY,而非OpenAI的API密钥,通过os.getenv从.env读取,避免硬编码。
- base_url参数:Qwen-plus的OpenAI兼容接口地址(固定),用于指定大模型调用的服务器地址,确保LangChain能正确请求Qwen-plus服务。
3. 核心数据结构:State(状态定义)
状态定义:MessagesState
state = MessagesState
MessagesState是LangGraph内置的状态类型,专门为对话场景设计,内部结构为{"messages": [消息列表]},自动管理用户消息与Qwen-plus的回复内容。MemorySaver会自动持久化该状态,实现对话记忆,无论大模型切换为哪种,该状态的管理逻辑完全不变。
4. 工具功能核心解析
1)工具初始化(Tavily搜索)
search_tool = TavilySearch(max_results=2) # 初始化 Tavily 搜索工具,最多返回 2 条结果
tools = [search_tool] # 工具列表(可扩展多个工具,如计算器、数据库查询等)
LangChain集成的Tavily搜索(TavilySearch)工具(需在.env中配置TAVILY_API_KEY),用于获取实时/联网信息(大模型本身无实时数据)。
2)绑定工具到大模型
llm_with_tools = llm.bind_tools(search_tool)
bind_tools将工具列表绑定给大模型,让大模型具备“判断是否需要调用工具”的能力。当用户问题不需要实时数据(如“1+1等于几”),大模型直接回复;当用户问题需要实时数据(如“今天北京天气”),大模型会生成工具调用请求(包含搜索关键词等参数)。
5. 记忆功能核心解析
1)MemorySaver初始化与工作流编译
# 初始化记忆存储器(内存版,轻量无依赖)
memory = MemorySaver()
# 编译工作流,传入memory开启记忆功能
app = workflow.compile(checkpointer=memory)
这是开启记忆功能的关键步骤,与Qwen-plus调用无关:
- 初始化MemorySaver实例,用于存储对话状态(检查点)。
- 编译工作流时,传入checkpointer=memory,告知LangGraph开启状态持久化功能。
- 编译后的app会自动完成“记忆加载→逻辑执行→记忆保存”的闭环,与大模型类型无关。
2)会话隔离:thread_id
thread_id = "user_1001"
config = {"configurable": {"thread_id": thread_id}}
thread_id是会话唯一标识,用于区分不同用户/对话,核心作用是实现多会话记忆隔离:
- 不同thread_id对应的记忆完全独立,不会出现“用户A的对话记忆被用户B获取”的情况。
- 实战中可使用用户ID、会话ID作为thread_id,适配多用户场景。
- 该机制与Qwen-plus调用无关,仅由LangGraph的记忆功能管理。
3)记忆的加载与保存机制(与Qwen-plus协同)
LangGraph记忆功能与Qwen-plus的协同流程如下(核心闭环):
- 加载记忆:调用app.invoke()时,传入包含thread_id的config,MemorySaver自动从内存中读取该会话的历史消息(状态)。
- 大模型调用:将加载的历史消息+当前用户输入,一同传入Qwen-plus,Qwen-plus基于完整上下文生成回复。
- 保存记忆:Qwen-plus生成回复后,LangGraph自动将该回复追加到对话状态中,MemorySaver同步保存更新后的状态,完成记忆更新。
6. 关键知识点补充(适配Qwen-plus场景)
- 多工具选择:只需在tools列表中添加新工具(如Calculator、SQLDatabaseToolkit等),llm.bind_tools会自动让大模型支持多工具选择。
- 无记忆与有记忆:不传入checkpointer=memory时,每次对话都是独立的,Qwen-plus无法获取历史上下文,仅能基于当前输入回复;传入后,即可实现跨轮次记忆。
- MemorySaver特性:内存存储,程序重启后记忆会丢失,适合开发调试;生产环境可替换为RedisSaver/SqliteSaver,记忆功能逻辑不变,仅修改存储器类型。
- Qwen-plus适配扩展:若需切换为Qwen-14B、Qwen-max等其他通义千问模型,只需修改model参数(如model="qwen-14b"),同时确保API密钥拥有对应模型的调用权限,记忆功能无须任何调整。
- 常见问题:若Qwen-plus调用失败,优先检查.env文件中的DASHSCOPE_API_KEY是否正确、网络是否能访问阿里云通义千问接口,与MemorySaver无关。


458

被折叠的 条评论
为什么被折叠?



