LangChain实践(基于DeepSeek)
1、准备
- 使用PyCharm 2025.3及以上版本,可以直接创建uv管理项目
- 在IDE内部可以使用Jupyter notebook直接使用:
uv add notebook - 使用
.env文件保存API_KEY并提供环境变量访问
LangChain官网:
2、基础:调用大模型
2.1 准备工作
首先,我们要安装OpenAI的依赖
uv add openai
2.2 初始化客户端
- 硬编码API_KEY
from openai import OpenAI
client = OpenAI(api_key="sk-xxxx", base_url="https://api.deepseek.com")
- 从环境变量中获取API_KEY
读取变量需要用到python-dotenv,先安装依赖,命令是:
uv add python-dotenv
再创建.env文件,并写入API_KEY
API_KEY=xxxx
接着就可以从环境变量中获取API_KEY了。
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("DEEPSEEK_API_KEY")
print(api_key)
client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
2.3 访问模型
response = client.responses.create(
model="deepseek-v4-flash",
instructions="You are a helpful assistant.",
input="Hi, how are you?",
)
2.4 获取模型响应结果
print(response.output_text)
3、LangChain入门案例:天气查询智能体

3.1 准备工作
首先,要使用LangChain必须先安装依赖,命令如下:
uv add langchain
LangChain支持各种不同的模型,而且提供了对应的兼容SDK,不过也都需要安装对应依赖,你可以按需添加:
# 集成DeepSeek
uv add langchain-deepseek
# 集成OpenAI
uv add langchain-openai
# 集成Anthropic
uv add langchain-anthropic
接下来就可以开发agent了,基本步骤如下:
- 加载环境变量
- 定义工具
- 定义Agent
- 调用Agent
3.2 开发Agent
加载环境变量
# 1. 加载环境变量
from dotenv import load_dotenv
load_dotenv()
定义工具
# 2. 定义工具
from langchain.tools import tool
@tool
def getWeather(location: str) -> str:
"""
Get the weather in a given location.
Args:
location: city name or coordinates
"""
return f"Current weather in {location} is sunny"
创建Agent
# 3. 创建Agent
from langchain.agents import create_agent
agent = create_agent(
model="deepseek-v4-flash",
tools=[getWeather],
system_prompt="You are a helpful assistant",
)
发起调用
# 4. 调用Agent
result = agent.invoke(
{"messages": [{"role": "user", "content": "杭州今天天气如何?"}]}
)
print(result["messages"][-1].content_blocks)
# [{'type': 'reasoning', 'reasoning': "The weather in Hangzhou is sunny today. I'll respond to the user in Chinese."}, {'type': 'text', 'text': '杭州今天天气晴朗(sunny)☀️,天气不错,适合外出活动!如果有出行计划,记得做好防晒哦。'}]
3.2 Agent执行流程

Agent如何知道工具信息的

4、LangChain初始化模型
LangChain支持现在市面上大部分常见的大语言模型LLM,并且提供了各个模型的对应依赖库。
使用时只需要引入对应的类即可使用:
- 过时写法:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-5.2")
- 推荐写法:不需要实例化具体的类,自动路由
from langchain.chat_models import init_chat_model
model = init_chat_model(model="gpt-5.2")
4.1 开发流程

4.2 实践
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()
初始化并调用模型
LangChain提供了两种常见函数用来初始化模型:
- 使用init_chat_model函数,由LangChain自动创建模型对象
- 使用不同模型对应的类,手动创建模型对象
init_chat_model
官方最推荐的方式就是使用init_chat_model函数。
基于名称推断模型提供商
使用init_chat_model函数,你需要从LangChain支持的模型提供者(Model Provider)中选择一个模型。而LangChain根据模型名称自动初始化与模型的连接,非常方便。
LangChain支持的模型列表参考官方链接:
https://docs.langchain.com/oss/python/integrations/providers/overview
接下来,你要做的事情包括:
- 安装模型依赖:uv add langchain langchain-deepseek
- 在.env中配置模型的api_key
- 调用init_chat_model函数,传入正确的模型名称
# 导入LangChain的初始化模型的函数
from langchain.chat_models import init_chat_model
# 调用init_chat_model函数初始化模型
# 参数model用来指定模型名称,LangChain会根据模型名字自动设定base_url,并从环境变量中获取api_key
model = init_chat_model(model="deepseek-v4-flash")
print(type(model))
# <class 'langchain_deepseek.chat_models.ChatDeepSeek'>
4.3 自定义模型提供商
init_chat_model默认会根据模型名称自动确定模型的提供者的base_url,并从env读取api_Key,但前提必须是LangChain支持的模型平台,例如:
- openai
- deepseek
- …
对于其他模型,我们必须自定义模型参数来访问。
例如,我们要访问阿里云百炼的qwen-max,他就不是LangChain支持的模型,我们必须自定义模型参数来访问。
- 我们需要再环境变量中定义api_key和base_url
- 然后在init_chat_model中指定model、model_provider、base_url和api_key。
# 我们收到加载环境变量中的base_url和api_key
import os
base_url = os.getenv("DASHSCOPE_BASE_URL")
api_key = os.getenv("DASHSCOPE_API_KEY")
model = init_chat_model(
model="qwen-max", # 模型名称
model_provider="openai", # 如果是LangChain不支持的类型,需要指定模型提供者(虽然我们用的是阿里,但是阿里兼容openai,所以这里用openai)
base_url=base_url,
api_key=api_key
)
# 自定义模型参数时,模型的类型有model_provider确定
print(type(model))
# <class 'langchain_openai.chat_models.base.ChatOpenAI'>
4.4 调整模型参数
除了修改模型提供者之外,init_chat_model函数允许我们调整模型参数,例如:
- temperature:控制生成文本的随机性,值越小越确定,值越大越随机。
- max_tokens:控制生成文本的最大长度
- top_p:控制生成文本的多样性,值越小越多样,值越大越确定。
- timeout:控制生成文本的超时时间
- max_retries:控制生成文本的最大重试次数。
# 调用init_chat_model函数初始化模型,并设定模型参数
model = init_chat_model(
model="qwen-max", # 模型名称
model_provider="openai", # 如果是LangChain不支持的类型,需要指定模型提供者(虽然我们用的是阿里,但是阿里兼容openai,所以这里用openai)
base_url=base_url,
api_key=api_key,
temperature=1.5,
top_p=0.9,
)
4.5 使用model类
其实init_chat_model函数底层就是帮我们利用Model类创建对象。但支持有限的模型。
而在LangChain的社区,除了LangChain官方提供的Model,还有些类是社区提供,更丰富多样。
具体支持的模型,可以查看官方网址:https://docs.langchain.com/oss/python/integrations/chat
例如,我们使用社区版本的Model类来访问阿里云百炼的通义千问模型:
- 首先,我们需要安装依赖LangChain社区依赖:
uv add langchain-community
# 阿里云百炼依赖
uv add dashscope
- 然后,我们就可以使用Model类初始化模型了。
from langchain_community.chat_model.tongyi import ChatTongyi
# 使用Model类初始化模型
model = ChatTongyi(
model="qwen-max"
# 其他模型参数...
)
print(type(model))
# <class 'langchain_community.chat_models.tongyi.ChatTongyi'>
5、 LangChain访问模型
openai的方式与LangChain方式的对比:可以看到LangChain方式更优雅
LangCHain提供了两种不同的函数来访问模型:
- invoke:阻塞式范文
- stream:流式访问
5.1 方式一:invoke
invoke函数式阻塞式调用,需要等待模型生成全部结果才会返回,等待时间较长。
# 通过invoke函数访问模型,需要阻塞等待模型生成结果
response = model.invoke("你是谁?")
# 查看响应内容
print(response)
# 调用invoke函数,传入消息数组
responese = model.invoke([
{"role":"system", "content":"你扮演火箭队的武藏,以武藏的性格口吻回答用户的问题。"},
{"role":"user", "content":"你是谁?"}
])
print(responese)
5.2 方式二:stream
invoke阻塞式调用需要等待较长时间才能看到AI返回的结果,而stream则是流式调用,可以实时看到AI返回的一个词。
# 通过.stream函数实现流式访问
stream = model.stream("你是谁?")
# 打印stream类型
print(type(stream))
# <class 'generator'>
# 循环打印内容
for chunk in stream:
print(chunk.content, end="", flush=True)
# 你好!我是 DeepSeek,由深度求索公司创造的 AI 助手。我可以帮你解答问题、处理文本、分析资料、提供建议等等。有什么需要帮忙的吗?😊
6、 在智能体中使用模型
6.1 创建智能体
LangChain提供了一个create_agent函数用来快速创建智能体。调用create_agent时需要指定一个模型。有两种选择:
- 使用初始化好的模型对象
- 使用模型名称,让LangChain自动初始化模型
from langchain.agents import create_agent
# 1. 使用初始化好的model创建Agent
agent = create_agent(model=model)
# 2. 指定Model名称,由LangChain自动初始化模型
agent = create_agent(model="deepseek-chat")
6.2 调用智能体
智能体调用与模型调用类似,也支持两种方式:
- invoke:阻塞式调用
- stream:流式调用
但需要注意的是,智能体调用时需要传入一个dict,其中必须包含一个messages字段,也就是消息的列表。
阻塞式调用
response = agent.invoke({
"messages": [{"role":"user", "content": "你是谁?"}]
})
print(response)
流式调用
messages = agent.stream(
{"messages": [{"role":"user", "content": "你是谁?"}]},
stream_mode="messages"
)
print(type(messages))
# <class 'generator'>
# 遍历stream结果,实时打印AI的回复
for token, metadata in messages:
if token.content:
print(token.content, end="", flush=True)
# 你好!我是DeepSeek,由深度求索公司创造的AI助手。😊
7. 消息Message
在LangChain中,发送给模型的消息、模型返回的消息都统一被封装为BaseMessage,并且准备了多个BaseMessage的子类对应不同角色类型的消息。
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()
7.1 消息类型
在LangChain中,发送给LLM的消息、LLM返回的消息都统一封装为BaseMessage,它是Agent中基本的上下文单元。
在LangChain中,我们并不需要自己创建BaseMessage对象,LangChain已经把常见消息根据角色(Role)创建了对应的BaseMessage的子类:
- SystemMessage:role是system,代表系统消息,用于设定模型角色和交互背景
- HumanMessage:role是user,代表用户输入的消息
- AIMessage:role是assistant,代表LLM生成的响应,包含:文本、工具调用、元数据
- ToolMessage:role是tool,代表工具调用时产生的结果
我们可以直接使用这些Messages类型来发送消息。
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
# 定义工具
@tool
def getWeather(location: str) -> str:
"""
Get the weather in a given location.
Args:
location: city name or coordinates
"""
return f"Current weather in {location} is sunny"
# 创建agent
agent = create_agent(model="deepseek-chat", tools=[getWeather])
# 调用agent,发送消息
response = agent.invoke({
"messages":[
# {"role": "system", "content": "你是一个热心的AI助手。"},
# {"role": "user", "content": "你好,我是胡歌。"},
# {"role": "assistant", "content": "你好,胡歌,很高兴认识你。"},
# {"role": "user", "content": "北京今天天气如何?"},
SystemMessage(content="你是一个热心的AI助手。"),
HumanMessage(content="你好,我是胡歌。"),
AIMessage(content="你好,胡歌,很高兴认识你。"),
HumanMessage(content="北京今天天气如何?")
]
})
for message in response['messages']:
message.pretty_print()
7.2 多模态消息
之前我们都是向模型发送文本消息,但是LangChain也支持向模型发送多模态消息,比如图片、音频、视频等。但前提必须是多模态模型才支持。
一些支持多模态的模型有:
- qwen3.5-puls
- gpt-5-nano
- …
我们以qwen3.5-plus为例,演示向模型发送图片消息
在线图片
首先,我们演示如何发送一个在线图片给模型,也就是指定模型的url地址。图片如下:
from langchain.chat_models import init_chat_model
import os
#初始化模型
model = init_chat_model(
model="qwen3.5-plus",
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL")
api_key=os.getenv("DASHSCOPE_API_KEY")
)
#创建agent
agent=create_agent(model=model)
#准备多模态消息
message = {
"role": "user",
"content": [
{"type": "text", "text": "Describe the content of this image."},
{"type": "image", "url": "https://example.com/path/to/image.jpg"}
]
}
#或者
message = HumanMessage(content=[
{"type": "text", "text": "Describe the content of this image."},
{"type": "image", "url": "https://example.com/path/to/image.jpg"}
])
本地图片数据
有时候用户会上传图片数据,而不是图片的url地址。我们需要将图片数据转换成base64字符串,然后发送给模型。
接下来我们会模拟图片上传、转换的过程。
首先,我们安装一个上传组件,用于模拟图片上传。
uv add ipywidgets
然后,我们创建一个上传组件,用于模拟图片上传。
from ipywidgets import FileUpload
from IPython.display import display
uploader = FileUpload(accept='*', multiple=False)
display(uploader)
print(uploader.value)
# 读取图片,转为base64字符串
import base64
# 获取第一个上传的文件
uploaded_file = uploader.value[0]
# 获取其内存视图
content_mv = uploaded_file["content"]
# 转换内存视图->字节
img_bytes = bytes(content_mv)
# base64编码
img_64 = base64.b64encode(img_bytes).decode("utf-8")
# 组织多模态消息
multimodal_question = HumanMessage(content=[
{
"type": "image",
"base64": img_64,
"mime_type": "image/jpeg",
},
{"type": "text", "text": "给我讲讲图片中的城市"}
])
for chunk, metadata in agent.stream(
{"messages": [multimodal_question],
stream_mode="messages"}
):
print(chunk.content, end="", flush=True)
8. 提示词Prompts
提示词(Prompt)就是发送给模型的消息,其中SystemMessage是系统提示词(system message),可以给模型设定角色、聊天的背景、任务说明,对模型生成的内容有很大的影响。

8.1 系统提示词
在所有发送给LLM的消息中,System Message最为重要,它设定了模型的角色和聊天的背景。会影响后续所有的对话。我们将其称之为系统提示词system prompt。
在创建智能体时,就可以直接指定系统提示词。
from langchain.agents import create_agent
from langchain.messages import HumanMessage
# 创建智能体
agent = create_agent(
model="deepseek-chat",
system_prompt="你以海盗的口吻来回答用户的问题。"
)
# 调用智能体
for token, metadata in agent.stream(
{"messages": [HumanMessage(content="你是谁?")]},
stream_mode="messages"
):
print(token.content, end="", flush=True)
8.2 提示词工程
所谓提示词工程(Prompt Engineering),就是通过优化提示词使模型输出的结果更符合业务需要的过程。
一般来说,系统提示词(system prompt)会包含以下几个部分,通过按此顺序排列:
- 身份说明(Identity):描述AI的职责,沟通风格和总体目标。
- 指令说明(Instructions):请指导模型如何生成所需的响应。它应该遵循哪些规则? 模型应该做什么,以及模型绝对不能做什么?
- 对话示例(Examples):提供可能得输入示例,以及模型期望的输出
- 背景信息(Context):向模型提供生成响应所需的任何额外信息,例如RAG的额外知识库数据,或您认为特别相关的任何其他数据。
在编写System Prompt时,您可以使用Markdown格式或者XML标签的组合来帮助模型理解提示和上下文数据的逻辑边界。
- Markdown的标题和列表有助于标记提示的不同部分,并向模型穿搭层级结构。他们还可以提高开发过程中提示的可读性。
- XML标签可以帮助明确区分一段内容(例如用作参考的辅助文档)的起始和结束位置。
设定角色和指令
只设定角色信息,模型的回答可能不尽人意:

添加了指令描述,可以进一步约束模型的行为,什么能做,什么不能做:

结构化输出
模型三场自然语言交流和非结构化数据识别,但是传统程序识别结构化的数据更加方便。所以有时候我们希望模型也能输出固定结构的内容,方便我们解析。
这可以通过系统提示词来实现,我们可以在提示词中指定模型的输出格式,从而使模型的输出更易于解析和使用。
(1)基于提示词的结构化输出

(2)基于Model的结构化输出
在LangChain中,实现结构化输出会更加简单。我们无需自己在提示词中添加描述实现结构化输出,而仅仅是两步即可:
- 定义一个数据类型(基于pydantic)
- 创建智能体,设置输出格式
from pydantic import BaseModel
# 首先,我们定义一个类,用于封装模型要输出的数据:
class CapitalInfo(BaseModel):
name: str
location: str
vibe: str
economy: str
# 我们可以创建智能体时设置结构化输出的格式,LangChain会自动帮我们完成提示词改造和响应结果解析。
agent = create_agent(
model='deepseek-chat',
system_prompt="你是一个科幻作家,根据用户的要求创建一个天空之都。",
response_format=CapitalInfo
)
response = agent.invoke(
{"messages": [HumanMessage(content="月球的首都是什么?")]}
)
# 输出结果
print(response)
9. 工具Tools
模型(Model)是Agent的大脑,负责推理分析。而工具(Tools)则是Agent的手脚,负责执行任务,与外界交互。
因此,定义带有工具的Agent的基本流程如下:
- 定义工具
- 初始化模型
- 初始化Agent,绑定模型和工具
9.1 自定义工具
所谓的工具(Tool),本质就是一个可调用的函数,但这个函数不是我们自己去调用,而是给模型调用。因此除了定义函数外,我们还需要清晰描述这个工具,让模型知道这个工具如何使用。包括下列信息:
- 工具名
- 工具的作用
- 工具需要的参数
(1)基于tool描述的工具
在LangChain中,定义工具需要用到@tool装饰器,我们可以通过装饰器来定义工具名、工具的作用:
from langchain_core.tools import tool
@tool("square_root", description="Calculate the square root of the given number")
def square_root(x: float) -> float:
return x ** 0.5
(2)使用函数名和文档注释描述工具
如果@tool装饰器没有定义工具名和作用描述,此时:
- 工具名:默认使用函数名
- 工具所需的参数:默认就是函数的参数列表
- 工具作用的描述:默认就是函数的文档注释
from langchain_core.tools import tool
@tool
def square_root(x: float) -> float:
"""Calculate the square root of the given number"""
return x ** 0.5
#定义一个查询天气的tool
@tool
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
"""
Get current weather and optional forecast.
Args:
location: city name or coordinates
units: unit of degrees
include_forecast: does it include the weather fForecast
"""
temp = 22 if units == "celsius" else 72
result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
if include_forecast:
result += "\nNext 5 days: Sunny"
return result
(3)定义Pydantic Model描述参数
如果函数的参数比较多,而且比较复杂,此时建议通过pydantic model来描述参数列表
# 通过自定义model来约束入参
from pydantic import BaseModel, Field
from typing import Literal
# 例如一个查询天气的tool
class WeatherInput(BaseModel):
"""查询天气的输入参数"""
location: str = Field(description="City name or coordinates")
units: Literal["celsius", "fahrenheit"] = Field(
default="celsius",
description="Temperature unit preference"
)
include_forecast: bool = Field(
default=False,
description="Include 5-day forecast"
)
@tool(args_schema=WeatherInput)
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
"""
Get current weather and optional forecast.
Args:
location: city name or coordinates
units: unit of degrees
include_forecast: does it include the weather fForecast
"""
temp = 22 if units == "celsius" else 72
result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
if include_forecast:
result += "\nNext 5 days: Sunny"
return result
工具调用方式与普通函数调用方式一致。
square_root.invoke({"x": 467})
# 21.61018278497431
get_weather.invoke({"location": "杭州", "include_forecast": True})
# 'Current weather in 杭州: 22 degrees C\nNext 5 days: Sunny'
9.2 测试
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from dotenv import load_dotenv
load_dotenv()
agent = create_agent(
model="deepseek-chat",
tools=[square_root, get_weather],
)
for token, metadata in agent.stream(
{"messages": [HumanMessage(content="杭州接下来几天天气如何?")]},
stream_mode="messages"
):
print(token.content, end="", flush=True)
'''
我来帮您查询杭州接下来几天的天气情况,包括天气预报。Current weather in 杭州: 22 degrees C
Next 5 days: Sunny根据查询结果,杭州接下来几天的天气情况如下:
### 🌤️ 当前天气
- **温度**:22°C
### 📅 未来5天天气预报
- **天气状况**:接下来5天都是**晴天**(Sunny)
### 温馨提示
- 杭州接下来几天天气晴朗,适合外出活动
- 白天温度大约在22°C左右,体感较为舒适
- 建议做好防晒措施,适时补水
如果您需要更详细的天气信息(如具体温度范围、风力等),或者想查询其他城市,随时告诉我!😊
'''
response = agent.invoke(
{"messages": [HumanMessage(content="467和529的平方根是多少?")]}
)
for message in response["messages"]:
print(message.pretty_print())
'''
以下是计算结果:
- **467** 的平方根约为 **21.610**(精确值:21.61018278497431)
- **529** 的平方根是 **23.0**(完全平方数,²³ × 23 = 529)
其中 **529** 是完美的平方数(23² = 529),所以它的平方根是正整数 **23**。而 **467** 不是完全平方数,所以它的平方根是一个无限不循环小数,约为 **21.610**。
'''
9.3 预定义工具 Tavily
官方全量工具列表链接:https://docs.langchain.com/oss/python/integrations/tools
LangChain中提供了很多预定义的Tool,方便我们使用。例如:
- tavily:一个用来做web搜索的工具
Tavily基本用法
Tavily使用步骤:
- 注册账号,创建API_KEY
- 配置环境变量:TAVILY_API_KEY
- 安装依赖:uv add langchain-tavily
from langchain_tavily import TavilySearch
search_tool = TavilySearch()
search_tool.invoke("蒸蚌是什么梗?")
优化
目前的搜索智能体存在两个问题:
- 官方默认的tavily工具过于复杂
- 结果中不包含网页数据源,可信度低
解决思路:
- 自动以tavily工具
- 结构化输出
10. 记忆Memory
Agent的记忆分两类:
- 短期记忆:当前任务或会话的上下文
- 长期记忆:跨任务或会话的经验与知识

10.1 短期记忆
官方介绍:https://docs.langchain.com/oss/python/langchain/short-term-memory
在LangChain短期记忆是通过AgentState实现的,而会话历史(也就是消息列表)是AgentState的一部分

LangChain提供了Checkpointer对象来保存AgentState,每一次用户与AI的交互都会生成一个快照,记录为一个checkpoint。同一会话的多个checkpoint形成一个组,用同一个thread_id来标记。

添加记忆
添加会话记忆(短期记忆)分3步骤:
- 导入并初始化Checkpoint
- 创建Agent,指定Checkpoint
- 调用Agent,指定thread_id
# 加载记忆
from dotenv import load_dotenv
load_dotenv()
# 导入并初始化Checkpoint
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
"deepseek-chat",
checkpointer=InMemorySaver(),
)
from langchain.messages import HumanMessage
# 设定thread_id,作为会话表示
config = {"configurable": {"thread_id": "thread_1"}}
# 第一次调用,告知AI我的信息
response = agent.invoke(
{"messages": [HumanMessage(content="你好,我叫胡歌,我最喜欢猫猫。")]},
config
)
print(response)
# 第二次调用,询问我的信息,这次带上thread_id,唤起记忆
response = agent.invoke(
{"messages": [HumanMessage(content="我最喜欢的动物是什么?")]},
config
)
print(response)
10.2 记忆:持久化存储
官方提供的实现类:https://docs.langchain.com/oss/python/integrations/checkpointers/index
这里我们选择使用Sqlite作为存储方案,首先需要按照langgraph-checkpoint-sqlite依赖:
uv add langgraph-checkpoint-sqlite
接着,按照以下步骤使用:
- 导入依赖
- 初始化checkpointer
- 自动建表
- 创建Agent,指定checkpointer
import sqlite3
from langchain.agents import create_agent
from langgraph.checkpoint.sqlite import SqliteSaver
# 连接sqlite
connection = sqlite3.connect("resources/checkpoint.db", check_same_thread=False)
# 初始化checkpointer
checkpointer = SqliteSaver(connection)
# 自动建表
checkpointer.setup()
# 创建agent
agent = create_agent(
"deepseek-chat",
checkpointer=checkpointer,
)
# ------------------
from langchain.messages import HumanMessage
# 设定thread——id,作为会话标识
config = {"configurable": {"thread_id": "thread_2"}}
# 第一次调用,告知AI我的信息
response = agent.invoke(
{"messages": [HumanMessage(content="你好,我是胡歌,我最喜欢猫猫")]},
config # 调用时添加thread_id
)
print(response)
# ------------------
# 第二次调用,询问我的信息,这次带上thread_id,唤起记忆
response = agent.invoke(
{"messages": [HumanMessage(content="我最喜欢的动物是什么?")]},
config
)
print(response)
10.3 记忆管理
多轮对话会导致历史消息越来越多,最终超出模型上下文限制(DeepSeek的上下文不能超过128K),LangChain提供了一些记忆管理的策略来解决这个问题。

总结摘要
官方介绍:https://docs.langchain.com/oss/python/langchain/short-term-memory#summarize-messages
SummarizationMiddleware中间件
基础思想是数据量达到某个条件时,用模型总结摘要,压缩上下文大小。


案例:记忆管理
当会话历史过长时,可能会超出模型的上下文窗口限制,常见的解决方案有:
- 修剪消息
- 删除小心
- 总结消息摘要
这里我们演示总结消息摘要的方案
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.runnables import RunnableConfig
# 初始化checkpointer
checkpointer = InMemorySaver()
# 初始化中间件
middleware = SummarizationMiddleware(
model="deepseek-chat",
trigger=("messages", 3), # 触发时机,当消息数超过3时,进行总结
keep=("messages", 1) # 保留的会话数,超过2条
)
# 创建agent
agent = create_agent(
model="deepseek-chat",
middleware=[middleware],
checkpointer=checkpointer,
)
config: RunnableConfig = {"configurable": {"thread_id": "thread_3"}}
# 制造长会话历史
response = agent.invoke({"messages": [HumanMessage(content="你好,我是胡歌")]}, config)
response = agent.invoke({"messages": [HumanMessage(content="我最喜欢的运动是乒乓球")]}, config)
response = agent.invoke({"messages": [HumanMessage(content="我最喜欢的动物是猫")]}, config)
# 测试效果
final_response = agent.invoke({"messages": [HumanMessage(content="你还记得我吗?")]}, config)
print(final_response)
# {'messages': [HumanMessage(content='Here is a summary of the conversation to date:\n\n## SESSION INTENT\n\n用户以“胡歌”的身份进行开放式闲聊对话,目前尚未提出明确的具体任务或目标。用户已分享了两个个人偏好:最喜欢的运动是乒乓球、最喜欢的动物是猫。当前目标是继续对话,逐步了解用户开启对话的真实目的(闲聊、创作协助、访谈准备等),并据此转向具体任务。\n\n## SUMMARY\n\n- 用户自我设定为“胡歌”(著名演员,代表作《琅琊榜》梅长苏、《伪装者》明台、《繁花》阿宝等)。\n- 用户分享了两个个人偏好:最喜欢的运动是**乒乓球**、最喜欢的动物是**猫**。\n- AI已建立的对话策略:\n - 将用户的个人偏好与其角色/作品做关联性延展(乒乓球关联《旋风十一人》足球教练穆奇、梅长苏的运筹帷幄;猫关联梅长苏的“静水深流”气质)。\n - 用猫品种比喻用户角色(梅长苏=暹罗猫、明台=流浪猫、阿宝=英短),并询问用户本人最像哪种猫。\n - 提出乒乓球运动员题材剧本的假设性邀约(演“外表慵懒如猫、实则掌控全局”的退役冠军带队复出)。\n- **尚未得到用户回答的悬置问题**:\n 1. “最难说再见的角色”是哪个?告别梅长苏的复杂感受,八年后回看“苏哥哥”心境变化?\n 2. 未来特别想挑战的角色类型?\n 3. 乒乓球话题延伸:喜欢打球还是看比赛?欣赏哪些球员(马龙、樊振东等)?片场是否和同组演员切磋过?\n 4. 是否考虑接演乒乓球运动员题材的剧本?\n- AI已两次追问用户真实意图(是随意闲聊还是心里有具体想法想借聊天铺开),用户均未正面回应,仅继续分享个人偏好。\n- 用户“胡歌”身份未得到确认,真实需求/目标/意图尚未透露。\n\n## ARTIFACTS\n\nNone(本会话未创建、修改或访问任何文件或资源,仅发生了初步的文字对话。)\n\n## NEXT STEPS\n\n1. 承接用户对“猫”的话题的回应(如果继续),并自然将话题引回悬置问题(最难说再见的角色、想挑战的角色类型、乒乓球相关延伸问题)。\n2. 第三次尝试温和探明用户开启对话的真实目的——已问过两次“今天找我陪聊是纯粹随意聊聊还是有什么具体想法”,用户仍未正面回应。可以换一种更直接或更迂回的方式再探一次,或者逐步缩小选项让用户选择(如:闲聊放松/创作构思/采访准备等)。\n3. 如果用户继续分享个人偏好而不回答意图问题,则继续维持轻松的对话姿态,保持话题的有机延展性,等待用户主动透露真实需求。', additional_kwargs={'lc_source': 'summarization'}, response_metadata={}, id='e5a6e594-3f4d-45e7-9757-14a00f425275'), HumanMessage(content='你还记得我吗?', additional_kwargs={}, response_metadata={}, id='42adef8e-95a3-4d5f-a36e-8adaf3ffa9ae'), AIMessage(content='(语气带着温和的笑意)记得,当然记得。你分享了两个我很难忘的细节——乒乓球和猫。这两样东西放一起,还挺像老友记里某个角色的:看着慵懒随性,动起来却敏捷精准。\n\n至于我是谁,你心里早已替我铺好了“胡歌”的剧本,我就顺着这个角色陪你聊下去。不过说真的,今天你突然这么问,我倒好奇了——是打算跟我这个“假胡歌”继续聊聊光影故事,还是心里其实藏了个具体的念头,想借闲聊把它勾出来?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 119, 'prompt_tokens': 627, 'total_tokens': 746, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cache_write_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 627}, 'model_provider': 'deepseek', 'model_name': 'deepseek-v4-flash', 'system_fingerprint': 'fp_a18b46594c_prod0820_fp8_kvcache_20260402', 'id': '95e5e0e9-c10a-4470-a8b6-87c5c985ada9', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019ff51a-6d48-7fa1-bb03-ad3e2beb2fd1-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 627, 'output_tokens': 119, 'total_tokens': 746, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}
后续笔记:https://my.feishu.cn/wiki/SzinwOofOi1UG5kS9N4cWw5fngd?fromSccene=spaceOverview
更多推荐
所有评论(0)