LangGraph 实战:连接 DeepSeek 和 GPT 大模型
LangGraph 不仅能编排普通 Python 函数,也可以把大模型调用封装成图节点。本文用一个最小示例,实现以下流程:
text
START -> call_model -> END
程序还支持通过运行配置,在 DeepSeek 和 GPT 之间动态切换。
1. 安装依赖
bash
python -m pip install -U langgraph langchain-deepseek langchain-openai
本文示例使用的主要版本:
text
Python 3.14.7
LangGraph 1.2.10
langchain-deepseek 1.1.0
langchain-openai 1.4.3
2. 配置 API Key
不要把 API Key 直接写进 Python 文件,可以先在终端中设置环境变量:
bash
export DEEPSEEK_API_KEY="你的 DeepSeek API Key"
export API_KEY="你的 GPT 服务 API Key"
代码通过 os.environ 读取密钥,并使用 SecretStr 包装:
python
api_key=SecretStr(os.environ["DEEPSEEK_API_KEY"])
如果环境变量不存在,运行时会出现 KeyError。
3. 定义消息状态
python
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]
messages 用来保存对话消息。operator.add 是 reducer,节点返回的新消息会追加到原消息列表中,而不是覆盖已有消息。
4. 在节点中调用模型
python
models = {"deepseek": deepseek, "gpt": gpt}
def call_model(state: AgentState, config: RunnableConfig):
configurable = config.get("configurable") or {}
model_name = configurable.get("model", "deepseek")
model = models[model_name]
response = model.invoke(state["messages"])
return {"messages": [response]}
节点先读取 configurable.model,再从 models 中选择对应的大模型。没有传入模型名称时,默认使用 DeepSeek。
运行配置如下:
python
run_config: RunnableConfig = {"configurable": {"model": "deepseek"}}
切换到 GPT 只需要改成:
python
run_config: RunnableConfig = {"configurable": {"model": "gpt"}}
5. 完整代码
python
import operator
import os
from typing import Annotated, Sequence
# BaseMessage 是所有 LangChain 消息类型的基类;
# HumanMessage 用于表示用户发送给大模型的消息。
from langchain_core.messages import BaseMessage, HumanMessage
# RunnableConfig 用于描述图运行时传入的配置信息。
from langchain_core.runnables.config import RunnableConfig
from langchain_deepseek import ChatDeepSeek
from langchain_openai import ChatOpenAI
# START 和 END 是 LangGraph 内置的开始、结束节点。
from langgraph.graph import END, START, StateGraph
# SecretStr 用于包装敏感字符串,避免 API Key 被直接显示在日志中。
from pydantic import SecretStr
from typing_extensions import TypedDict
# 创建 DeepSeek 聊天模型客户端。
deepseek = ChatDeepSeek(
# 指定需要调用的 DeepSeek 模型。
model="deepseek-v4-flash",
# temperature 越低,回答越稳定;设置为 0 适合演示和确定性任务。
temperature=0,
# DeepSeek 官方 API 地址。
base_url="https://api.deepseek.com",
# 从环境变量读取 API Key,避免将密钥直接写进源代码。
# 运行前需要执行:export DEEPSEEK_API_KEY="你的密钥"
api_key=SecretStr(os.environ["DEEPSEEK_API_KEY"]),
)
# ChatOpenAI 不仅可以连接 OpenAI 官方接口,也可以连接兼容
# OpenAI API 协议的第三方服务。
gpt = ChatOpenAI(
# 模型名称必须是当前 API 服务实际支持的模型。
model="gpt-5.6-sol",
temperature=0,
# 当前示例使用自定义的 OpenAI 兼容接口地址。
base_url="https://codex.ximuai.com",
# 运行前需要执行:export API_KEY="你的密钥"
api_key=SecretStr(os.environ["API_KEY"]),
)
# 使用字典统一管理模型,后面可以通过名称动态选择模型。
models = {"deepseek": deepseek, "gpt": gpt}
# 定义整个图在节点之间传递的状态结构。
class AgentState(TypedDict):
# messages 保存完整的对话消息。
# Annotated 的第二个参数 operator.add 是 reducer(归并函数):
# 当节点返回新消息时,LangGraph 会把新消息追加到原消息序列中,
# 而不是直接覆盖原来的消息。
messages: Annotated[Sequence[BaseMessage], operator.add]
# 图的运行时配置。
# configurable 中可以放自定义配置,这里通过 model 指定使用 DeepSeek。
# 如果需要切换到 GPT,可以把 "deepseek" 改为 "gpt"。
run_config: RunnableConfig = {"configurable": {"model": "deepseek"}}
def call_model(state: AgentState, config: RunnableConfig):
"""读取当前对话状态,调用指定模型,并返回模型生成的新消息。"""
# RunnableConfig 中的 configurable 字段是可选字段。
# 使用 get() 和空字典兜底,可以避免字段不存在时触发 KeyError。
configurable = config.get("configurable") or {}
# 读取本次运行指定的模型名称;没有指定时默认使用 DeepSeek。
model_name = configurable.get("model", "deepseek")
# 根据模型名称获取已经创建好的聊天模型客户端。
model = models[model_name]
# 把状态中保存的全部历史消息发送给大模型。
response = model.invoke(state["messages"])
# 节点只返回本次生成的新消息。
# AgentState 中配置的 operator.add 会将它追加到原消息序列。
return {"messages": [response]}
# 创建状态图,并指定图中流转的状态类型为 AgentState。
graph_builder = StateGraph(AgentState)
# 注册一个名为 call_model 的节点,并绑定同名处理函数。
graph_builder.add_node("call_model", call_model)
# 图开始后进入 call_model 节点。
graph_builder.add_edge(START, "call_model")
# 大模型调用完成后直接结束图,不再执行其他节点。
graph_builder.add_edge("call_model", END)
# 编译图。编译后得到的 graph 才能通过 invoke() 执行。
graph = graph_builder.compile()
# 执行图:
# 1. 初始状态中放入一条用户消息;
# 2. config 用于指定本次运行需要调用的模型;
# 3. 返回值包含初始消息和模型追加的回复消息。
res = graph.invoke(
{"messages": [HumanMessage(content="你好,你是谁?")]},
config=run_config,
)
# 依次格式化输出用户消息和 AI 回复。
for message in res["messages"]:
message.pretty_print()
6. 运行与输出
执行程序:
bash
python index.py
输出示例:
text
================================ Human Message =================================
你好,你是谁?
================================== Ai Message ==================================
你好!我是一个由人工智能技术驱动的助手,可以帮助你解答问题、整理信息和编写代码。
大模型生成的内容并不固定,因此每次运行的回答可能略有不同。res["messages"] 中同时包含最初的 HumanMessage 和节点追加的 AI 回复。
总结
连接大模型的关键步骤只有三个:定义消息状态、在节点中调用模型、用边连接 START 和 END。把模型名称放进 RunnableConfig 后,同一张图就可以在不修改节点逻辑的情况下切换不同模型。
需要注意:当前代码在程序启动时会同时创建 DeepSeek 和 GPT 客户端,因此两个 API Key 都必须存在,即使本次只调用其中一个模型。