使用LangGraph搭建简单的聊天机器人
LangGraph简介:基于图结构的 AI 工作流框架
1. 定义与定位
- LangGraph 是由 LangChain 团队开发的开源框架,专为构建有状态、多代理、循环式 AI 工作流设计。它基于 LangChain 生态,通过图结构(节点+边) 建模复杂任务流程,支持动态调整、状态管理和多步骤决策,适用于需要循环交互或复杂任务分解的场景。
2. 核心特性
- 图结构驱动:以 StateGraph 为核心,节点代表计算步骤(如 LLM 调用、工具执行),边定义状态转移路径,支持有向图(含循环) 而非仅限于有向无环图(DAG)。
- 状态管理:通过 State 字典在节点间传递和更新状态(如对话历史、工具调用结果),支持自定义状态类型(如消息列表)。
- 多代理协调:支持多 LLM 代理或工具的协同工作,例如通过 ToolNode 集成搜索、计算等外部工具。
- 人类干预:内置 interrupt() 函数实现“人在回路”(Human-in-the-Loop),允许在工具调用前暂停执行,等待人工审批或反馈。
- 持久化存储:提供内存、文件系统或数据库(如 PostgreSQL + pgvector)存储选项,支持跨会话数据保留和语义搜索。
3. 典型使用场景
- 对话系统:构建多轮对话机器人,支持上下文记忆、工具调用(如搜索、计算)和动态响应生成。
- 任务分解:将复杂任务拆分为子任务,通过图结构管理执行顺序和依赖关系(如自动化报告生成、数据清洗)。
- 多代理系统:协调多个 AI 代理协作完成任务(如客服系统中的问题分类、解决方案推荐)。
- 自动化工作流:在金融、电商等领域实现自动化决策(如订单处理、交易监控),支持高并发和动态调整。
环境配置与安装
为避免不同环境的冲突,可以新建一个环境,再安装相应的库。
conda create -n langgraph_env python=3.10 # 创建新虚拟环境
conda activate langgraph_env # 激活虚拟环境
# 安装相应的库
pip install langgraph
pip install openai
首先我们需了解langgraph的四个核心组件:
-
State: 在图中传递的数据结构
-
Node: 执行具体任务的函数
-
Edge: 连接节点,决定流程走向
-
Graph: 由节点和边组成的完整工作流
怎么理解呢,可以把Graph看作是一张地图,Node就是地图上的城市,Edge就连接不同城市的道路(当然,两个城市之间有没有道路连接可以由自己决定),那么State就是流转于这些城市之间的货车。
一开始,我们会把一个Node当作开始结点,相当于货车从某个城市开始出发。然后沿着规定好的道路行驶,每到一个城市(Node)就会对车上的货物进行处理,就相当于改变State的状态。货车一直行驶下去,到达规定的最后一个城市(Node结束结点)。注意:这个graph应该是有向无环图,开始结点和结束结点都只能有一个。
简单工具流的搭建
建立图
首先定义State数据结构
这一步相当于确定好货车。
from typing import TypedDict, List
class State(TypedDict):
data: str # 处理的数据
current_step: str # 记录当前到达哪个结点
node_history: List[str] # 记录经过的结点
上述代码中,定义了一个State类,其继承于TypedDict,本质上是一个字典,我们定义了3个键值对。data:str 表示键为'data',而值应该为str类型。
定义开始结点
相当于确定好货车的出发城市
def start_node(state: State) -> State:
state['current_step'] = 'start_node' # 记录当前结点
print('当前结点:', state['current_step'])
state['node_history'].append('start_node') # 记录历史结点
return state
def start_node(state: State) -> State:
表示声明开始结点函数,state:State表示函数的参数类型是State,->State表示函数的返回值期望是State类型。
定义处理结点
确定好货车经过的城市,在这里可以对数据state做一些处理。
def process_node(state:State) -> State:
state['current_step'] = 'process_node'
print('当前结点:', state['current_step'])
state['node_history'].append('process_node')
state['data'] = '你好,世界'
return state
定义结束结点
确定货车的目的地城市
def end_node(state:State) -> State:
state['current_step'] = 'end_node'
print('当前结点:', state['current_step'])
state['node_history'].append('end_node')
return state
在结点创建好后,我们需要把结点连接起来,形成一个graph地图。
from langgraph.graph import StateGraph, END
# 先定义一个空的地图
builder = StateGraph(State)
# 这一步先把所有结点加入到地图中
builder.add_node('start', start_node) # 第一个参数是给结点取名,第二个参数是结点
builder.add_node('process', process_node)
builder.add_node('end', end_node)
# 在结点之间添加边
builder.set_entry_point('start') # 确定出发城市
builder.add_edge('start', 'process')
builder.add_edge('process', 'end')
builder.add_edge('end', END) # 注意,这里确定结束结点的方式不大一样
# 最后要对图进行编译
graph = builder.compile()
运行工作流
我们的工作流已经搭建完成了,接下来就是试一下能否正常运行。
首先先初始化一下state:
test_state: State = {
'data': '',
'current_step': '',
'node_history': [],
}
然后通过的invoke方法把state传进去:
result = graph.invoke(test_state)
print(result)
上述代码中,使用result接受工作流的结果,然后打印result。
运行一下看看结果:

可以看到,state经过的每个结点及处理后的最终结果。
下面是完整代码:
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
class State(TypedDict):
data: str # 处理的数据
current_step: str # 记录当前到达哪个结点
node_history: List[str] # 记录经过的结点
def start_node(state: State) -> State:
state['current_step'] = 'start_node' # 记录当前结点
print('当前结点:', state['current_step'])
state['node_history'].append('start_node') # 记录历史结点
return state
def process_node(state:State) -> State:
state['current_step'] = 'process_node'
print('当前结点:', state['current_step'])
state['node_history'].append('process_node')
state['data'] = '你好,世界'
return state
def end_node(state:State) -> State:
state['current_step'] = 'end_node'
print('当前结点:', state['current_step'])
state['node_history'].append('end_node')
return state
# 先定义一个空的地图
builder = StateGraph(State)
# 这一步先把所有结点加入到地图中
builder.add_node('start', start_node) # 第一个参数是给结点取名,第二个参数是结点
builder.add_node('process', process_node)
builder.add_node('end', end_node)
# 在结点之间添加边
builder.set_entry_point('start') # 确定出发城市
builder.add_edge('start', 'process')
builder.add_edge('process', 'end')
builder.add_edge('end', END) # 注意,这里确定结束结点的方式不大一样
# 最后要对图进行编译
graph = builder.compile()
test_state: State = {
'data': '',
'current_step': '',
'node_history': [],
}
result = graph.invoke(test_state)
print(result)
加入AI对话
在上述工作流搭建的基础上,我们可以把AI加入到我们的工作流当中。
这里我选择使用deepseek-chat模型。
获取api_key
首先我们要到deepseek开发平台上获取api_key,网址https://platform.deepseek.com/
注册并实名认证之后,在左边栏的用量信息这里去充值(只需充一点点小钱就行,我充了5块钱就已经可以使用很久了),也可以查一下左下的产品定价。

然后就可以点击左边栏的API Keys, 然后在界面里点击创建

输入自己定的api key的名字后,就可以复制自己的api_key了。注意api_key不要泄露出去,也不要与他人共享哦。

那么为了保护好api_key,我们尽量不要直接在代码中显式指定api_key。有两种方法使用api_key:
方法一:把api_key保存到系统环境变量中。
搜索环境变量,点击打开

点击环境变量

在系统变量这里点击新建

输入变量名,在变量值输入刚才的获取api_key

然后一直点击确定即可。
方法二:使用.env
在代码的同目录下新建一个.env文件,注意文件名就叫.env
![]()
不会的可以右键打开终端,然后在终端中输入:
New-Item .env
![]()
然后右键用记事本打开.env文件,把api_key记录进去(注意等号两边不要有空格)

保存并退出。
创建AI客户端
接下来就可以创建AI客户端了。
先在代码中获取api_key
若你保存api_key时采用方法一:
import os
api_key = os.getenv('OPENAI_API_KEY')
os.getenv会自动查找系统环境变量里变量名为OPENAI_API_KEY的环境变量,并把变量值赋值给api_key。
若你采用方法二:
from dotenv import load_dotenv
import os
# 加载.env到当前进行的环境变量里
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
因为os.getenv只能在系统环境变量里查找,所以我们存在.env里的api_key是找不到的。所以使用load_dotenv()可以把.env加载到当前运行的环境变量里,然后就可以用os.getenv获得api_key了。
下面我使用方法二,连接AI,并向AI提问一个小问题,完整代码如下:
from dotenv import load_dotenv
from openai import OpenAI
import os
# 加载.env到当前进行的环境变量里
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(
api_key=api_key,
base_url = "https://api.deepseek.com",
)
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个AI智能助手"},
{"role": "user", "content": "请问一台计算机主要由哪几部分构成?"}
],
temperature=0.1
)
print(response.choices[0].message.content)
上述代码中:client是创建好的AI客户端。
client.chat.completions.create()是向api发送请求,获得的回应保存在response。
其中的参数:
model 表示指定的模型。
messages 表示发送给AI的提示,{"role": "system", "content": "你是一个AI智能助手"} 表示这是系统提示,告诉AI应该扮演什么角色; {"role": "user", "content": "请问一台计算机主要由哪几部分构成?"} 是用户提示,用于将用户的问题发送给AI。
temperature 控制生成文本的随机性/创造性(范围:0.0 到 2.0) 具体含义: 低温度 (0.0-0.3):更确定、一致的回答,适合事实性任务。中温度 (0.4-0.7):平衡创造性和一致性,适合一般对话。高温度 (0.8-2.0):更有创造性、随机性,适合创意写作
返回的response是一个json对象,包含许多内容,如token用量。使用response.choices[0].message.content将具体的回答内容取出。
运行结果如下:

AI聊天的工作流搭建
接下来,我们先抛掉上面的所有代码,建立一个AI聊天的工作流
下面是所需的库文件
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
import os
from dotenv import load_dotenv
from openai import OpenAI
AI客户端建立:
def create_client():
# 加载.env到当前进行的环境变量里
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(
api_key=api_key,
base_url = "https://api.deepseek.com",
)
return client
为了能够与AI进行交互的state定义并初始化:
class State(TypedDict):
user_input: str # 用户输入的数据
ai_response: str # ai的回应
current_step: str # 记录当前到达哪个结点
node_history: List[str] # 记录经过的结点
开始结点、处理结点和结束结点的定义:
def start_node(state: State) -> State:
state['current_step'] = 'start_node' # 记录当前结点
print('当前结点:', state['current_step'])
state['node_history'].append('start_node') # 记录历史结点
return state
# 处理结点
def process_node(state: State, client: OpenAI) -> State:
state['current_step'] = 'process_node'
print('当前结点:', state['current_step'])
state['node_history'].append('process_node')
user_input = state['user_input']
# 构建prompt
message = [
{"role": "system", "content": "你是一个AI智能助手"},
{"role": "user", "content": f"{user_input}"}
]
# 获得回应
response = client.chat.completions.create(
model="deepseek-chat",
messages=message,
temperature=0.2,
)
# 保存回应结果
state['ai_response'] = response.choices[0].message.content
return state
# 结束结点
def end_node(state:State) -> State:
state['current_step'] = 'end_node'
print('当前结点:', state['current_step'])
state['node_history'].append('end_node')
return state
利用结点创建图:
def create_graph(client: OpenAI) -> StateGraph:
# 先定义一个空的地图
builder = StateGraph(State)
# 这一步先把所有结点加入到地图中
builder.add_node('start', start_node) # 第一个参数是给结点取名,第二个参数是结点
builder.add_node('process', lambda state: process_node(state, client))
builder.add_node('end', end_node)
# 在结点之间添加边
builder.set_entry_point('start') # 确定出发城市
builder.add_edge('start', 'process')
builder.add_edge('process', 'end')
builder.add_edge('end', END) # 注意,这里确定结束结点的方式不大一样
# 最后要对图进行编译
graph = builder.compile()
return graph
定义主函数:
def main():
# 建立客户端
client = create_client()
print('AI客户端建立成功!')
graph = create_graph(client)
print('工作流建立成功!')
user_input = input('请输入:')
# 初始化状态
state = {
'user_input': user_input,
'ai_response': '',
'current_step': '',
'node_history': []
}
# 传入状态,获得结果
result_state = graph.invoke(state)
print('AI回应结果:', result_state['ai_response'])
在以上函数都定义完后,使用:
if __name__ == '__main__':
main()
来调用主函数。
接下来运行程序,得到如下输出:

若想重复输入,可以在主函数中加入循环:
def main():
# 建立客户端
client = create_client()
print('AI客户端建立成功!')
graph = create_graph(client)
print('工作流建立成功!')
while(True):
user_input = input('请输入:')
# 初始化状态
state = {
'user_input': user_input,
'ai_response': '',
'current_step': '',
'node_history': []
}
# 传入状态,获得结果
result_state = graph.invoke(state)
print('AI回应结果:', result_state['ai_response'])
输出结果:

以下是完整代码:
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
import os
from dotenv import load_dotenv
from openai import OpenAI
def create_client():
# 加载.env到当前进行的环境变量里
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(
api_key=api_key,
base_url = "https://api.deepseek.com",
)
return client
class State(TypedDict):
user_input: str # 用户输入的数据
ai_response: str # ai的回应
current_step: str # 记录当前到达哪个结点
node_history: List[str] # 记录经过的结点
# 开始结点
def start_node(state: State) -> State:
state['current_step'] = 'start_node' # 记录当前结点
print('当前结点:', state['current_step'])
state['node_history'].append('start_node') # 记录历史结点
return state
# 处理结点
def process_node(state: State, client: OpenAI) -> State:
state['current_step'] = 'process_node'
print('当前结点:', state['current_step'])
state['node_history'].append('process_node')
user_input = state['user_input']
# 构建prompt
message = [
{"role": "system", "content": "你是一个AI智能助手"},
{"role": "user", "content": f"{user_input}"}
]
# 获得回应
response = client.chat.completions.create(
model="deepseek-chat",
messages=message,
temperature=0.2,
)
# 保存回应结果
state['ai_response'] = response.choices[0].message.content
return state
# 结束结点
def end_node(state:State):
state['current_step'] = 'end_node'
print('当前结点:', state['current_step'])
state['node_history'].append('end_node')
return state
def create_graph(client: OpenAI) -> StateGraph:
# 先定义一个空的地图
builder = StateGraph(State)
# 这一步先把所有结点加入到地图中
builder.add_node('start', lambda state: start_node(state)) # 第一个参数是给结点取名,第二个参数是结点
builder.add_node('process', lambda state: process_node(state, client))
builder.add_node('end', lambda state: end_node(state))
# 在结点之间添加边
builder.set_entry_point('start') # 确定出发城市
builder.add_edge('start', 'process')
builder.add_edge('process', 'end')
builder.add_edge('end', END) # 注意,这里确定结束结点的方式不大一样
# 最后要对图进行编译
graph = builder.compile()
return graph
def main():
# 建立客户端
client = create_client()
print('AI客户端建立成功!')
graph = create_graph(client)
print('工作流建立成功!')
while(True):
user_input = input('请输入:')
# 初始化状态
state = {
'user_input': user_input,
'ai_response': '',
'current_step': '',
'node_history': []
}
# 传入状态,获得结果
result_state = graph.invoke(state)
print('AI回应结果:', result_state['ai_response'])
if __name__ == '__main__':
main()
以上就是一个基于langgraph的简单AI聊天机器人的搭建了,本人水平有限,如有错误欢迎指出。如果这篇文章对你有帮助,请动动手指点个赞哦,谢谢~
更多推荐


所有评论(0)