LangChain的入门教程
原文链接:Mint-Blog——LangChain
部分内容参考来自 黑马程序员2026最新版LangChain+LangGraph开发实战全套视频课程
1. 相关概念
1.1 神经网络结构
深度神经网络分为很多层,是神经网络基本的计算单元,分为
- 输入层(
Input Layer):入口,接收数据 - 隐藏层(
Hidden Layer):信息处理和学习。可以有很多层。 - 输入层(
Output Layer):出口,产生结果
1.2 反向传播
反向传播(Back propagation):根据前向传播产生的预测结果与真实值之间的误差,从输出层开始,反向逐层计算每个参数(权重和偏置)对总误差的"贡献"大小(即梯度),并据此更新参数。这是一个学习过程。
基本流程如下:
- 前向传播:数据逐层加工,直到输出层产出结果
- 计算误差:计算产出结果与正确结果的误差(
Loss) - 反向追责:倒推计算每一层的每个连接对误差的贡献
- 调整权重:根据每个连接的误差贡献比例,调整其权重参数,使误差变小
1.3 词向量
词向量(Word Embedding)就是把词转为多维空间向量的一种技术。
- 将人类自然语言文字拆分为一个个片段,称为
Token(词) - 每个Token都经过模型计算转为一个浮点数数组,作为向量坐标
- 目标:使词向量在多维空间中的不同方向表达不同的语义

1.4 Transformer自注意力机制
注意力机制(self-attention):其使得模型能够更加高效的根据上下文信息处理Token,理解Token含义。
1.5 MLP
多层感知机(Multi-Layer Perceptron)是层级化、全连接的神经网络结构,层与层之间无跳过、无循环,神经元之间全连接(相邻层的任意两个神经元都有连接)
1.6 SoftMax
归一化指数函数(SoftMax)会根据模型计算出的向量结果得出下一个token的概率分布,然后基于概率的随机采样方式挑选一个作为结果。
这个概率受模型的温度系数(Temperature)参数影响,值越大,概率分布越均匀,模型生成结果的随机性越强;反之,结果越确定
温度系数(Temperature)是控制大模型生成文本随机性和多样性的关键参数。"它通过调整模型输出的概率分布,直接影响生成结果的保守性”(值小)或“创造性”(值大)。

1.7 大语言模型
Transformer本来是作为翻译用的,但当模型参数规模和训练数据量增突破某个临界点时,模型像是突然拥有了智能,不仅可以理解人类语言,还能推理、分析。
这种现象被称为“涌现”(Emergent Abiities)。这种超大规模的语言模型则被称为大语言模型(Large Language Model)
GPT是指
- 生成式(
Generative):根据上文预测紧跟着的下一个Token,从而形成连续的文本输出 - 预训练(
Pre-trained):通过大规模的文本数据进行训练,让大模型可以理解人类语言的语法、词性。 Transformer:深度学习的一种神经网络结构。多数大模型都依赖于此。
大语言模型(Large Language Model, LLM)是指模型的参数规模、训练数据量、训练成本、智能程度都远超普通模型的一种神经网络模型。
1.8 认识LangChain
LangChain 由 Harrison Chase 创建于2022年10月,是用于开发智能体工程(Agent Engineering)的平台。
LangChain自身并不开发LLMS,它的核心理念是为各种LLMs实现通用的接口,把LLMs相关的组件“链接”在一起,简化LLMs应用的开发难度,方便开发者快速地开发复杂的LLMs应用.
主要功能:
- Prompts:优化提示词(提示词工程)
- Models:调用各类模型
- History:管理会话历史记录(记忆)
- Indexes:管理和分析各类文档
- Chains:构建功能的执行链条
- Agent:构建智能体
1.9 Agent
在人工智能领域,Agent(通常翻译为智能体或代理)是指一种能够感知环境、进行推理、自主决策并采取行动以实现特定目标的智能系统。
2. 大模型API
2.1 CURL接口调用
2.1.1 DeepSeek
curl https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \ # 请求头:告诉服务器请求体是 JSON 格式
-H "Authorization: Bearer ${DEEPSEEK_API_KEY}" \ # 请求头:Bearer 认证,${} 表示从环境变量读取 API Key
-d '{ # -d 参数:指定要发送的 JSON 数据体
"model": "deepseek-v4-pro", # 模型名称
"messages": [ # 对话消息数组(按时间顺序排列)
{"role": "system", "content": "You are a helpful assistant."},
# system 角色:设定模型的行为、人格和回复风格(可选)
{"role": "user", "content": "Hello!"}
# user 角色:表示用户输入的内容
],
"thinking": {"type": "enabled"}, # 深度思考开关:enabled 开启后模型会先输出内部推理链
"reasoning_effort": "high", # 推理强度:指定思考深度,可选 low/medium/high(仅在 thinking 开启时生效)
"stream": false # 流式输出:false 表示一次性返回完整结果;true 表示逐字流式输出
}'
2.1.2 百炼
curl -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.6-plus",
"messages": [
{
"role": "user",
"content": "你是谁?"
}
]
}'
# 返回结果
{
"choices": [
{
// 消息对象:包含完整的对话内容
"message": {
"role": "assistant", // 角色:assistant 表示这是模型的回复(与 user 对应)
"content": "你好!我是Qwen..." // 实际生成的文本内容
},
"finish_reason": "stop", // 结束原因:stop 表示正常完成(未触发生成长度限制)
"index": 0, // 索引号:当一次请求生成多个回复时的序号(0 表示第一个)
"logprobs": null // 对数概率:通常为 null,需单独开启才返回 token 级别的概率信息
}
],
"object": "chat.completion", // 对象类型:固定值,表示这是一个对话补全请求的响应
// Token 使用统计:按量计费的关键数据
"usage": {
"prompt_tokens": 12, // 输入 token 数:用户发送的消息 + 系统提示词消耗的 token
"completion_tokens": 77, // 输出 token 数:模型生成回复消耗的 token
"total_tokens": 89 // 总 token 数:12 + 77 = 89(本次 API 调用的计费依据)
},
"created": 1680300000, // 创建时间:Unix 时间戳(秒),记录本次请求的生成时间
"system_fingerprint": null, // 系统指纹:通常为 null,用于后端调试或版本追踪
"model": "qwen-plus-2025-07-28", // 实际使用的模型:确认请求时指定的模型生效
"id": "XX" // 请求唯一标识:用于排查问题和追踪调用记录
}
2.2 会话记忆
DeepSeek
多轮对话,内容来源官网
DeepSeek /chat/completions API 是一个“无状态” API,即服务端不记录用户请求的上下文,用户在每次请求时,需将之前所有对话历史拼接好后,传递给对话 API。
下面的代码以 Python 语言,展示了如何进行上下文拼接,以实现多轮对话。
from openai import OpenAI
client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")
# Round 1
messages = [{"role": "user", "content": "What's the highest mountain in the world?"}]
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages
)
messages.append(response.choices[0].message)
print(f"Messages Round 1: {messages}")
# Round 2
messages.append({"role": "user", "content": "What is the second?"})
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages
)
messages.append(response.choices[0].message)
print(f"Messages Round 2: {messages}")
在第一轮请求时,传递给 API 的 messages 为:
[
{"role": "user", "content": "What's the highest mountain in the world?"}
]
在第二轮请求时:
- 要将第一轮中模型的输出添加到
messages末尾 - 将新的提问添加到
messages末尾
最终传递给 API 的messages为:
[
{"role": "user", "content": "What's the highest mountain in the world?"},
{"role": "assistant", "content": "The highest mountain in the world is Mount Everest."},
{"role": "user", "content": "What is the second?"}
]
2.3 客户端调用
from dotenv import load_dotenv
import os
from openai import OpenAI
load_dotenv()
api_key = os.getenv("API_KEY")
client = OpenAI(
api_key=api_key,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
response = client.chat.completions.create(
model="XXX",
messages=[
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "Hello"},
],
stream=False
)
print(response.choices[0].message.content)
# Hello! How can I assist you today?
3. LangChain使用
3.1 Demo案例
# uv add langchain
# uv add langchain-openai
# uv add python-dotenv
# 在.env文件中添加
# OPENAI_API_KEY=XXXXXXXXX
# OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY") # 获取API KEY
# 定义工具
from langchain.tools import tool
@tool
def getWeather(location:str)->str:
"""
获取指定位置的天气信息。
参数:
location: 城市名称,如"北京"、"上海"
"""
# 模拟天气数据(实际使用中可以替换成真实API)
weather_db = {
"北京": "晴天 25°C",
"上海": "多云 28°C",
"深圳": "阵雨 30°C",
"广州": "阴天 27°C",
"杭州": "晴转多云 26°C"
}
# 查找天气
if location in weather_db:
result = f"{location}天气:{weather_db[location]}"
else:
# 默认返回通用天气
result = f"{location}天气:晴 22°C"
return result
# 创建agent
from langchain.agents import create_agent
agent = create_agent(
model="openai:qwen-plus",
tools=[getWeather]
)
# 发起调用
response = agent.invoke({
"messages": [
{"role": "user", "content": "今天深圳天气如何"},
]
})
print(response)

3.2 init_chat_model初始化
init_chat_model是 LangChain 提供的一个统一模型初始化函数,它的核心作用是:用同一套代码,无缝切换不同提供商的大语言模型。
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
import os
# 在.env文件中添加
# OPENAI_API_KEY=XXXXXXXXX
# OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
load_dotenv()
model = init_chat_model(
model="qwen-plus-2025-07-28",
model_provider="openai", # 提供商(qwen不支持自动识别,因此伪装为openai)
temperature=0.7, # 随机性
max_tokens=1024, # 输出最大token数
timeout=10, # 请求超时秒数
max_retries=3, # 失败重试次数
top_p=0.5, # 范围 0-1,通常与 temperature 二选一调整
stop=["4.", "4)", "4、"] # 用于控制回复的结束位置
)
response = model.invoke("你好,请介绍一下自己")
print(response.content)
print(type(model))
# <class 'langchain_openai.chat_models.base.ChatOpenAI'>
3.3 调用方式
3.3.1 invoke
- invoke函数是阻塞式调用,需要等待模型生成全部结果才会返回,等待时间较长
response = model.invoke("message")
response = model.invoke([
{"role":"system","content":"你是一个AI助手"},
{"role":"user","content":"介绍你自己"},
])
3.3.2 stream
invoke阻塞式调用需要等待较长时间才能看到AI返回的结果,而stream则是流式调用,可以实时看到AI返回的一个个词。
stream = model.stream("你好,请介绍一下自己")
print( type(stream)) # <class 'generator'>
for chunk in stream: # 只可遍历一次即内容用完了
print(chunk.content,end="")
# 你好!我是......
4. 智能体使用模型
4.1创建智能体
Langchain提供了一个create_agent函数用来快速创建智能体。调用create_agent时需要指定一个模型。有两种选择:
- 使用初始化好的模型对象
- 使用模型名称,让Langchain自动初始化模型
from langchain.agents import create_agent
# 方法1:初始化已经定义好的model
agent = create_agent(model=model)
# 方法2:指定model名称
agent1 = create_agent("openai:qwen-plus-2025-07-28")
4.2 调用智能体
智能体调用与模型调用类似,也支持两种方式:
- invoke:阻塞式调用
- stream:流式访问
但需要注意的是,智能体调用时需要传入一个dict,其中必须包含一个messages字段,也就是消息的列表。
# 方法1:invoke
response = agent1.invoke({
"messages": [{"role":"user","content":"Hi"}]
})
print(response["messages"][-1].content)
# Hello! ٩(◕‿◕。)۶ How can I assist you today?
# 方法2:stream
response = agent.stream(
{"messages": [{"role":"user","content":"Hi"}]},
stream_mode="messages"
)
for token, metadata in response:
if token.content:
print(token.content,end="",flush=True)
5. 消息
消息(message),在LangChain中,发送给模型的消息、模型返回的消息都统一被封装为BaseMessage,并且准备了多个BaseMessage的子类对应不同角色类型的消息。
- SystemMessage -> Role: system,代表系统消息,用于设定模型角色和交互背景
- HumanMessage -> Role: user,代表用户输入的消息
- AIMessage -> Role: assistant,代表LLM生成的响应,包含:文本、工具调用、元数据
- ToolMessage -> Role: tool,代表工具调用时产生的结果
我们可以直接使用这些Messages类型来发送消息,以此替代消息数组
5.1 文本消息
'''省略部分,可参考 3.LangChain使用 - 3.1Demo案例'''
# 发起调用
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
response = agent.invoke({
"messages": [
SystemMessage("可以使用工具获取天气状态"),
HumanMessage("你好"),
AIMessage("你好我是DeepSeek,请问有什么可以帮忙的?"),
HumanMessage("香港的天气怎么样?")
]
})
print(response["messages"][-1].content)
# 香港目前天气晴朗,气温为22°C,非常舒适。建议穿着轻便衣物,适合外出活动。
for message in response["messages"]:
message.pretty_print()
'''
=== System Message ========================
可以使用工具获取天气状态
=== Human Message =========================
你好
=== Ai Message ============================
你好我是DeepSeek,请问有什么可以帮忙的?
=== Human Message =========================
今天香港天气怎么样?
===Ai Message =============================
Tool Calls:
getWeather (call_XXX)
Call ID: call_XXX
Args:
location: 香港
=== Tool Message ==========================
Name: getWeather
香港天气:晴 22°C
==== Ai Message ===========================
今天香港天气晴朗,气温为22°C。适合外出活动哦!
'''
5.2 多模态消息
LangChain也支持向模型发送
多模态消息,比如图片、音频、视频、文本等。但前提是必须是多模态模型才支持。以
qwen3.5-omni-flash-2026-03-15为例子
5.2.1 在线图片
# 发送在线图片消息,多模态
from langchain.chat_models import init_chat_model
# 初始化模型
model = init_chat_model(
model="qwen3.5-omni-flash-2026-03-15",
model_provider="openai",
temperature=0.7,
max_tokens=1024
)
# 创建agent
agent = create_agent(model=model)
# 准备多模态消息
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
message = HumanMessage(
[
{"type":"text","text":"这是谁?请通过这张图片的内容进行简要回答即可"},
{"type":"image","url":"https://......."}
]
)
# 发送请求
stream = agent.stream(
{"messages": [message]},
stream_mode="messages"
)
for token, metadata in stream:
if token.content:
print(token.content,end="",flush=True)
5.2.2 本地图片
有时候用户会上传图片数据,而不是图片的url地址。我们需要将图片数据转换
base64字符串,然后发送给模型。使用插件
模拟图片上传、转换的过程。uv add ipywidgets
from ipywidgets import FileUpload # 导入文件上传组件
from IPython.display import display # 导入显示函数
'''
创建上传控件
1. accept='*' : 接受所有文件类型(也可以指定如 '.txt,.pdf')
2. multiple=False : 不允许同时上传多个文件(True 则允许)
'''
uploader = FileUpload(accept='*', multiple=False)
display(uploader) # 在 notebook 中显示这个控件
print (uploader.value)
# ({'name': 'OIP-C.jpeg', 'type': 'image/jpeg', 'size': 42998, 'content': <memory at 0x147d32800>, 'last_modified': datetime.datetime(2026, 1, 3, 12, 24, 29, 700000, tzinfo=datetime.timezone.utc)},)
# 读取图片,转为base64字符串
import base64
uploaded_file = uploader.value[0] # 获取第一个上传的文件
content_mv = uploaded_file["content"] # 获取其内存视图
img_bytes = bytes(content_mv) # # 转换内存视图->字节 or content_mv.tobytes()
img_b64 = base64.b64encode(img_bytes).decode( "utf-8") # base64编码
# 组织多模态消息
picture_question = HumanMessage(content=[
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{img_b64}"}
},
{"type":"text","text":"简要介绍这个图片里是谁"}
])
# 遍历结果
for chunk,metadata in agent.stream(
{"messages":[picture_question]},
stream_mode="messages"
):
print(chunk.content,end="",flush=True)
6. 提示词
6.1 系统提示词
提示词(Prompt)就是发送给模型的消息,其中SystemMessage是系统提示词(system prompt),可以给模型设定角色、聊天的背景、任务说明,对模型生成的内容有很大的影响。
通过在定义agent的过程中,利用参数system_prompt进行声明相关内容
from langchain.agents import create_agent
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv
load_dotenv()
# 创建model
model = init_chat_model(
model="qwen-plus-2025-07-28",
model_provider="openai",
temperature=0.7,
max_tokens=1024
)
# 创建agent
agent = create_agent(
model=model,
system_prompt="请你以XXX的语气并进行简短回答",
)
# 调用智能体
for token, metadata in agent.stream(
{
"messages": [HumanMessage(content="你是谁?")]
},
stream_mode="messages"
):
print(token.content,end="",flush=True)
6.2 提示词工程
所谓提示词工程(Prompt Engineering),就是通过优化提示词使模型输出的结果更符合业务需要的过程
一般来说,系统提示词(SystemPrompt)会包含以下几个部分,通常按此顺序排序
- 身份角色(
Identity):描述AI的职责、沟通风格和总体目标。 - 指令说明(
Instructions):请指导模型如何生成所需的响应。它应该遵循哪些规则?模型应该做什么,以及模型绝对不能做什么? - 对话示例(
Examples):提供可能的输入示例,以及模型期望的输出. - 背景信息(
Context):向模型提供生成响应所需的任何额外信息,例如RAG的额外知识库数据,或您认为特别相关的任何其他数据。
在编写System Prompt时,您可以使用Markdown格式和XML标签的组合来帮助模型理解提示和上下文数据的逻辑边界。
- Markdown的标题和列表有助于标记提示的不同部分,并向模型传达层级结构。它们还可以提高开发过程中提的可读性。
- XML标签可以帮助明确区分一段内容(例如用作参考的辅助文档)的起始和结束位置。
6.2.1 设定角色和指令
添加了指令描述,可以进一步约束模型的行为,什么能做,什么不能做
'''
# 身份
- 你是一个编程助手,你帮助用户编写Python代码
# 指令
- 定义变量时,使用snake case命名法,而不是camel case命名法。
- 不要返回markdown格式说明,仅仅返回代码即可。
'''
6.2.2 对话示例
Few-shot示例是一种为模型提供多个示例的方法,以便它可以学习行为模式并生成更准确的响应。
'''
# 身份
- 你是一个文本分类助手
# 指令
- 请严格遵循以下示例的模式进行分类
- 只返回分类结果,不输出任何额外解释
# 示例
- 输入:"这个产品太棒了!" → 正面
- 输入:"质量很差,不推荐。" → 负面
- 输入:"还可以吧,凑合用。" → 中性
# 输出格式
- 只输出:正面 / 负面 / 中性
'''
6.2.3 结构化输出
模型擅长自然语言交流和非结构化数据识别,但是传统程序识别结构化的数据会更加方便。所以有时候我们希望模型也能输出固定结构的内容,方便我们解析。
这可以通过系统提示词来实现,我们可以在提示词中指定模型的输出格式,从而使模型的输出更易于解析和使用。
- 基于提示词的结构化输出
'''
# 身份
- 你是一个信息提取助手,负责从用户输入中提取结构化数据
# 指令
- 严格按 JSON 格式输出
- 只输出 JSON,不输出任何额外解释或标记
- 缺失的字段用 null 填充
# 输出格式
{
"name": "姓名",
"age": "年龄(数字)",
"city": "城市",
"occupation": "职业"
}
# 示例
用户输入:"我叫张三,今年25岁,在上海做工程师"
输出:
{"name": "张三", "age": 25, "city": "上海", "occupation": "工程师"}
用户输入:"李四,北京"
输出:
{"name": "李四", "age": null, "city": "北京", "occupation": null}
'''
- 基于Model的结构化输出
在LangChain中,实现结构化输出会更加简单。我们无需自己在提示词中添加描述实现结构化输出,而仅仅是两步即可:
- 定义一个数据类型(基于
pydantic) - 创建智能体,设置输出格式
在构建agent中,使用参数response_format
from pydantic import BaseModel
# 定义类,用于封装模型所需要输出的数据结构:
class CapitalInfo(BaseModel):
name: str # 城市名称
location: str # 地理位置
vibe: str # 城市特色/氛围
economy: str # 经济发展
agent = create_agent(
model = model,
system_prompt="你是一个科幻作家,根据用户的要求创建一个太空之都。",
response_format=CapitalInfo
)
response = agent.invoke(
{"messages":[HumanMessage("月球的首都在哪里?")]}
)
city = response['structured_response']
print(city) # name='月影城' location='月球静海基地' vibe='宁静而科技感十足' economy='以太空科研和氦-3能源产业为主'
7. 工具
模型(Mode)是Agent的大脑,负责推理分析。而工具(Tools)则是Agent的手脚,负责执行任务,与外界交互。
一个完整的Agent至少要包含两个关键的部分:
- 模型:是Agent的大脑,负责推理、分析,规划任务步骤
- 工具:是Agent的手脚,负责执行任务,与外界交互
因此,定义带有工具的Agent的基本流程如下:
- 定义工具
- 初始化模型
- 初始化Agent,绑定模型和工具

7.1 自定义工具
所谓的工具(Tool),本质就是一个可调用的函数,但是这个函数不是我们自己去调用,而是给模型调用。因此除了定义函数外,我们还需要清晰描述这个工具,让模型知道这个工具如何使用。包括下列信息:
- 工具名称
- 工具的作用
- 工具所需要的参数
- 基于Tool描述工具
在LangChain中,定义工具需要用到@tool装饰器,我们可以通过装饰器来定义工具名、工具的作用:
from langchain_core.tools import tool
@tool("square_tool",description="用于计算一个数的平方根值")
def square_tool(x:float)->float:
return x**2
- 使用函数名和文档注释描述工具
如果不使用@tool装饰器没有定义工具名和作用描述,此时:
- 工具名:默认就是函数名
- 工具所需的参数:默认就是函数的参数列表
- 工具作用的描述:默认就是函数的文档注释
from langchain_core.tools import tool
@tool
def square_tool(x:float)->float:
"""用于计算一个数的平方值"""
return x**2
@tool
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
"""
获取当前天气和可选的天气预报。
参数:
location: 城市名称或坐标
units: 温度单位
include_forecast: 是否包含天气预报
"""
temp = 22 if units == "celsius" else 72
result = f"{location}当前天气:{temp} 度 {units[0].upper()}"
if include_forecast:
result += "\n未来5天:晴朗"
return result
get_weather.invoke({"location":"HongKong","units":"celsius","include_forecast":False})
- 定义PydanticModel描述参数
如果函数的参数比较多,而且比较复杂,此时建议通过pydantic model来描述参数列表。
# 通过自定义模型约束入参
from pydantic import BaseModel, Field
from typing import Literal # 枚举
# 天气查询工具的输入参数模型
class WeatherInput(BaseModel):
location: str = Field(description="城市名或坐标")
units: Literal["celsius", "fahrenheit"] = Field(
default="celsius",
description="温度单位"
)
include_forecast: bool = Field(
default=False,
description="是否包含5天预报"
)
@tool(args_schema=WeatherInput) # 参数约束 args_schema
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
"""获取当前天气和可选的天气预报。"""
temp = 22 if units == "celsius" else 72
result = f"{location}当前天气:{temp} 度 {units[0].upper()}"
if include_forecast:
result += "\n未来5天:晴朗"
return result
7.2 预定义工具
以TavilySearch为例,每月1000次免费搜索(实际情况以官网为准)
- 初步认识工具
from langchain_tavily import TavilySearch
from dotenv import load_dotenv
import os
load_dotenv()
search_tool = TavilySearch(
max_results=5, # 最大返回结果数
topic="general", # 搜索主题:general/news/finance
# include_answer=False, # 是否包含AI生成答案
# include_raw_content=False, # 是否包含完整页面内容
# include_images=False, # 是否包含图片列表
# include_image_descriptions=False,# 是否包含图片描述
# search_depth="basic", # 搜索深度:basic/advanced
# time_range="day", # 时间过滤:day/week/month/year
# include_domains=None, # 限定域名列表
# exclude_domains=None # 排除域名列表
)
search_tool.invoke({"query": "上周热点新闻有哪些?简短回答即可"})
- 实践使用
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain.messages import HumanMessage, AIMessage, SystemMessage
model = init_chat_model(
model="qwen-plus-2025-07-28",
model_provider="openai",
temperature=0.7,
max_tokens=1024
)
agent = create_agent(
model=model,
tools=[search_tool]
)
response = agent.invoke(
{"messages":[HumanMessage("上周知乎热点有哪些,简要回答列表10个即可")]}
)
print(response["messages"][-1].content)
- 工具优化
- 使用
@tool装饰器将 TavilySearch 实例包装为 LangChain 工具,使其可被 Agent 直接调用 - 定义
AnswerInfo和Reference结构化输出模型,强制 Agent 返回包含答案和引用来源的规范格式
tavily = TavilySearch(
max_results=5,
topic="general",
)
@tool
def web_search(query:str):
"""用于Web网页信息检索"""
return tavily.invoke(query)
from pydantic import BaseModel,Field
# Agent回答内容引用的网页信息
class Reference(BaseModel):
title: str = Field(description="答案中引用的网页标题")
url: str = Field(description="答案中引用的网页链接")
# Agent的回答内容
class AnswerInfo(BaseModel):
answer: str = Field(description="给用户的最终答案")
reference: list[Reference] = Field(description="答案所引用的网页")
model = init_chat_model(
model="qwen-plus-2025-07-28",
model_provider="openai",
temperature=0.7,
max_tokens=1024
)
agent = create_agent(
model=model,
tools=[web_search],
system_prompt="你是一个智能助手,用于解决用户问题",
response_format=AnswerInfo # 控制 Agent 返回结构化数据的核心参数
)
response = agent.invoke(
{"messages":[HumanMessage("知乎今日热点都有哪些?")]}
)
structured = response["structured_response"]
print("=== 答案 ===")
print(structured.answer)
print("\n=== 引用来源 ===")
for idx, ref in enumerate(structured.reference, 1):
print(f"{idx}. {ref.title}")
print(f" 链接:{ref.url}")
'''
=== 答案 ===
知乎的今日热点内容通常包括实时讨论度高的社会事件、科技动态、文化娱乐等话题。您可以通过知乎App或网页端的“今日热点”话题页(如 https://www.zhihu.com/topic/23509571)查看最新热门讨论。此外,聚合类平台如“今日热榜”(tophub.today)也提供知乎实时热点榜单,便于一站式浏览全网热点。
=== 引用来源 ===
1. 今日热点 - 知乎
链接:https://www.zhihu.com/topic/23509571
2. 真的能追溯微博、知乎等历史热门榜单吗?
链接:https://zhuanlan.zhihu.com/p/1925271264437733172
'''
8. 会话记忆
记忆(Memory)分为两种:
- 短期记忆(
short-term memory):当前任务或会话的上下文。如对话历史、查询结果、任务状态 - 长期记忆(
long-term memory): 跨任务或会话的经验和知识。如知识库、用户偏好、失败经验
8.1 基于内存记忆存储
在LangChain短期记忆是通过Agentstate实现的,而会话历史(也就是消息列表)是AgentState的一部分。
- LangChain提供了
Checkpointer对象来保存Agentstate,每一次用户与AI的交互都会生成一个快照,记录为一个checkpoint。 - 同一个会话的多个checkpoint形成一个组,用同一个
thread_id来标记。

# `langgraph`使用该软件包导入记忆会话功能
from langgraph.checkpoint.memory import InMemorySaver
# 在agent创建时,checkpointer参数使用
agent = create_agent(
model=model,
tools=[],
checkpointer=InMemorySaver(),
)
config = {"configurable":{"thread_id":"thread_1"}} # 创建配置线程
response = agent.invoke( # 第一次调用
{"messages":[HumanMessage("你好,我是masshiro,我喜欢anime")]},
config=config # 使用配置
)
print(response["messages"][-1].content) # qwen:啊,你好呀 Masshiro! 很高兴认识一位喜欢 anime 的小伙伴~
response = agent.invoke( # 第二次调用
{"messages":[HumanMessage("我喜欢什么东西,叫什么名字?")]},
config=config
)
print(response["messages"][-1].content) # qwen:啊,你刚才提到你是 **Masshiro**,而且特别喜欢 **anime(动漫)** 呢!
8.2 基于数据库记忆存储
在生产环境中Langchain建议使用数据库进行会话记忆存储。
使用数据库进行存储步骤如下:
- 导入依赖
- 初始化checkpointer
- 自动创建表
- 创建Agent,指定checkpointer
# uv add langgraph-checkpoint-postgres
from langgraph.checkpoint.postgres import PostgresSaver # 导入 PostgreSQL 检查点存储
DB_URI = "postgresql://localhost/postgres" # 数据库连接字符串(URI)
with PostgresSaver.from_conn_string(DB_URI) as checkpointer: # 创建数据库连接
checkpointer.setup() # 初始化数据表(首次运行)
agent = create_agent(
model=model, # 语言模型
tools=[],
checkpointer=checkpointer, # 启用会话记忆
)
config = {"configurable": {"thread_id": "thread_1"}} # 会话配置(线程ID)
# 第一次对话:自我介绍
resp = agent.invoke(
{"messages": [HumanMessage("你好,我是Aki")]},
config=config
)
print("AI_1:\n" + resp["messages"][-1].content)
# 第二次对话:测试记忆功能
resp2 = agent.invoke(
{"messages": [HumanMessage("我叫什么名字?")]},
config=config # 使用相同的 thread_id
)
print("AI_2:\n" + resp2["messages"][-1].content)

8.3 记忆管理策略
多轮对话会导致历史消息越来越多,最终超出模型的上下文限制。因此LangChain提供了一些记忆管理的策略来解决这个问题。
- 修剪(
Ttim):拿到消息历史后,先移除前N条或后N条消息,再调用模型 - 删除(
Delete):永久删除AgentState的快照 - 总结摘要(
Summarize):先总结历史消息中的早期消息,得到消息摘要。然后用消息摘要和最近的消息形成消息列表,再调用模型 - 自定义(
Custom):自定义策略,例如根据用户问题筛选历史消息
LangChain 提供了 SummarizationMiddleware 中间件进行摘要总结。主要作用是当对话历史接近模型的上下文窗口限制时,自动将旧的消息内容总结成摘要,从而释放空间,保留最近的完整对话。
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver() # 初始化checkpointer
middleware = SummarizationMiddleware( # 初始化中间件
model="openai:qwen-plus-2025-07-28",
trigger=("messages",3), # 触发时机,消息数量超过3条(包括AI回复),进行总结
keep=("messages",1), # 保留的会话数量
)
model = init_chat_model(
model="qwen-plus-2025-07-28",
model_provider="openai",
temperature=0.7,
max_tokens=1024
)
agent = create_agent(
model=model,
checkpointer=checkpointer,
middleware=[middleware]. #
)
config = {"configurable":{"thread_id":"thread_2"}}
agent.invoke({"messages":[HumanMessage("你好,我是Mint")]},config)
agent.invoke({"messages":[HumanMessage("我喜欢Anime")]},config)
agent.invoke({"messages":[HumanMessage("我有一只叫Happy的Pet")]},config)
final_response = agent.invoke({"messages":HumanMessage("你还记得我叫什么吗?")},config)
for message in final_response["messages"]:
print(message.pretty_print())
'''
================================ Human Message =================================
Here is a summary of the conversation to date:
## SESSION INTENT
The user, Mint, is engaging in a casual conversation about their interest in Anime and has introduced their pet named Happy. The primary goal is to explore Mint’s connection between their pet’s name and the character Happy from *Fairy Tail*, identify their favorite Anime titles or genres, and build rapport for potential future tasks such as personalized recommendations or themed discussions.
## SUMMARY
- Mint owns a pet named Happy, which prompted the assistant to inquire about a possible connection to the blue cat character Happy from *Fairy Tail*.
- The assistant asked clarifying questions to determine:
- The type of pet Happy is (e.g., cat, dog, other).
- Whether the name was inspired by *Fairy Tail*.
- Mint’s familiarity with or feelings toward *Fairy Tail*.
- Other favorite Anime titles or genres Mint might enjoy.
- Strategy remains focused on using associative, friendly questioning to uncover deeper Anime preferences while maintaining engaging, light-hearted interaction.
- No explicit confirmation yet from Mint regarding *Fairy Tail* affinity or specific Anime tastes.
'''
9. LangSmith联调测试
LangSmith提供了对Agent的GUI管理界面,而且还支持一键云部署功能。通常在测试阶段,建议大家在Agent中引入Simth,方便做测试和调试。
基于LangChain开发的智能体,如果使用LangSmith部署的话,
不用考虑开发与前端对接的接口,也不用考虑会话记忆的问题。部署到本地后直接可以使用智能体的调试、行为追踪、监控;但是如果要部署到云端需要收取昂贵的费用,所以只建议在测试检测使用LangSmith
配置步骤(可参考飞书文档):
- 注册LangSmith帐号
- 登录 - 进入控制台 - settings - API Keys
- 创建API_KEY
- .env文件中添加配置信息
LANGSMITH_API_KEY= XXX
LANGSMITH_TRACING=true
- 开发agent:将代码集成到根目录下
app/agent/personal_chief.py - LangGraph依赖包安装:uv add “langgraph-cli[inmem]”
- 根目录下添加一个langgraph配置文件
{
"dependencies": ["."],
"graphs": {
"chief_agent": "./app/agents/personal_chief.py:agent"
},
"env": ".env"
}
其中的chief_agent配置格式为:[Agent文件路径]:[Agent变量名]
当前项目agent名字为agent,可自定义
- 部署启动服务:uv run langgraph dev

:::tip
当前只建议在Agent测试阶段使用LangSmith
:::
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)