博客配套代码发布于github:04 LangChain基础
本系列所有博客均配套Gihub开源代码,开箱即用,仅需配置API_KEY。
如果该Agent教学系列帮到了你,欢迎给我个Star⭐,非常感谢!
知识点:LLM 调用|Prompt 设计|Chain 构建|Memory 记忆|实战练习
一、了解Langchain
LangChain:Language Chain 语言链。
是的,LangChain作为一个模块,它的其中一个核心就是链:把不同的重要模块用链连接起来,作为一个统一的接口一起输出。
而LangChain作为一个非常庞大,内容量极其丰富的框架。想把里面知识点与文档全部啃完确实有点不太现实。所以本文会着重于最重要的知识点,一切讲解均以做出一个基于Langchain的智能体为目标,帮助读者尽快了解并学会使用Langchain。如果想要更深入的了解Langchain,推荐访问官方文档:docs.langchain.com/oss/python/… ,做进一步的学习。
二、六大核心模块概述
LangChain 的很多核心模块,其实我们在前三章就已经接触过了。现在的它们只不过是“换了个马甲”,把这层包装剥掉,你会发现:
底下的东西,还是你熟悉的老朋友。
下面我们逐一看清它们的“真面目”。
1. Models:就是 LLM,只是更规范了
-
它就是我们之前直接调用的大模型(如 GPT、通义千问)。
-
调用方式几乎一致,主要变化是:
- 导入路径变了(
from langchain_openai import ChatOpenAI) - 接口更统一(所有模型都支持
.invoke())
- 导入路径变了(
-
本质没变:输入消息 → 返回回复。
📌 小结:Models 是“标准化的 LLM 调用方式” 。
2. Prompt:名字没变,能力升级了
-
名字还是
PromptTemplate,用法也基本一样。 -
变化在于:
- 支持更多格式(如
ChatPromptTemplate适配对话模型) - 可以直接与 Messages 集成
- 和 Chain 无缝组合
- 支持更多格式(如
-
它不再是字符串拼接工具,而是“可执行的模板” 。
📌 小结:Prompt 是“会说话的输入” 。
3. Chain:新概念,但思想很老
-
表面作用:把 Prompt、LLM、Parser 等模块“串起来”形成流水线。
-
真正核心:统一接口,实现“可组合编程”
- 所有模块都实现
.invoke()、.stream()等方法 - 用
|操作符自由连接,像搭积木一样构建应用
- 所有模块都实现
-
它是 LangChain 的 核心设计思想:一切皆为
Runnable。
📌 小结:Chain 不是“功能”,而是“通信协议”——让 AI 组件能“即插即用” 。
4. Memory:记忆的“工业级”版本
-
功能还是“记住上下文”,但不再靠手动
messages.append({})。 -
LangChain 提供了:
- 标准化的记忆管理(如
ConversationBufferMemory) - 自动注入 prompt
- 支持长期记忆、摘要、向量记忆等高级模式
- 标准化的记忆管理(如
-
使用方式从“脚本式”变为“声明式”。
📌 小结:Memory 是“可插拔的记忆系统” 。
5. Agents:Function Calling 的“自动挡”
-
本质就是我们之前写的 Function Calling —— 让 AI 调用外部工具。
-
但我们自己写时:
- 要手动判断调用哪个函数
- 手动解析参数
- 控制流程
- 容错困难
-
LangChain 的 Agents:
- 把这些重复工作全封装了
- 引入 ReAct 框架(Thought → Action → Observation)
- 支持多步推理、自动循环、错误恢复
- 成为一个“自主决策系统”
🎯 所以:
Agents 是 LangChain 最复杂的模块,也是最接近“智能体”概念的部分。
📌 小结:Agents 是“会自己做决定的 AI”——从“程序员控制”到“AI 自主决策” 。
⚠️ 因其复杂度高,我们将放在《LangChain 进阶》篇详细讲解。
6. RAG:让 AI “查着资料答题”
-
一句话理解:AI 在回答前,先从你的资料库中“找答案”,然后“看着找到的内容”来回答,确保不瞎编。
-
技术上:
- 把文档切片 → 向量化 → 存入向量数据库
- 用户提问时,检索最相关的文本片段
- 拼入 prompt,让 LLM 基于此生成回答
-
它不是简单的“导入文件”,而是一套语义检索 + 上下文增强的系统。
📌 小结:RAG 是“开卷考试”模式,让 AI 基于你的数据回答问题。
⚠️ RAG 涉及向量检索、chunk 策略、rerank 等细节,复杂度不亚于 Agents,我们将单独开篇详解。
以上就是Langchain的六大核心模块。把这六大核心模块啃下来就能算基本掌握Langchain这个框架了。
其中Models、Prompt、Chain、Memory相对知识点较少,会一并在本文中讲解完毕。
而Agents较为复杂,会放在下篇 Langchain进阶 中再做讲解。
Rag则需要我们单独另开新篇,它的知识点与具体使用方法细节等同样需要好好唠一唠,其复杂程度完全不输Agents。
三、Models(模型)
代码实现:
from langchain_openai import ChatOpenAI
# 初始化模型
llm = ChatOpenAI(
model="deepseek-chat",
api_key=OPENAI_API_KEY,
base_url="https://api.deepseek.com"
)
# 调用模型
response = llm.invoke('你好喵')
print(response.content)
🔍 核心说明
llm是一个 LangChain Runnable 对象,代表一个可执行的 LLM 组件;.invoke()是 LangChain 为所有可运行单元(LLM、Tool、Chain、Agent 等)提供的统一调用接口;- 无论底层是 OpenAI、DeepSeek、Anthropic 还是本地模型,调用方式始终一致。
💡 LangChain 的核心价值之一: 抹平不同模型厂商的 API 差异,让你能用同一套代码组合任意 LLM + 工具 + 记忆 + 流程。
🧠 理解技巧
在读代码时,完全可以把response = llm.invoke("你好喵")脑内简化为 response = llm("你好喵")
因为从逻辑上看,它就是“传入输入,拿到输出”——.invoke() 不改变你的业务意图,只是框架的标准包装。
✅ 这样理解,流程更清爽。
⚠️ 但写代码时,请务必保留 .invoke()
虽然理解上可以忽略,实际开发中必须显式调用,原因包括:
- 它是 LangChain 生态的标准协议;
- 支持未来无缝切换到异步(
.ainvoke())、流式(.stream())等模式; - 确保与
ToolNode、Agent 等组件兼容。
✅ 一句话判断要不要用:
“LangChain 生态内,万物皆 Runnable,调用必 invoke; 自家写的纯函数,括号直接上,无需绕弯。”
四、Prompt(提示词)
代码实现:
from langchain_core.prompts import ChatPromptTemplate
# 定义提示词模板(推荐写法)
prompt = ChatPromptTemplate.from_messages([
("system","你是一个猫娘,说完话后面都会带个喵"),
("human","{input}") # {query}:占位符
])
# 格式化输出
formatted_prompt = prompt.invoke({"input":"你好呀"})
print(formatted_prompt)
📌 说明:
ChatPromptTemplate.from_messages是最通用、最推荐的写法- 支持
system、human、ai角色 {query}是变量,后续可被 Chain 自动填充- 返回的是
PromptValue,可直接传给 LLM
注意:此处prompt.invoke返回的并非是答案。
实际上,这里的作用可以理解为是把提示词写完。仅仅是写完,如果想使用该提示词,得再接入给llm。所以这里返回的答案自然也不会是ai的回复:
五、Chain(链)
逻辑构思:
这里的Chain就需要我们分为好几步,依次按照之前我们讲的模块顺序输出即可。
-
定义提示词模板
prompt = ChatPromptTemplate.from_messages([ ("system", "你非常可爱,说话末尾会带个喵"), ("human", "{input}") # {input}:占位符 ]) -
初始化模型
llm = ChatOpenAI( model="deepseek-chat", api_key=OPENAI_API_KEY, base_url="https://api.deepseek.com" ) -
定义解析器
parser = StrOutputParser()这里解析器要稍微讲解下:
-
LLM返回格式一般是像我们之前所见的AIMessage[{xx}]..之类的看起来非常繁琐的格式。 parser这里确定好解析器,相当于直接对其.content,拿到其中最重要的东西。并指定一个想最终输出的格式类型。比如这里要求的是StrOutputParser,输出的就是Str类。
-
组成chain并输出
# 组成Chain chain = prompt|llm|parser # 最终调用 result = chain.invoke({"input":"你好喵"}) print(result)
注:此处的chain内的|顺序不能调换,里面格式必须固定!
这里简单讲解一下这个管道符 |
LCEL
(Langchain Expression Language:Langchain表达式语言) :
可以理解为,将左边的输出作为右边的输入,依次从左向右执行。
比如:chain = prompt | llm | parser ≈ result = parser(llm(prompt(input)))
它是一种声明式语言,可以让你用 | 将不同的组件链接起来。
输出结果:
看起来是不是非常一目了然?顺序也十分优雅,从前到后依次排列完毕,这就是Chain的妙用。
六、Memory(记忆)
有了Chain的思路,这里你估计也能猜到我们打算怎么做了,上篇Chain的流程几乎不变,只需要再为其增加个 | Memory模块即可...吗?并非。
再看看这个chain:它的确能=llm|prompt|parser,但在memory这里可不适用。
chain的动作是线性的:prompt给ai写问题,llm让ai回答,parser确定输出格式。
而Memory的逻辑则不同,它是要独立出去,作为一种状态存在,持续记录上下文。
所以我们写法就得与chain独立开来:
# ...
prompt = ChatPromptTemplate.from_messages([
("system", "你非常可爱,说话末尾会带个喵"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}") # {input}:占位符
])
# ...
这里注意下:
prompt的写法明显不一样了,我们在system与human的中间新增了个MessagePlacehoolder,叫做history的占位符。它的作用就是在其中加入以往的历史对话,让它拥有记忆的功能。
其他地方llm,parser等跟之前一样:
llm = ChatOpenAI(
model="deepseek-chat",
api_key=OPENAI_API_KEY,
base_url="https://api.deepseek.com"
)
parser = StrOutputParser()
chain = prompt | llm | parser
再者,我们需要存储对应的会话历史,需要专门写个函数存储,同时还希望这个会话能隔离不同用户对话记录:
# 存储所有会话历史(可用数据库替换)
# 此处用字典模拟,也可替换成Redis、SQL等
store = {}
def get_session_history(session_id:str):
"""根据session_id获取该用户的聊天历史"""
if session_id not in store:
store[session_id] = ChatMessageHistory() # 创建新的历史记录
return store[session_id]
这里store可以自主改成某个数据库链接。get_session_histroy是目前较基础的记录聊天历史功能。后续你想扩展比如长期存储,或者对接数据库存储,都可以再做延伸。
最后我们将其包装成一个带记忆的Runnable:
# 包装成带记忆的Runnable
runnable_with_memory = RunnableWithMessageHistory(
runnable=chain,
get_session_history=get_session_history,
input_messages_key="input",
history_messages_key="history"
)
runnbale:我们之前做好的chain(链);
get_session_history:获取历史聊天记录的函数;
input_messages_key:当初用户提问的占位符;
history_messages_key:当初提示词中间的聊天历史记录占位符。
全部写完后我们就可以来个while 1函数测试下是否成功:
假设好某个用户的session_id:
session_id = 'user_123'
while 1:
user_input = input("\n你:")
if user_input=="quit":
print('拜拜喵!')
break
response = runnable_with_memory.invoke(
{"input":user_input},
config={"configurable":{"session_id":session_id}}
)
print(f'AI:{response}')
测试成功。
七、Agent实战
我们已经完全掌握了以上这些知识点:Models、Prompt、Chain、Memory。
此时我们的工具已经齐全,趁热打铁,赶紧来试试用Langchain自主搭建一个Agent。
假设:有固定人设、能记住用户对话内容、可以多轮对话、不调用工具与查阅资料、基于Langchain框架完成的Agent。
读者可以试试自己来完成上述要求,完成后或者有所阻碍再参照下方代码修改一下。
以下是完成对应要求的Agent代码:(将llm与prompt作为参数,重复功能封装了下)
def create_bot(llm,sys_prompt):
"""
:param sys_prompt: 系统提示词
:param llm: 已配置好的语言模型实例
:return:
"""
prompt = ChatPromptTemplate.from_messages([
("system",sys_prompt),
MessagesPlaceholder(variable_name="history"),
("human","{input}")
])
parser = StrOutputParser()
chain = prompt | llm | parser
store = {}
def get_session_history(session_id):
return store.setdefault(session_id,ChatMessageHistory())
return RunnableWithMessageHistory(
runnable=chain,
get_session_history=get_session_history,
input_messages_key="input",
history_messages_key="history"
)
def main():
# 此处集中配置LLM
llm = ChatOpenAI(
model="deepseek-chat",
api_key=OPENAI_API_KEY,
base_url="https://api.deepseek.com"
)
prompt = """你是‘小智’,一位专业、耐心且记忆力出色的 AI 助手。
你善于倾听,能记住用户之前提到的信息,并在后续对话中自然提及。
回答时简洁明了,避免冗余。"""
bot = create_bot(llm,prompt)
session_id = '123'
while 1:
user_input = input('\n你:')
if user_input == "quit":
print('拜拜')
break
response = bot.invoke({"input":user_input},config={"configurable":{"session_id":session_id}})
print("AI:",response)
if __name__ == '__main__':
main()
成功。它的确拥有了记忆。
但...似乎它有点傻?今天咋会是2023年。这就是它不能联网的弊端了。
所以在下篇文章的Langchain进阶中,我们会继续为它加入至关重要的Agents模块,为其赋予调用外部工具函数的功能,让它真正变得智能起来。
八、总结
知识点概括:LLM 调用|Prompt 设计|Chain 构建|Memory 记忆|实战练习
怎么样,把Langchain拆分成这六个模块逐个击破后,是不是立刻就感觉清晰明了了?基础的四大模块我们已经啃掉了,后面的Agents模块和Rag模块也是俩硬骨头。但别怕,我们慢慢啃,啃掉一块是一块。
下篇内容我们会开始学习Langchain的进阶部分。主要开始对Agents的学习与理解。同时还会涉及Langchain的一些高阶用法,让Agent更聪明。
🚀一键跳转:[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体
📌 项目代码 + 后续案例合集 全部发布在 Github 仓库 agent-craft ,持续更新中,欢迎Star⭐!