Langchain+LangGraph
第1章. AI通识与基础
1.1 人工智能的发展
AI,人工智能(Artificial Intelligence),是一门致力于使机器能够模拟人类思维、学习与解决问题的技术。
1.2 智能产生的要素
影响大模型智能的核心要素有三点:
-
模型算法
-
海量数据
-
超级算力
1.2.1 模型算法
首先是模型算法,现在的AI都是采用神经网络架构,你可以把它看做是AI的大脑,是决定AI是否”聪明”的基础。
人类的大脑是由很多神经元细胞构成,AI神经网络的本质就是在模拟人类大脑神经元:
AI的神经元与人类神经元一样,接收多个不同的输入x,经过加权求和得到初步结果,再通过激活函数处理生成最终的输出结果。但由于早期的激活函数比较简单,只能做一些简单的二分类任务,比如判断性别、判断真假。
1.2.2 海量数据
神经网络算法是AI的大脑,是决定AI是否”聪明”的基础。然而,再聪明的人,如果不学习任何知识,也不会产生智慧。
AI也是一样,要想让AI产生智慧,就必须用海量的数据来训练它。AI可以学习整个互联网的精华:所有的维基百科、无数的新闻文章、海量的书籍、庞大的代码库……这个数据量是以万亿级的词汇来计算的。而这,就给AI的训练提供了庞大的数据基础。
1.2.3 超级算力
最后是超级算力,大模型训练的数据规模庞大,神经网络架构复杂,因此训练时的计算量都是天文数字。需要成千上万的顶级GPU一起,不间断的工作数周,甚至数月才行,这背后是巨大的电力消耗和硬件成本。
1.3 大模型原理
通过前面的分析,我们知道AI产生智能的三要素分别是:算法、数据、算力。本质来说,AI的智能还是基于各种数学计算产生的。
1.3.1模型的训练
AI的神经网络模型就是在模仿人类的神经元:
你给它输入一些参数,最终它经过计算返回一个结果。因此从某种意义上,你可以把模型看做是一个函数。
模型的训练更像是在猜答案:
-
先给模型参数设定为随机值
-
然后输入一个参数,再把模型计算的结果与预期的正确结果做对比
-
如果不对就调整参数,直到正确为止
这里的输入参数和预期结果就是所谓的训练数据(平面上的“点”)。不断的给模型提供新的训练数据,根据计算结果不断调整模型的参数,直到模型的计算能够与大多数的训练数据吻合,那么模型的训练就完成了。
大语言模型的训练就是拿海量的人类语言文字作为训练数据,不断调整模型参数,使其与人类的语言文字系统拟合。
1.3.2 大语言模型
词向量(Word Embedding)的概念雏形,这为神经网络训练学习自然语言打下了坚实的基础。
-
每个词语都可以经过模型运算转化为一个多维向量(也就是一个浮点数数组,GPT3采用12288维向量)
-
通过训练使模型计算出的多维向量与文字语义产生关联,使多维空间中的不同方向表示不同语义
大语言模型,就是把人类语言转为可以计算的多维向量坐标,然后根据上文向量计算,来推测下文。
更神奇的是,人类一开始训练语言模型只是为了让它理解人类语言,起到翻译作用。但当模型和数据规模足够大时,它不仅能够理解和生成自然语言,还能理解、推理、分析人类生活中的大部分问题,成为了可应用于各个领域的通用人工智能(AGI)!
这种因为数据和模型规模扩大而涌现出各种能力的现象,我们称之为泛化。
而这样的大规模语言模型我们就称为大语言模型(Large Language Model),简称LLM.
1.4 大模型应用
1.4.1 什么是大模型应用
-
传统应用:是由程序员告诉计算机规则(编程),计算机照着规则执行。
-
擅长:规则清楚、流程固定的事情;可以确保100%准确;行为可控、可追溯
-
不擅长:没有明确规则的事情;自然语言的理解;模糊的判断和表达
-
-
大模型:计算机通过大量数据训练,自己学会规律和知识
-
擅长:理解和生成自然语言;模糊问题的合理回答;总结、改写、对话、创作
-
不擅长:准确的计算;固定的流程和规则;稳定可预测的结果
-
而大模型应用则是把两者的能力结合:大模型负责“思考”,传统程序负责“行动”。
1.4.2 常见的大模型
|
大模型 |
对话产品 |
公司 |
地址 |
|---|---|---|---|
|
GPT-3.5、GPT-4o |
ChatGPT |
OpenAI |
|
|
Claude 3.5 |
Claude AI |
Anthropic |
|
|
DeepSeek-R1 |
DeepSeek |
深度求索 |
|
|
文心大模型3.5 |
文心一言 |
百度 |
|
|
星火3.5 |
讯飞星火 |
科大讯飞 |
|
|
Qwen-Max |
通义千问 |
阿里巴巴 |
|
|
Moonshoot |
Kimi |
月之暗面 |
|
|
Yi-Large |
零一万物 |
零一万物 |
1.4.3 与大模型的交互(调用接口)
大模型在部署时通常都会对外暴露基于HTTP协议的API接口,我们可以用任何自己喜欢的方式调用该接口,实现与大模型的交互:

1.5 大模型服务
前面说过:大模型应用开发并不是在浏览器中跟AI聊天。而是通过访问模型对外暴露的API接口,实现与大模型的交互。
因此,企业开发大模型应用,首先需要有一个可访问的大模型,通常有两种选择:
-
使用开放大模型
-
部署私有大模型
使用开放大模型API的优缺点如下:
-
优点:
-
没有部署和维护成本,按调用收费
-
-
缺点:
-
依赖平台方,稳定性差
-
长期使用成本较高
-
数据存储在第三方,有隐私和安全问题
-
部署私有模型:
-
优点:
-
数据完全自主掌控,安全性高
-
不依赖外部环境
-
虽然短期投入大,但长期来看成本会更低
-
-
缺点:
-
初期部署成本高
-
维护困难
-
1.6 大模型API
要学习大模型应用开发,就必须掌握模型的API接口规范。
目前大多数大模型都遵循OpenAI的接口规范,是基于Http协议的接口。因此请求路径、参数、返回值信息都是类似的,可能会有一些小的差别。具体需要查看大模型的官方API文档。
1.6.1 大模型接口规范
-
接口说明
-
请求方式:通常是POST,因为要传递JSON风格的参数
-
请求URL:与平台有关
-
DeepSeek官方平台:https://api.deepseek.com/chat/completions
-
阿里云百炼平台:https://dashscope.aliyuncs.com/compatible-mode/v1
-
本地ollama部署的模型:http://localhost:11434
-
-
请求头:开放平台都需要提供API_KEY来校验权限,本地ollama则不需要
-
Content-Type: application/json,请求参数的格式,必须是application/json,稍后解释
-
Authorization: Bearer <DeepSeek API Key>,上一节创建的API_KEY
-
-
请求参数:JSON格式:
{
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
],
"stream": false
}
-
model:模型名称,DeepSeek支持deepseek-reasoner和deepseek-chat两者模型 -
messages:发送给大模型的消息,[]是数组的意思,里面可以有多条消息。消息结构:-
content:是消息的内容 -
role:消息的角色,有system、user、assisant三种角色-
system:是给大模型设定一个角色,比如你让她扮演你的奶奶,让她哄你睡觉 -
user:就是用户提问的问题 -
assisant:是大模型的回答
-
-
-
stream:true,代表响应结果流式返回;false,代表响应结果一次性返回,但需要等待
注意,这里请求参数中的messages是一个消息数组,而且其中的消息要包含两个属性:
其中System和User消息的内容,也被称为提示词(Prompt),也就是用户发送给大模型的指令。
-
role:消息对应的角色
-
content:消息内容
-
System提示词,是系统指令,给大模型设定一个角色,比如你让她扮演你的奶奶,让她哄你睡觉
-
User提示词,是用户指令,也就是用户向大模型的提问或命令
1.6.2 提示词角色
|
角色 |
描述 |
示例 |
|---|---|---|
|
system |
优先于user指令之前的指令,也就是给大模型设定角色和任务背景的系统指令 |
你是一个乐于助人的编程助手,你以小团团的风格来回答用户的问题。 |
|
user |
终端用户输入的指令(类似于你在ChatGPT聊天框输入的内容) |
写一首关于Java编程的诗 |
|
assistant |
由大模型生成的消息,可能是上一轮对话生成的结果 |
注意,用户可能与模型产生多轮对话,每轮对话模型都会生成不同结果。 |
1.6.3 会话记忆问题
大模型的API接口是"无状态"的,服务端不会记录用户请求的上下文。因此我们调用API接口与大模型对话时,每一次对话信息都不会保留,多次对话之间都是独立的,没有关联的。
要想让大模型有记忆,必须在每次请求时,将之前所有对话的历史拼接好,传递给对话API接口。
第2章. LangChain入门
2.1 LangChain核心组件
2.1.1架构体系
包含一系列开源的智能体(Agent)开发框架,而且兼容Python和TypeScript两种语言:
-
LangChain:用于快速构建智能体,可兼容任何模型提供商。
-
LangGraph:从底层一步步控制智能体的构建,包括记忆(Memory)、人机协同(HITL)等
-
Deep Agents:用于构建复杂的、处理多步骤的任务的智能体
-
LangSmith:用于测试、观察、评估、部署智能体
2.1.2 什么是Agent
在人工智能领域,Agent(通常翻译为智能体或代理)是指一种能够感知环境、进行推理、自主决策并采取行动以实现特定目标的智能系统。
|
特性 |
传统聊天机器人/LLM |
AI Agent |
|---|---|---|
|
交互模式 |
被动响应,问一句答一句 |
主动规划,以目标为导向 |
|
执行力 |
停留在文本生成层面 |
能操作软件、发送邮件、分析数据 |
|
自主性 |
需要人类给出详细步骤 |
只需给定最终目标,自主寻找路径 |
总结如下:
-
LLM = 聪明的大脑
-
Agent = 聪明的大脑 + 手脚
2.1.3 快速入门
-
准备工作
首先,要使用LangChain必须先安装依赖,命令如下:
uv add langchain
LangChain支持各种不同的模型,而且提供了对应的兼容SDK,不过也都需要安装对应依赖,你可以按需添加:
# 集成 DeepSeek uv add langchain-deepseek # 集成 OpenAI uv add langchain-openai # 集成 Anthropic uv add langchain-anthropic
代码示例
接下来就可以开发Agent了,基本步骤如下:
-
加载环境变量
-
定义工具
-
定义Agent
-
调用Agent
Langchain提供了create_agent方法用来快速创建Agent,我们只需要提供好Agent所需的模型(Models)、工具(Tools)即可。
示例代码如下:
# 1.加载环境变量 from dotenv import load_dotenv load_dotenv() # 2.定义工具,基础版,通过注释描述工具 @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" # 3.定义Agent agent = create_agent( "deepseek-chat", # 模型名称(必须是LangChain支持的模型) tools=[getWeather] # 工具集 ) # 4.调用模型 print("🚀 正在调用大模型...") response = agent.invoke({ "messages": [ {"role": "user", "content": "杭州今天天气如何?"} ] }) # 5.打印结果 print(response)
原本大模型不具备查询天气的能力,所以无法回答天气问题。但是,当我们提供了一个查询添加的Tool以后,它就能自动查询天气来回答问题,是不是很神奇。
那么,Agent是如何做到的呢?
传统的LLM应用都是一问一答的形式,模型只能根据自己的训练数据来回答,流程非常简单:
而智能体则可以调用工具与外界交互,获取实时信息,工作流程则要复杂很多,是这样的:
流程如下:
-
用户提问(Input):杭州今天天气如何?
-
模型分析(Reasoning):用户询问杭州天气,我不知道,需要调用查询天气的工具
get_weather -
调用工具(Action):调用工具,get_weather,传入城市"杭州"
-
分析结果(Observation):工具返回结果,模型分析结果,判断是否足以回答用户问题
-
是:整理生成响应结果
-
否:重复前面步骤
-
-
生成结果(Output):根据工具的结果生成响应给用户
其实,在大模型提供的API接口中,有一个tools参数,描述了工具的详细信息:
所以,LangChain会帮助我们把tool的信息封装为此tool参数,与message一起发送给大模型,大模型就了解tool的详细信息,根据用户需求判断是否需要调用tool,需要调用哪个tool.
那么问题来了,当大模型决定调用某个tool时,该如何调用呢?毕竟,tool是我们定义的,模型是没有调用能力的。
模型确实不能直接调用tool,只能返回字符串。但是它可以把要调用的tool信息、参数信息都以Json格式返回:
这样一来,LangChain就会帮我们解析响应结果中的Function信息,也就是tool信息,就知道了要调用哪个函数,以及参数是什么了。LangChain就会执行该函数,再把得到的结果再次发送给大模型。
具体的工作流程如图:
OK,弄明白了Agent的原理,我们不难发现,Agent中最重要的两个部分,就是:
-
Model:负责推理分析、思考,相当于Agent的大脑
-
Tools:负责执行任务,相当于Agent与外界交互的手脚
当然,Agent中肯定不止这两个部分,接下来,我们就逐一解析Agent创建的各个细节。
2.2 模型(Models)
这里说的模型,完整叫法是大语言模型(LLM)。它能够理解人类语言,使用人类语言生成内容、翻译、提取摘要、回答问题等。
可以说LLM就是Agent的大脑,是Agent的推理引擎。它驱动Agent做出每个决定:何时调用工具、调用哪个工具、如何解释结果,以及何时提供最终答案。
2.2.1 初始化模型
langchain提供了两种常见方法用来初始化模型:
-
使用
init_chat_model函数,由langchain自动创建模型对象 -
使用不同模型对应的Model类,手动创建模型对象
-
init_chat_model
在LangChain中开始使用独立模型的最简单方法是使用init_chat_model函数。
调用init_chat_model函数时,你需要从langchain支持的模型提供者(Model Provider)中选择一个模型,而langchain会自动初始化这个模型,非常方便。
例如,我们要使用Deepseek这个模型。
-
首先,我们需要安装模型依赖:
uv add langchain-deepseek -
然后,我们要确保在项目的.env环境中配置好api_key:
DEEPSEEK_API_KEY=sk-f362e1ea622c40878f11a9ca95f58847 -
最后,就可以直接使用init_chat_model初始化模型了:
# 导入Langchain的初始化模型的函数 from langchain.chat_models import init_chat_model # 加载环境变量 from dotenv import load_dotenv load_dotenv() # 调用init_chat_model函数初始化模型,参数model用来指定模型名称,Langchain会根据模型名字自动设定base_url,并从环境变量中获取api_key model = init_chat_model(model="deepseek-chat") -
测试,我们可以通过打印model的类型,查看生成的结果:
print(type(model)) # <class 'langchain_deepseek.chat_models.ChatDeepSeek'>
可见,采用init_chat_model自动初始化模型时,模型的类型由LangChain通过模型名称自动推断。
如果要切换其它模型,我们只需要安装其它模型依赖,然后配置API_KEY,改变模型名称即可,其它代码不用动。
2.自定义模型及参数
init_chat_model默认会根据模型名称自动确定模型的提供者、其base_url,并从env读取api_key,但前提是必须是langchain支持的模型提供者(支持模型参考链接),例如:
-
Openai
-
Deepseek
-
Google
-
Anthropic
-
...
对于其它不支持的模型,我们必须自定义模型参数来访问。
例如,我们要访问阿里云百炼的qwen-max,它就是不被langchain支持的模型,我们必须自定义模型参数来访问。
-
我们需要在环境变量中定义api_key和base_url
-
然后在
init_chat_model中指定model、model_provider、base_url和api_key
具体步骤如下:
-
首先,在.env中配置好
api_key和base_url:DASHSCOPE_API_KEY=sk-915a82ea621f412ed9c8c8c7b22f8792 DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 -
然后,手动读取环境变量中的
api_key和base_url:# 非支持模型无法自动加载环境遍历,我们需要自己加载环境变量中的base_url和api_key import os
base_url = os.getenv("DASHSCOPE_BASE_URL")
api_key = os.getenv("DASHSCOPE_API_KEY")
-
最后,调用init_chat_model,初始化模型:
# 初始化模型 model = init_chat_model( model="qwen-max", # 模型名称,这里可以自定义,我们用的是阿里的qwen-max model_provider="openai", # 如果是Langchain不支持的模型,需要指定模型提供者(虽然我们用的是阿里,但是阿里兼容openai,所以这里用openai,就是默认采用openai的API规范) base_url=base_url, api_key=api_key ) -
测试,查看生成的模型类型:
print(type(model)) # <class 'langchain_openai.chat_models.base.ChatOpenAI'>
可见,通过参数自定义模型时,模型的类型由model_provider参数类决定。
除了修改模型提供者以外,init_chat_model方法允许我们调整模型参数,例如:
-
temperature: 控制生成文本的随机性,值越小越确定,值越大越随机
-
max_tokens: 控制生成文本的最大长度
-
top_p: 控制生成文本的多样性,值越小越多样,值越大越确定
-
timeout: 控制生成文本的超时时间
-
max_retries: 控制生成文本的最大重试次数
-
...
3.使用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_models.tongyi import ChatTongyi# 使用Model类初始化模型 model = ChatTongyi( model="qwen-plus" # 其它模型参数... ) -
测试,查看生成的模型类型:
print(type(model)) # <class 'langchain_community.chat_models.tongyi.ChatTongyi'>
2.2.2 访问模型
LangChain提供了两个不同的方法来访问模型:
-
invoke:阻塞式访问
-
stream:流式访问
-
invoke
invoke方法是阻塞式调用,需要等待模型生成全部结果才会返回,等待时间较长。
# 调用invoke方法
response = model.invoke("月亮的首都是哪里?")
# 查看响应结果
print(response)
2. stream
阻塞式调用需要等待较长时间才能看到AI返回的结果,而流式调用则可以实时看到AI返回的一个个词。
# 通过.stream方法实现流式访问
stream = model.stream("月亮的首都是哪里?")
# stream调用返回的结果是一个generator,方便我们循环获取结果
print(type(stream)) # 遍历stream结果,实时打印AI的回复
for chunk in stream:
print(chunk.content, end="", flush=True)
2.2.3 在Agent中使用模型
Langchain提供了一个create_agent方法用来快速创建智能体。当我们创建Agent的时候,可以直接使用创建好的Model,也可以指定模型名,让Langchain自动初始化模型。
-
创建智能体
-
创建智能体,指定模型名,由Langchain初始化模型
from langchain.agents import create_agent # 1.指定Model名称,由LangChain自动初始化模型 agent = create_agent(model="deepseek-chat")
2. 创建智能体,并使用创建好的model
from langchain.agents import create_agent from langchain_community.chat_models.tongyi import ChatTongyi # 1.使用Model类初始化模型 model = ChatTongyi( model="qwen-plus" # 其它模型参数... ) # 2.使用初始化好的model创建智能体 agent = create_agent(model=model)
2.调用智能体
-
阻塞式调用,使用invoke方法:

-
流式调用,只需要把调用方式改为
stream:

要注意,Agent的stream模式同样返回一个generator,但是其结构由stream_mode参数决定:
-
messages: 返回LLM生成的每一个片段,是一个包含token和metadata的元组(Tuple)
-
updates: 返回Agent运行过程中的每一次事件,例如与LLM的对话、工具的调用等
-
custom: 返回通过stream writer记录的每一次自定义的输出
如果是为了流式输出AI返回的结果,使用messages模式即可。
2.3 消息(Messages)
在调用模型时,发送给LLM的消息、LLM返回的消息都包含以下几部分内容:
-
role:消息所属角色,可以是system、user、assistant
-
content:消息的内容
-
metadata(可选):消息的元数据,例如:消息的ID、消耗的token等
-
消息类型
在LangChain中,我们并不需要自己创建BaseMessage对象,LangChain已经把常见消息根据角色(Role)创建了对应的BaseMessage的子类:
-
SystemMessage:role是system,代表系统消息,用于设定模型角色和交互背景
-
HumanMessage:role是user,代表用户输入的消息
-
AIMessage:role是assistant,代表LLM生成的响应,包含:文本、工具调用、元数据
-
ToolMessage:role是tool,代表工具调用时产生的结果
所以,我们可以这样传递消息列表

Agent的返回结果中包含完整的消息列表(Messages)
我们可以通过遍历Messages数组,更友好的打印结果:
for message in response['messages']:
message.pretty_print()
结果:

2. 多模态消息
之前我们都是向模型发送文本消息,但是 LangChain 也支持向模型发送多模态消息,比如图片、音频、视频、文本等。但前提是必须是多模态模型才支持。
一些支持多模态的模型有:
-
qwen3.5-plus
-
gpt-5-nano
-
...
我们以qwen3.5-plus为例,演示向模型发送图片消息
首先,我们演示如何发送一个在线图片给模型,也就是指定模型的url地址。
第1节. LangChain核心组件
-
认识LangChain
LangChain 由 Harrison Chase 创建于2022年10月,是用于开发智能体工程(Agent Engineering)的平台。
官网地址:
https://www.langchain.com/
官网文档:
https://docs.langchain.com/
-
架构体系
LangChain并不仅仅是一个框架,而是一整个智能体开发平台,包含很多不同的组件。
其中,包含一系列开源的智能体(Agent)开发框架,而且兼容Python和TypeScript两种语言:
-
LangChain:用于快速构建智能体,可兼容任何模型提供商。
-
LangGraph:从底层一步步控制智能体的构建,包括记忆(Memory)、人机协同(HITL)等
-
Deep Agents:用于构建复杂的、处理多步骤的任务的智能体
另外,LangChain还包含一套帮助人工智能团队利用实时生产数据进行持续测试和改进的平台,叫做LangSmith:
总结:
LangChain是智能体开发平台,包含一套各种帮助开发、测试、评估智能体的框架。核心包括:
-
LangChain:用于快速构建智能体,可兼容任何模型提供商。
-
LangGraph:从底层一步步控制智能体的构建,包括记忆(Memory)、人机协同(HITL)等
-
Deep Agents:用于构建复杂的、处理多步骤的任务的智能体
-
LangSmith:用于测试、观察、评估、部署智能体
可以看到,LangChain平台的所有框架都是围绕着构建智能体(Agent)这一目标的,那么问题来了:
什么是智能体(Agent)呢?
-
什么是Agent
什么是Agent,这其实没有一个标准的答案,每个人都有自己的理解。
对于这个问题,LangChain创始人Harrison Chase有一个偏向技术性的答案:
An AI agent is a system that uses an LLM to decide the control flow of an application.
Agent是一种使用大语言模型(LLM)来决定应用程序控制流的系统。
在人工智能领域,Agent(通常翻译为智能体或代理)是指一种能够感知环境、进行推理、自主决策并采取行动以实现特定目标的智能系统。
|
特性 |
传统聊天机器人/LLM |
AI Agent |
|---|---|---|
|
交互模式 |
被动响应,问一句答一句 |
主动规划,以目标为导向 |
|
执行力 |
停留在文本生成层面 |
能操作软件、发送邮件、分析数据 |
|
自主性 |
需要人类给出详细步骤 |
只需给定最终目标,自主寻找路径 |
如果说大模型(LLM)是“大脑”,那么 Agent 就是“拥有手脚和思维逻辑的独立个体”。它不再只是被动地回答问题,而是能主动拆解任务并调用各种工具来完成工作。
例如:要开发一个《AI旅游助手》的应用。
如果是传统LLM应用,程序流程是这样的:
用户提出需求,例如:帮我计划一个5天的北京之旅,预算8000元,我喜欢历史。
调用LLM,分析用户需求,直接由LLM生成一个简单旅游计划
这个计划基于它训练数据中的通用知识,可能没有考虑当前的天气、景点是否关闭、门票是否可预订等实时信息。
如果是Agent应用,Agent可以自主规划程序流程:
用户提出需求,例如:帮我计划一个5天的北京之旅,预算8000元,我喜欢历史。
Agent分析用户需求,分步执行:
规划: 将大目标分解为:查询机票酒店价格 -> 查询天气和景点信息 -> 设计每日行程 -> 计算总预算。
调用工具:
调用机票/酒店API,查询用户指定日期范围内的价格和可选酒店。
调用天气预报API,查询未来5天北京的天气,建议携带的衣物。
调用搜索引擎/景点API,查询故宫、国博等热门景点的最新开放时间、预约政策和当前展览。
感知与反馈: 综合感知所有查询到的实时信息,生成一个动态的、可执行的计划。例如:“根据预算和您对历史的兴趣,我推荐入住胡同里的XX酒店。第一天去故宫,但请注意下周一故宫闭馆,所以调整到第二天……总花费预计7500元,还在预算内。需要我现在帮您预订酒店和机票吗?”
Agent通过主动规划任务流程,主动使用工具,整合了实时信息,并进行了动态调整,最终产出的是一个真正可落地的方案。
总结如下:
-
LLM = 聪明的大脑
-
Agent = 聪明的大脑 + 手脚
当然,Agent的模式也是在不断演进的:
-
阶段一:ReAct + Tool Calling
-
阶段二:Reflection + Long Memory
-
阶段三:Multi Agent System,MAS
接下来,我们会从最简单的Agent开始学习,逐渐升级到更复杂的Agent结构。
-
快速入门
下面,我们通过一个快速入门,了解Agent的定义和工作流程。
-
准备工作
首先,要使用LangChain必须先安装依赖,命令如下:
uv add langchain
LangChain支持各种不同的模型,而且提供了对应的兼容SDK,不过也都需要安装对应依赖,你可以按需添加:
# 集成 DeepSeek uv add langchain-deepseek # 集成 OpenAI uv add langchain-openai # 集成 Anthropic uv add langchain-anthropic
-
代码示例
接下来就可以开发Agent了,基本步骤如下:
-
加载环境变量
-
定义工具
-
定义Agent
-
调用Agent
Langchain提供了create_agent方法用来快速创建Agent,我们只需要提供好Agent所需的模型(Models)、工具(Tools)即可。
示例代码如下:
# 1.加载环境变量 from dotenv import load_dotenv load_dotenv() # 2.定义工具,基础版,通过注释描述工具 @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" # 3.定义Agent agent = create_agent( "deepseek-chat", # 模型名称(必须是LangChain支持的模型) tools=[getWeather] # 工具集 ) # 4.调用模型 print("🚀 正在调用大模型...") response = agent.invoke({ "messages": [ {"role": "user", "content": "杭州今天天气如何?"} ] }) # 5.打印结果 print(response)
运行结果如下:
🚀 正在调用大模型... {'messages': [HumanMessage(content='杭州今天天气如何?', additional_kwargs={}, response_metadata={}, id='216c9cd1-8ebc-4365-a192-6b1a30ae788c'), AIMessage(content='我来帮您查询杭州今天的天气情况。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 51, 'prompt_tokens': 313, 'total_tokens': 364, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 256}, 'prompt_cache_hit_tokens': 256, 'prompt_cache_miss_tokens': 57}, 'model_provider': 'deepseek', 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'id': 'bbeda11e-7653-4c3d-9cc5-9a58491f63f0', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019c92f4-8395-7852-8e36-d4645f86d443-0', tool_calls=[{'name': 'getWeather', 'args': {'location': '杭州'}, 'id': 'call_00_H7Yklbf4osnSeFOj3k4TP33N', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 313, 'output_tokens': 51, 'total_tokens': 364, 'input_token_details': {'cache_read': 256}, 'output_token_details': {}}), ToolMessage(content='Current weather in 杭州 is sunny', name='getWeather', id='911eda0e-a5a8-4375-909d-b8707b3a08a9', tool_call_id='call_00_H7Yklbf4osnSeFOj3k4TP33N'), AIMessage(content='根据查询结果,杭州今天的天气是**晴朗**的。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 388, 'total_tokens': 401, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 320}, 'prompt_cache_hit_tokens': 320, 'prompt_cache_miss_tokens': 68}, 'model_provider': 'deepseek', 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'id': '692c1420-4a06-4080-adf7-54250207e86a', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019c92f4-8d74-7770-89fd-da1e9d67efca-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 388, 'output_tokens': 13, 'total_tokens': 401, 'input_token_details': {'cache_read': 320}, 'output_token_details': {}})]}
原本大模型不具备查询天气的能力,所以无法回答天气问题。但是,当我们提供了一个查询添加的Tool以后,它就能自动查询天气来回答问题,是不是很神奇。
那么,Agent是如何做到的呢?
传统的LLM应用都是一问一答的形式,模型只能根据自己的训练数据来回答,流程非常简单:
暂时无法在飞书文档外展示此内容
而智能体则可以调用工具与外界交互,获取实时信息,工作流程则要复杂很多,是这样的:
暂时无法在飞书文档外展示此内容
流程如下:
-
用户提问(Input):杭州今天天气如何?
-
模型分析(Reasoning):用户询问杭州天气,我不知道,需要调用查询天气的工具
get_weather -
调用工具(Action):调用工具,get_weather,传入城市"杭州"
-
分析结果(Observation):工具返回结果,模型分析结果,判断是否足以回答用户问题
-
是:整理生成响应结果
-
否:重复前面步骤
-
-
生成结果(Output):根据工具的结果生成响应给用户
那么,模型是如何知道工具的信息的呢?
其实,在大模型提供的API接口中,有一个tools参数,描述了工具的详细信息:
所以,LangChain会帮助我们把tool的信息封装为此tool参数,与message一起发送给大模型,大模型就了解tool的详细信息,根据用户需求判断是否需要调用tool,需要调用哪个tool.
那么问题来了,当大模型决定调用某个tool时,该如何调用呢?毕竟,tool是我们定义的,模型是没有调用能力的。
模型确实不能直接调用tool,只能返回字符串。但是它可以把要调用的tool信息、参数信息都以Json格式返回:
这样一来,LangChain就会帮我们解析响应结果中的Function信息,也就是tool信息,就知道了要调用哪个函数,以及参数是什么了。LangChain就会执行该函数,再把得到的结果再次发送给大模型。
具体的工作流程如图:
暂时无法在飞书文档外展示此内容
OK,弄明白了Agent的原理,我们不难发现,Agent中最重要的两个部分,就是:
-
Model:负责推理分析、思考,相当于Agent的大脑
-
Tools:负责执行任务,相当于Agent与外界交互的手脚
当然,Agent中肯定不止这两个部分,接下来,我们就逐一解析Agent创建的各个细节。
2.2 模型(Models)
这里说的模型,完整叫法是大语言模型(LLM)。它能够理解人类语言,使用人类语言生成内容、翻译、提取摘要、回答问题等。
不仅如此,现在大多数的模型还有一些特别能力:
-
Tool calling - 调用外部工具(例如查询数据库或调用 API),并在其回复中使用这些工具返回的结果。
-
Structured output - 将模型的响应结果约束为遵循已定义的格式,例如:json
-
Multimodality - 可以处理和返回文本以外的数据,如图像、音频和视频。
-
Reasoning - 模型可以执行多步推理来得出结论。
可以说LLM就是Agent的大脑,是Agent的推理引擎。它驱动Agent做出每个决定:何时调用工具、调用哪个工具、如何解释结果,以及何时提供最终答案。
LangChain支持现在市面上大部分的大语言模型(LLM),并且提供了统一的模型调用接口。使您可以轻松访问许多不同的模型提供者,并且在模型之间进行试验和切换也变得很容易。
有关模型提供者(Model Providers)的信息和功能,请参阅langchain官网的 chat model page.
-
初始化模型
langchain提供了两种常见方法用来初始化模型:
-
使用
init_chat_model函数,由langchain自动创建模型对象 -
使用不同模型对应的Model类,手动创建模型对象
-
init_chat_model
在LangChain中开始使用独立模型的最简单方法是使用init_chat_model函数。
调用init_chat_model函数时,你需要从langchain支持的模型提供者(Model Provider)中选择一个模型,而langchain会自动初始化这个模型,非常方便。
例如,我们要使用Deepseek这个模型。
-
首先,我们需要安装模型依赖:
uv add langchain-deepseek -
然后,我们要确保在项目的.env环境中配置好api_key:

DEEPSEEK_API_KEY=sk-f362e1ea622c40878f11a9ca95f58847 -
最后,就可以直接使用init_chat_model初始化模型了:
# 导入Langchain的初始化模型的函数 from langchain.chat_models import init_chat_model # 加载环境变量 from dotenv import load_dotenv load_dotenv() # 调用init_chat_model函数初始化模型,参数model用来指定模型名称,Langchain会根据模型名字自动设定base_url,并从环境变量中获取api_key model = init_chat_model(model="deepseek-chat") -
测试,我们可以通过打印model的类型,查看生成的结果:
print(type(model)) # <class 'langchain_deepseek.chat_models.ChatDeepSeek'>
可见,采用init_chat_model自动初始化模型时,模型的类型由LangChain通过模型名称自动推断。
如果要切换其它模型,我们只需要安装其它模型依赖,然后配置API_KEY,改变模型名称即可,其它代码不用动。
-
自定义模型及参数
init_chat_model默认会根据模型名称自动确定模型的提供者、其base_url,并从env读取api_key,但前提是必须是langchain支持的模型提供者(支持模型参考链接),例如:
-
Openai
-
Deepseek
-
Google
-
Anthropic
-
...
对于其它不支持的模型,我们必须自定义模型参数来访问。
例如,我们要访问阿里云百炼的qwen-max,它就是不被langchain支持的模型,我们必须自定义模型参数来访问。
-
我们需要在环境变量中定义api_key和base_url
-
然后在
init_chat_model中指定model、model_provider、base_url和api_key
具体步骤如下:
-
首先,在.env中配置好
api_key和base_url:
DASHSCOPE_API_KEY=sk-915a82ea621f412ed9c8c8c7b22f8792 DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 -
然后,手动读取环境变量中的
api_key和base_url:# 非支持模型无法自动加载环境遍历,我们需要自己加载环境变量中的base_url和api_key import os base_url = os.getenv("DASHSCOPE_BASE_URL") api_key = os.getenv("DASHSCOPE_API_KEY") -
最后,调用init_chat_model,初始化模型:
# 初始化模型 model = init_chat_model( model="qwen-max", # 模型名称,这里可以自定义,我们用的是阿里的qwen-max model_provider="openai", # 如果是Langchain不支持的模型,需要指定模型提供者(虽然我们用的是阿里,但是阿里兼容openai,所以这里用openai,就是默认采用openai的API规范) base_url=base_url, api_key=api_key ) -
测试,查看生成的模型类型:
print(type(model)) # <class 'langchain_openai.chat_models.base.ChatOpenAI'>
可见,通过参数自定义模型时,模型的类型由model_provider参数类决定。
除了修改模型提供者以外,init_chat_model方法允许我们调整模型参数,例如:
-
temperature: 控制生成文本的随机性,值越小越确定,值越大越随机
-
max_tokens: 控制生成文本的最大长度
-
top_p: 控制生成文本的多样性,值越小越多样,值越大越确定
-
timeout: 控制生成文本的超时时间
-
max_retries: 控制生成文本的最大重试次数
-
...
示例:
# 调用init_chat_model函数初始化模型,并设定模型参数 model = init_chat_model( model="qwen-max", model_provider="openai", base_url=base_url, api_key=api_key, temperature=1.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_models.tongyi import ChatTongyi # 使用Model类初始化模型 model = ChatTongyi( model="qwen-plus" # 其它模型参数... ) -
测试,查看生成的模型类型:
print(type(model)) # <class 'langchain_community.chat_models.tongyi.ChatTongyi'>
-
访问模型
LangChain提供了两个不同的方法来访问模型:
-
invoke:阻塞式访问
-
stream:流式访问
-
invoke
invoke方法是阻塞式调用,需要等待模型生成全部结果才会返回,等待时间较长。
# 调用invoke方法 response = model.invoke("月亮的首都是哪里?") # 查看响应结果 print(response)
-
stream
阻塞式调用需要等待较长时间才能看到AI返回的结果,而流式调用则可以实时看到AI返回的一个个词。
示例:
# 通过.stream方法实现流式访问 stream = model.stream("月亮的首都是哪里?") # stream调用返回的结果是一个generator,方便我们循环获取结果 print(type(stream)) # 遍历stream结果,实时打印AI的回复 for chunk in stream: print(chunk.content, end="", flush=True)
-
在Agent中使用模型
Langchain提供了一个create_agent方法用来快速创建智能体。当我们创建Agent的时候,可以直接使用创建好的Model,也可以指定模型名,让Langchain自动初始化模型。
-
创建智能体
-
创建智能体,指定模型名,由Langchain初始化模型
from langchain.agents import create_agent # 1.指定Model名称,由LangChain自动初始化模型 agent = create_agent(model="deepseek-chat")
-
创建智能体,并使用创建好的model
from langchain.agents import create_agent from langchain_community.chat_models.tongyi import ChatTongyi # 1.使用Model类初始化模型 model = ChatTongyi( model="qwen-plus" # 其它模型参数... ) # 2.使用初始化好的model创建智能体 agent = create_agent(model=model)
-
调用智能体
智能体也分为阻塞调用和流式调用两种。
-
阻塞式调用,使用invoke方法:
# 2.调用模型,需要传入一个消息列表 response = agent.invoke({ "messages": [{"role": "user", "content": "月亮的首都是哪里?"}] }) print(response) -
流式调用,只需要把调用方式改为
stream:for token, metadata in agent.stream( {"messages": [{"role": "user", "content": "月亮的首都是哪里?"}]}, stream_mode="messages" ): if token.content: # Check if there's actual content print(token.content, end="", flush=True) # Print token
要注意,Agent的stream模式同样返回一个generator,但是其结构由stream_mode参数决定:
-
messages: 返回LLM生成的每一个片段,是一个包含token和metadata的元组(Tuple)
-
updates: 返回Agent运行过程中的每一次事件,例如与LLM的对话、工具的调用等
-
custom: 返回通过stream writer记录的每一次自定义的输出
如果是为了流式输出AI返回的结果,使用messages模式即可。
-
总结
目前为止,我们学习了:
-
如何使用init_chat_model初始化模型
-
如何使用Model类初始化模型
-
如何调用模型
-
如何创建Agent,并在Agent中使用模型
-
如何调用Agent
2.3 消息(Messages)
在调用模型时,发送给LLM的消息、LLM返回的消息都包含以下几部分内容:
-
role:消息所属角色,可以是system、user、assistant
-
content:消息的内容
-
metadata(可选):消息的元数据,例如:消息的ID、消耗的token等
之前我们都是自己用dict模拟消息:
response = agent.invoke({ "messages": [{"role": "user", "content": "月亮的首都是哪里?"}] })
这太麻烦了。在LangChain中发送给LLM的消息、LLM返回的消息都统一被封装为BaseMessage,它是中基本的上下文单元。
-
消息类型
在LangChain中,我们并不需要自己创建BaseMessage对象,LangChain已经把常见消息根据角色(Role)创建了对应的BaseMessage的子类:
-
SystemMessage:role是system,代表系统消息,用于设定模型角色和交互背景
-
HumanMessage:role是user,代表用户输入的消息
-
AIMessage:role是assistant,代表LLM生成的响应,包含:文本、工具调用、元数据
-
ToolMessage:role是tool,代表工具调用时产生的结果
所以,我们可以这样传递消息列表:
from langchain.messages import HumanMessage, AIMessage from langchain.agents import create_agent # 创建Agent agent = create_agent(model="deepseek-chat") # 调用Agent,发送消息 response = agent.invoke({ "messages": [ HumanMessage(content="你好,我是虎哥"), AIMessage(content="你好,虎哥,很高兴认识你。"), HumanMessage(content="我的名字是什么?") ] }) print(response)
注意看,Agent的返回结果中包含完整的消息列表(Messages):
{'messages': [HumanMessage(content='你好,我是虎哥', additional_kwargs={}, response_metadata={}, id='f5703ee9-f567-48d6-8e07-e6ddaf24547e'), AIMessage(content='你好,虎哥,很高兴认识你。', additional_kwargs={}, response_metadata={}, id='5c654447-828c-43b7-9505-a341e0d21b8a', tool_calls=[], invalid_tool_calls=[]), HumanMessage(content='我的名字是什么?', additional_kwargs={}, response_metadata={}, id='a3390334-85b8-4f5f-8528-782a18671ac9'), AIMessage(content='你刚才提到你的名字是“虎哥”。如果这是你希望我称呼你的方式,我会记住的。如果有其他偏好,随时告诉我哦! 😊', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 33, 'prompt_tokens': 26, 'total_tokens': 59, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 26}, 'model_provider': 'deepseek', 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'id': '9ea39267-c54a-4523-82e0-1377435ffde4', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019cad79-8b7a-7861-855b-5a87ba11d38c-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 26, 'output_tokens': 33, 'total_tokens': 59, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}
我们可以通过遍历Messages数组,更友好的打印结果:
for message in response['messages']: message.pretty_print()
结果:
================================ Human Message ================================= 你好,我是虎哥 ================================== Ai Message ================================== 你好,虎哥,很高兴认识你。 ================================ Human Message ================================= 我的名字是什么? ================================== Ai Message ================================== 你刚才提到你的名字是“虎哥”。如果这是你希望我称呼你的方式,我会记住的。如果有其他偏好,随时告诉我哦! 😊
提示:
通过刚才的实现可以发现,拼接message列表可以让AI记住会话历史,产生记忆。不过手动拼接Message太麻烦了,后面我们学习如何实现自动的会话记忆功能。
-
多模态消息
之前我们都是向模型发送文本消息,但是 LangChain 也支持向模型发送多模态消息,比如图片、音频、视频、文本等。但前提是必须是多模态模型才支持。
一些支持多模态的模型有:
-
qwen3.5-plus
-
gpt-5-nano
-
...
我们以qwen3.5-plus为例,演示向模型发送图片消息
-
在线图片
首先,我们演示如何发送一个在线图片给模型,也就是指定模型的url地址。
图片如下:

消息格式如下:

示例代码:

-
本地图片
所谓本地图片,就是用户上传的图片数据或者本地存在的图片,而不是图片的url地址。我们需要将图片数据转换成base64字符串,然后发送给模型。
本地图片的消息格式:

示例:

2.4提示词(Prompts)
发送给大模型的所有消息都可以称为提示词(Prompt),它直接影响模型的输出结果。
其中,SystemMessage尤为重要,我们把SystemMessage称为系统提示词(System Prompt),它可以给模型设定角色和本次聊天的背景,对模型生成的内容有很大的影响。
2.4.1系统提示词
在创建智能体时,我们可以直接设定system prompt,不必在每次发送消息时指定。

2.4.2 提示词工程
通过优化System Prompt从而让模型输出更理想的结果的这一过程,我们称为提示词工程(Prompt Engineering)。
也就是说,提示词优化不是一锤子买卖,而是一个不断优化、测试、再优化的过程。那么,提示词到底该怎么写呢?
从内容来说,提示词通常包含以下几个部分,通常按此顺序排列:
-
身份(Identity):描述AI的职责、沟通风格和总体目标。
-
说明(Instructions):请指导模型如何生成所需的响应。它应该遵循哪些规则?模型应该做什么,以及模型绝对不能做什么?
-
示例(Examples):提供可能的输入示例,以及模型期望的输出。
-
背景信息(Context):向模型提供生成响应所需的任何额外信息,例如RAG的额外知识库数据,或您认为特别相关的任何其他数据。
从格式来说,在编写System Prompt时,您可以使用Markdown格式和XML 标签的组合来帮助模型理解提示和上下文数据的逻辑边界。
-
Markdown 的标题和列表有助于标记提示的不同部分,并向模型传达层级结构。它们还可以提高开发过程中提示的可读性。
-
XML 标签可以帮助明确区分一段内容(例如用作参考的辅助文档、对话示例等)的起始和结束位置。
-
设定角色和详细指令
角色可以帮助模型认清自己的身份,以对应的身份来回答问题。
指令则告诉模型需要遵循哪些规则,应该做什么,不应该做什
system_prompt = """
# 身份 -
你是一个编程助手,你帮助用户编写Python代码。
# 指令
- 定义变量时,使用snake case命名法,而不是camel case命名法。
- 不要返回markdown格式说明,仅仅返回代码即可。
"""
2.Few-Shot examples
有的时候我们希望模型按照固定的风格来回答问题,而这种风格又不太好描述,那我们就可以通过举例的方式让模型学习例子来回答。
用户只需在输入提示(Prompt)中提供几个输入-输出示例,模型就能理解任务模式并生成符合预期的输出
system_prompt = """ # 身份 - 你是一个科幻作家,根据用户的要求创建一个太空之都。 # 示例 user:月球的首都是什么? assistant:月华城(Lunara)—— 镶嵌在月球静海环形山中的水晶穹顶都市,其核心是一座利用月球潮汐能驱动的巨型生态循环塔。 user:火星的首都是什么? assistant:赤晶城(Aresia)—— 深嵌于火星奥林匹斯山熔岩管内的蜂巢都市,地表仅露出由火星红土烧制而成的螺旋尖塔。 """
3.结构化输出
由于传统程序识别结构化的数据会更加方便,所以有时候我们希望LLM也能输出固定结构的内容,方便我们解析。这同样可以通过系统提示词来实现。

在LangChain中,实现结构化输出会更加简单。我们无需自己在提示词中添加描述实现结构化输出,而仅仅是设定好一个数据类型即可。
完整代码:

2.5 工具(Tools)
一个完整的Agent至少要包含两个关键的部分:
-
模型:是Agent的大脑,负责推理、分析,规划任务步骤
-
工具:是Agent的手脚,负责执行任务,与外界交互
-
基本用法
定义一个带有工具的Agent分为两步:
-
定义工具
-
定义Agent,绑定工具
首先,使用tool装饰器定义工具:

接着,定义Agent,绑定工具:

由此可见,所谓的工具,本质就是一个可调用的函数,要想让Agent知道有哪些工具可调用,该如何调用这些工具,就必须把这个函数的详细信息发送给模型。包括:
-
函数名
-
函数的作用
-
函数的参数和返回值信息
所以,定义工具的时候,关键就是把这些信息描述清楚即可。
2.自定义工具
在LangChain中,定义工具的过程被大大简化,与定义普通函数几乎没什么差别,只是在一些细节上需要注意。
首先,定义工具需要在函数上添加@tool装饰器。

智能体在工作时,需要将函数的名称、输入、作用传递给大模型,默认情况下这些信息的来源是:
-
工具名称:函数名
-
工具输入:函数入参
-
工具作用:函数的注释
当然,我们可以通过tool装饰器来覆盖上述信息:
-
通过装饰器定义工具入参约束
如果要覆盖工具的入参信息则会复杂很多,我们要借助于Pydantic或JSON约束。
工具定义好之后,调用方式与普通函数类似:

当我们创建智能体时,可以把定义好的工具传递给智能体,将来模型就能得到工具信息,并根据情况判断是否需要调用工具,需要调用哪个工具了。

3.预定义工具
LangChain中提供了很多预定义好的工具,方便我们使用,可使用的预定义工具列表可参考官网:
例如,模型本身只能根据本身的训练数据回答问题,无法获取实时信息。但如果我们给它提供了web搜索的工具,那么你的Agent就如同具备了实时web搜索的能力,回答会更加准确。
有一个专门用于给Agent提供Web搜索的工具,叫做Tavily
要使用这个工具,步骤如下:
-
注册账号,可看到一个默认的API_KEY:
-
配置环境变量,接下来,我们需要把这个KEY配置到我们的.env文件中:
-
安装依赖,uv add langchain-tavily
-
使用工具,接下来,就可以使用tavily来做web搜索了

5.结合智能体

6. 优化
注意,LangChain提供的TavilySearch工具描述非常复杂,参数也很多。会有额外的网络消耗。如果我们仅仅是需要query参数,建议自定义工具。

2.6 记忆(memory)
模型本身是没有记忆的,它记不住历史的会话内容,参考之前的章节介绍:第1章. AI通识与基础
我们需要通过技术手段,帮助模型记住会话历史,产生记忆。
对于Agent而言,记忆至关重要,因为它能让代理记住之前的交互情况,从反馈中学习,并适应用户的偏好。随着代理处理的任务愈发复杂,涉及的用户交互也越来越多,这种能力对于提高效率和用户满意度而言变得不可或
2.6.1记忆的分类
对于智能体而言,记忆分为了两类:
-
短期记忆(short-term memory)
-
长期记忆(long-term memory)
-
短期记忆:当前任务或会话的上下文(Working Memory 或 Session Memory)
-
长期记忆:跨任务或会话的经验与知识(Persistent Memory)
2.6.2 短期记忆
由于短期记忆通常生命周期是当前会话,所以我们也可以称为会话记忆。Agent的会话记忆通常包含三部分:
-
对话历史
-
查询结果
-
任务状态
LangChain提供了自动化的记忆管理方案:
-
首先,LangChain把会话记忆(也就是Messages列表)记录为AgentState的一部分
-
AgentState通过Checkpointer对象来保存,每一次与AI的交互都会生成一个快照,记录为一个checkpoint,把同一会话的所有checkpoint组合在一起,就是完整的会话历史了。
-
为了区分不同的会话记忆,不同会话需要设定各自的
thread_id,相同会话则使用相同thread_id -
向Agent发起会话时必须指定自己的
thread_id以唤起对应的会话记忆
1.InMemorySaver
具体步骤是这样的:
-
导入CheckPointer的内存版实现:
# langchain提供的checkpointer的默认实现,基于内存存储
from langgraph.checkpoint.memory import InMemorySaver
2.创建智能体,设置checkpointer:

3.发起调用时,指定thread_id

由于两次调用使用了相同的thread_id,被认定为是同一次对话,所以LangChain会在请求模型时携带历史对话的Messages,模型就能根据历史消息来正确回答了
2.持久化Memory(选学)
LangChain也提供了很多持久化存储的checkpointer,例如:
-
SqlLiteSaver :基于sqlite存储
-
PostgresSaver :基于Postgres存储
-
CosmosDBSaver :使用Azure Cosmos DB的实现
我们以SqlLiteSaver 为例来讲解如何自定义Memory存储方案。

2.6.3 记忆管理策略
由于会话记忆要保存会话的历史,并且在调用LLM时携带历史消息列表。而当会话越来越长时,历史消息就可能超过LLM的上下文限制。例如,DeepSeek的上下文不能超过128K.
一旦会话历史超过上下文窗口,就会出现上下文丢失的情况,从而导致丢失记忆。而且即便不丢失,太长的上下文容易让模型出现“注意力分散”问题,模型的响应速度、回答质量会大大降低。
未来解决这一问题,通常有以下几种手段:

1.修剪消息
修剪消息并不是真正的删除消息,在AgentState中的消息列表依然是完整的,只不过发送给LLM之前会进行修剪,只保留一部分消息。
2.删除消息
删除消息与修剪不同:
-
修剪消息:只是从State中选取一部分消息发送给模型
-
删除消息:直接删除State中保存的消息,也就是说消息历史中不再存在
3.总结消息
不管是修剪还是删除,都会导致一部分消息丢失,从而丢失记忆。所以就有了第三种策略:总结消息
LangChain提供了总结消息的默认实现:SummarizationMiddleware
用法很简单:
-
初始化SummarizationMiddleware和checkpointe

注意这里SummarizationMiddleware的参数(详细内容参考官网链接:summarization):
-
model:会话摘要时要使用的模型
-
trigger:会话摘要的触发时机,有三种设置:
-
fraction(float): 模型上下文大小的比例(0-1) -
tokens(int): 令牌数量 -
messages(int): 消息数量
-
-
keep:是指触发摘要后要保留的消息
-
fraction(float): 要保留的消息占模型上下文大小的比例(0-1) -
tokens(int): 要保留的消息的令牌数量 -
messages(int): 要保留的消息数量
-
2.创建Agent,设置middleware和checkpointer

更多推荐



所有评论(0)