一、python环境 & 相关库版本信息
代码运行在 conda
创建的python环境下,python和相关库的版本信息如下:
$ python --version
Python 3.12.3
$ pip list | grep langchain
langchain 0.3.15
langchain-community 0.3.15
langchain-core 0.3.31
langchain-groq 0.2.3
langchain-text-splitters 0.3.5
langgraph 0.2.64
langgraph-checkpoint 2.0.10
langgraph-sdk 0.1.51
langsmith 0.2.11
导入需要用的库:
import os
import json
from langchain_community.tools.tavily_search import TavilySearchResults
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_groq import ChatGroq
from langchain_core.messages import ToolMessage
(若不确定相关库是否有缺失,可以先运行,根据库缺失等报错信息进行 pip install
)
安装 langchain
:pip install langchain
安装 langgraph
:pip install -U langgraph
安装 langchain-groq
:pip install langchain-groq
二、申请 API Key
本次代码运行需要用到三个不同的 API Key:
- GROQ_API_KEY(用于借助groq云平台实现高效LLM推理):申请页面
- TAVILY_API_KEY(专为大型语言模型(LLMs)和检索增强生成(RAG)应用设计的搜索引擎,在本次代码示例中作为LLM可使用的Tool):获取页面
- LANGCHAIN_API_KEY(为了使用LangSmith需要用到,LangSmith可以帮助我们清晰直观地跟踪搭建的LangGraph的每一次状态变化过程):申请页面
获取完以上 API Key 之后,可以将它们统一放在代码同级的 .env
文件中进行管理,并使用 python-dotenv
库在运行时加载这些环境变量。因为我使用该方法时有点问题,所以我还是直接把环境变量写在代码里了。
因为我们要使用LangSmith用于调试和跟踪,涉及到另外一个环境变量 LANGCHAIN_TRACING_V2,默认为 false
,设置为 true
就可以开启跟踪功能。
os.environ["TAVILY_API_KEY"] = "TAVILY_API_KEY"
os.environ["LANGCHAIN_API_KEY"] = "LANGCHAIN_API_KEY" # Get this from smith.langchain.com
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["GROQ_API_KEY"] = "GROQ_API_KEY"
三、Graph功能描述
Graph图如下所示:
我们主要想实现的功能就是,用户可以不断提问,LLM将根据用户提问内容判断是否需要使用作为外部搜索引擎的tavily API服务获取更多信息,若需要则结合这些信息对用户提问做出回答。
Graph处理逻辑流程描述
- 用户输入问题;
chatbot
节点接收用户输入并更新 Graph 的状态信息;- 通过
conditional edge
,根据相应的代码逻辑判断 Graph 的下一步操作,决定是进入tools
节点调用工具,还是直接跳转至END
节点结束流程; - 如果进入
tools
节点,则执行工具调用逻辑,通过调用 Tavily API 服务进行联网检索。在获取返回结果后,更新 Graph 的状态信息,然后通过与chatbot
节点之间的有向边返回chatbot
; chatbot
接收更新后的状态信息,作为 LLM 的输入进行推理。如果推理结果不需要再次调用工具,则通过conditional edge
判断后直接进入END
节点;否则继续执行,直到流程到达END
节点,完成一次 Graph 的迭代。
四、核心代码详解
以下代码全部来自 Langgraph 官方教程文档 。
1. 定义用于保存graph状态的数据结构
首先,创建一个继承自 TypedDict
类的子类 State
,且 State
类定义了一个 messages
键,用于定义描述graph状态的数据结构。messages
键的类型被指定为 list
,意味着该键的值是一个列表,用于存储Graph状态变化时产生的消息。Annotated
则是用来为 messages
类型(列表)添加额外的元数据 add_messages
,以此控制 messages
键的列表值的更新方式为追加而不是默认的覆盖。即当graph的状态,也就是消息列表被更新时,上一次的消息列表不会被新产生的消息列表所覆盖,而是会将新消息追加到上一次的消息列表中,以达到每一次graph流迭代时,所有产生的状态都会保存在消息列表中。
# 定义状态
class State(TypedDict):
# Messages have the type "list". The `add_messages` function
# in the annotation defines how this state key should be updated
# (in this case, it appends messages to the list, rather than overwriting them)
messages: Annotated[list, add_messages]
2. 定义 tool 节点
2.1 创建工具列表
# 创建tavily搜索引擎工具,max_results用来设置返回检索结果的数量
tool = TavilySearchResults(max_results=2)
# 放入列表中
tools = [tool]
2.2 定义tool节点类
该类的主要作用是执行上一个 AI 消息中请求的工具,并返回执行结果。
class BasicToolNode:
"""A node that runs the tools requested in the last AIMessage."""
def