1.什么是LangChain
LangChain由Harrison Chase创建于2022年10月,是围绕LLMs(大语言模型)建立的一个框架

LangChain自身并不开发LLMs,它的核心理念是为各种LLMs实现通用的接口,把LLMs相关的组件"链接 " 在一起,简化LLMs应用的开发难度,方便开发者快速地开发复杂的LLMs应用. LangChain目前有两个语言的实现:python 和 Nodejs
LangChain主要组件:
- Models: 模型,各种类型的模型和模型集成, 比如GPT-4
- Prompts: 提示,包括提示管理、提示优化和提示序列化
- Memory:记忆,用来保存和模型交互时的上下文状态
- Indexes: 索引,用来结构化文档, 以便和模型交互
- Chains: 链,一系列对各种组件的调用
- Agents:代理,决定模型采取哪些行动,执行并且观察流程,直到完成为止
LangChain官网: LangChain Python integrations - Docs by LangChain
官网上可以查看所有LangChain相关的组件应用
2. Models组件
LangChain目前支持三种模型类型:
- LLMs:****大语言模型接收文本字符 作为输入,返回的也是文本字符
- Chat Models(聊天模型):**基于LLMs, 不同的是它接收聊天消息(一种特定格式的数据)作为输入,返回的也是聊天消息**
- Embeddings Models(文本嵌入模型):文本嵌入模型接收文本作为输入, 返回的是浮点数 列表
LLMs (大语言模型)
LLMs使用场景最多,常用大模型的下载库:https://huggingface.co/models

第一步:安装必备的工具包:langchain 和 ollama(属于第三方库)
pip install langchain pip install ollama第二步:ollama工具的安装与使用:
第三步:代码实现:
pythonfrom langchain_community.llms import Ollama # Ollama 类 属于 LLMs(大语言模型)组件,专门用于与本地运行的 Ollama 服务进行通信。它接收纯文本作为输入,并返回纯文本结果 # 初始化模型实例 # model = Ollama(model="qwen2.5:1.5b") model = Ollama(model="qwen2.5:7b") # 指定加载并运行 qwen2.5:7b(70亿参数)版本的通义千问模型 # invoke() 是 LangChain 提供的统一调用接口。这里传入了一段中文字符串 "请给我讲个七仙女的故事",模型会根据这段文本进行推理,并将完整的回复内容赋值给变量 result result = model.invoke("请给我讲个七仙女的故事") # 向模型发送提示词(Prompt)并获取生成结果 print(result)生成的结果:
python当然可以,这里有一个关于七仙女的简化故事。 在中国古代传说中,七仙女是由玉帝的女儿组成的。她们住在天宫,过着无忧无虑的生活。其中有一位叫织女的仙女,她不仅美丽,还非常善良和聪明,擅长纺织和缝纫,每天都会为人间的百姓制作美丽的衣服。 然而,织女最特别的是与牛郎的故事联系在一起。牛郎是人间的一个孤儿,他在父母早逝后被送到了亲戚家。不幸的是,他的舅舅不善待他,让他干了许多辛苦活。但牛郎非常勤劳和善良,这使他在牛群中变得非常受欢迎。 一天晚上,织女偷偷下凡来到人间游玩。她遇到了正在放牛的牛郎,两人一见如故,并很快相爱了。他们在人间共同生活了一段时间,生下了两个可爱的儿子。然而好景不长,这件事被玉帝得知后,他命令王母娘娘将织女带回天宫。 七仙女被带回到天庭,被迫与人间的生活隔绝开来。牛郎得知这一消息后,非常悲伤,但他并没有放弃希望。他向天上的星星祈求帮助,并最终用一匹神奇的神牛和一把金簪为工具,在天上开凿了一条银河,将他和织女分开了。 这条银河后来被人们称为"鹊桥",每年的七月初七,成千上万只喜鹊会飞来搭起一座彩虹般的桥梁,让织女和牛郎得以在这一天短暂地相会。这个故事象征着爱情的力量能够战胜一切困难,并且让人们相信,在最困难的时候,爱与希望不会消失。 这就是关于"七仙女"的一个经典版本,它传达了忠贞不渝的爱情主题。
Chat Models (聊天模型)
Chat Models和LLMs效果在某些场景表现基本类似,但是使用时需要按照约定传入合适的值, 常用下载库:https://huggingface.co/models:

Chat Models (聊天模型)代码需要用到的方法解析:
- **AIMessage:**用来保存LLM的响应, 以便在下次请求时把这些信息传回给LLM
- **HumanMessage:**发送给LLMs的提示信息, 比如"实现一 个快速排序方法 "
- **SystemMessage:**设置LLM模型的行为方式和目标,可以在这里给出具体的指示, 比如"作为 一个代码专家 ",或者"返回json格式 "
- **ChatMessage:**ChatMessage可以接收任意形式的值, 但是在大多数时间,应该使用上面的三种类型
代码实现:
python# 通过构建多角色消息列表(Messages)来实现系统指令设定和多轮上下文对话 # 导入消息类:LangChain 使用不同的消息类来区分对话中的角色 from langchain_core.messages import HumanMessage, SystemMessage, AIMessage from langchain_community.chat_models import ChatOllama # 初始化模型 model = ChatOllama(model="qwen2.5:7b") # 第一轮对话:设定系统角色 messages = [ # 用于给模型设定背景、环境或行为准则。这里告诉模型"你是一个著名的诗人",这会影响后续生成的语气和风格 SystemMessage(content="现在你是一个著名的诗人"), # 代表用户的输入 HumanMessage(content="给我写一首唐诗") ] # nvoke 与 打印:调用模型后,res 是一个 AIMessage 对象。 # 直接 print(res) 会打印出对象的完整结构(包含 content, response_metadata 等), # 而 print(res.content) 则只提取并打印模型生成的文本 res = model.invoke(messages) print(res) # # 输出完整的 AIMessage 对象(包含元数据等) print(res.content) # 仅输出模型生成的纯文本内容 # 加入AIMessage # 第二轮对话:引入 AIMessage 实现多轮上下文 # AIMessage:这是实现多轮对话记忆的关键。它代表了 AI 之前的回复。 # 上下文构建:通过将之前的 SystemMessage、HumanMessage 以及当前的 AIMessage 全部打包进 messages 列表中,模型就能"看到"之前的对话历史。 # 效果:当用户第二次输入"给我写一首宋词"时,模型不仅知道自己"是个诗人",还知道自己"刚刚写过一首唐诗",从而能够生成风格连贯、符合上下文逻辑的回复 messages = [ SystemMessage(content="现在你是一个著名的诗人"), HumanMessage(content="给我写一首唐诗"), # AIMessage:这是实现多轮对话记忆的关键。它代表了 AI 之前的回复 AIMessage(content='清风明月夜,独坐思故人。\n江水东流去,孤舟何处人?\n花落知多少,柳暗闭重门。\n唯有心中意,常随鹤归云。'), HumanMessage(content="给我写一首宋词"), ] res = model.invoke(messages) print(res) print(res.content)
pythoncontent='好的,我来为您创作一首唐风的诗歌:\n\n《秋江独步》\n\n秋水共长天一色,\n寒烟凝处见孤舟。\n独步江边听落叶,\n飘零似我此时愁。\n\n这首诗描绘了秋天江边独步的景象,通过"秋水"、"孤舟"、"落叶"等意象,表达了作者的孤独与哀愁。希望您会喜欢!' response_metadata={'model': 'qwen2.5:7b', 'created_at': '2026-06-23T13:59:13.0132221Z', 'message': {'role': 'assistant', 'content': ''}, 'done': True, 'done_reason': 'stop', 'total_duration': 39408887100, 'load_duration': 300001200, 'prompt_eval_count': 23, 'prompt_eval_duration': 5618198200, 'eval_count': 91, 'eval_duration': 33003823600} id='run-02998e13-58a6-4a0a-ab3a-dd3f399afe97-0' 好的,我来为您创作一首唐风的诗歌: 《秋江独步》 秋水共长天一色, 寒烟凝处见孤舟。 独步江边听落叶, 飘零似我此时愁。 这首诗描绘了秋天江边独步的景象,通过"秋水"、"孤舟"、"落叶"等意象,表达了作者的孤独与哀愁。希望您会喜欢! content='红叶西风瘦,秋水共长天。\n独立小桥幽梦,残月挂疏烟。\n露冷鸳鸯被,霜寒翡翠衾。\n独倚阑干处,泪眼问花笺。' response_metadata={'model': 'qwen2.5:7b', 'created_at': '2026-06-23T13:59:48.9419502Z', 'message': {'role': 'assistant', 'content': ''}, 'done': True, 'done_reason': 'stop', 'total_duration': 33656647200, 'load_duration': 194817800, 'prompt_eval_count': 82, 'prompt_eval_duration': 15615918700, 'eval_count': 48, 'eval_duration': 17592537600} id='run-c16aa356-105f-4f42-bffd-3ffe5bc1a900-0' 红叶西风瘦,秋水共长天。 独立小桥幽梦,残月挂疏烟。 露冷鸳鸯被,霜寒翡翠衾。 独倚阑干处,泪眼问花笺。
总结:
这段代码完美演示了 LangChain 中对话模型的标准范式:
- 不再使用纯字符串:输入不再是单纯的文本,而是带有角色标签的消息对象数组。
- 手动管理历史 :LangChain 本身不会自动帮你记住历史,你需要自己维护这个
messages列表,并在每次调用时把最新的对话追加进去传给模型。- 灵活的角色控制 :通过组合
System、Human、AI消息,你可以轻松实现角色扮演、少样本提示(Few-shot prompting)等高级技
Embeddings Models(嵌入模型)
Embeddings Models特点:将字符串作为输入 ,返回一个浮动数的列 表,在NLP中,Embedding的作用就是将数据进行文本向量化
将文本转换为这种浮点数列表(向量)的过程叫做文本向量化2。它的作用是捕捉词语之间的语义关系和语法相似性

代码如下:
pythonfrom langchain_community.embeddings import OllamaEmbeddings # temperature=0:设置温度参数为 0。对于文本向量化任务,我们希望每次输入的文本生成的向量是完全确定和一致的, # 不需要任何随机性,因此设为 0 是标准做法 model = OllamaEmbeddings(model="qwen2.5:7b", temperature=0) # embed_query 方法用于将单个字符串转换为向量表示(嵌入 res1 = model.embed_query('这是第一个测试文档') # 输出一个浮点数列表(例如 [0.0123, -0.0456, 0.0789, ...]),这就是该文本在模型高维语义空间中的坐标 print(res1) # 输出向量的维度 print(len(res1)) # embed_documents 方法用于对多个文本(列表)进行批量嵌入处理 res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档']) print(res2)
实际应用场景 :
这段代码是构建 RAG(检索增强生成) 或 本地知识库 的基础步骤。在实际开发中,通常的流程是:
- 使用
embed_documents将你的本地文档全部转化为向量,存入向量数据库(如 Chroma、FAISS)- 当用户提问时,使用
embed_query将用户的问题转化为向量。- 在向量数据库中进行相似度搜索(
similarity_search),找出与问题语义最相近的文档片段,最后喂给大模型进行总结回答⚠️ 进阶建议
虽然使用
qwen2.5:7b可以进行向量化,但在实际工程中,强烈建议使用专门的 Embedding 模型 (如nomic-embed-text或bge-large-zh-v1.5)
- 原因:通用大语言模型(如 Qwen2.5)的主要训练目标是预测下一个词,而专用 Embedding 模型是专门针对"判断两段文本是否相似"这一任务进行优化的,使用专用模型不仅速度更快,而且检索的准确率会大幅提升
3. Prompts组件
Prompt是指当用户输入信息给模型时加入的提示 ,这个提示的形式可以是zero-shot或者 few-shot等方式 , 目的是让模型理解更为复杂的业务场景以便更好的解决问题
提示模板:如果有了一个起作用的提示,可能想把它作为一个模板用于解决其他问题, LangChain就提供了PromptTemplates组件,它可以帮助更方便的构建提示
zero-shot提示方式
以一个场景来说明zero-shot提示方式: 代码展示了 LangChain 中 PromptTemplate(提示词模板) 的核心用法,即如何通过定义带占位符的模板,动态生成结构化的提示词并发送给大模型
代码如下:
python
# 导入与初始化模型
# 导入模块:引入了 PromptTemplate,这是 LangChain 中最基础的提示词管理工具
from langchain import PromptTemplate
from langchain_community.llms import Ollama
# 初始化模型:使用本地的 Qwen2.5-7B 模型作为推理引擎
model = Ollama(model="qwen2.5:7b")
# 定义模板
# template:定义了一个包含两个动态变量 {lastname} 和 {wname} 的字符串模板。这种设计使得模板可以复用,只需替换变量即可生成不同的提示词
# template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
template = "我的邻居姓{lastname},他的妻子姓{wname},他生了个儿子,结合两人的姓氏,给他儿子起个名字"
# PromptTemplate:将字符串实例化为 LangChain 对象。input_variables 显式声明了模板中需要被替换的变量名列表,这有助于在格式化时进行参数校验
prompt = PromptTemplate(
input_variables=["lastname", 'wname'],
template=template,
)
# 动态填充模板
# format() 方法:将具体的值("王" 和 "李")传入模板,替换掉对应的占位符。
# 注释掉的代码:展示了如果只传一个参数而缺少 wname,会导致报错。这体现了 input_variables 的校验作用。
# 输出结果:打印出的 prompt_text 将是完整的句子:我的邻居姓王,他的妻子姓李,他生了个儿子,结合两人的姓氏,给他儿子起个名字
# prompt_text = prompt.format(lastname="王")
prompt_text = prompt.format(lastname="王", wname="李")
print(f'prompt_text-->{prompt_text}')
# result: 我的邻居姓王,他生了个儿子,给他儿子起个名字
# 调用大模型进行推理
# nvoke():将格式化后的完整字符串发送给 Qwen2.5-7B 模型。
# 模型推理:模型接收到这个具体的场景描述后,会理解"结合两人姓氏起名"的意图,并生成诸如"王李轩"、"李王浩"或"王慕李"等富有创意的名字
result = model.invoke(prompt_text)
print(result)
python
prompt_text-->我的邻居姓王,他的妻子姓李,他生了个儿子,结合两人的姓氏,给他儿子起个名字
给孩子的姓名取名是一件既充满乐趣也富有意义的事情。结合您提供的信息,"王"和"李",可以考虑从这两个姓氏中汲取灵感,创造一个既有文化韵味又具有独特个性的名字。
这里提供一个建议:"王建黎"。这个名字中的"建"字象征着建设与建立的美好寓意,同时也意味着对未来的希望;而"黎"则来源于姓氏"李"的谐音,不仅巧妙地融合了两个姓氏,还带有一种清新脱俗的感觉。当然,这只是一个参考建议,最终的选择可以根据个人偏好和文化背景来决定。
另外,还可以根据五行、四柱等中国文化中的传统方法来进行起名,以期为孩子带来好运气和美好的未来。如果需要更加专业的名字推荐服务,也可以考虑咨询专门的取名大师或利用在线取名工具辅助选取。
这段代码演示了 LangChain 中**"模板与逻辑分离"** 的设计思想。在实际应用中,我们不需要把用户输入直接硬编码在字符串里,而是通过
PromptTemplate统一管理提示词结构,这不仅让代码更优雅,也极大提升了后续维护和扩展的便利性
few-shot提示方式
以一个场景来说明few-shot提示方式: 代下面码展示了如何使用 LangChain 的 Few-Shot Prompting(少样本提示) 技术,通过提供几个示例来引导大模型理解任务模式,从而准确完成"写出反义词"的任务
代码如下:
python
# 引入了 PromptTemplate(基础模板)和 FewShotPromptTemplate(少样本模板)
from langchain import PromptTemplate, FewShotPromptTemplate
from langchain_community.llms import Ollama
model = Ollama(model="qwen2.5:7b")
# 定义示例数据
# 作用:这是"少样本"的核心。我们给模型提供了两个"输入-输出"对。
# 目的:让模型通过观察这些例子,学习到任务是"寻找反义词",而不是解释词义或造句
examples = [
{"word": "开心", "antonym": "难过"},
{"word": "高", "antonym": "矮"},
]
# 定义单个示例的格式
# example_template:定义了每一个示例在最终 Prompt 中长什么样。它使用了占位符 {word} 和 {antonym}
example_template = """
单词: {word}
反义词: {antonym}\\n
"""
# example_prompt:将上述字符串模板实例化为一个 LangChain 对象,告诉系统哪些变量需要被替换
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_template,
)
# 构建少样本提示模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples, # 传入上面定义的示例列表
example_prompt=example_prompt, # 传入单个示例的格式化模板
prefix="给出每个单词的反义词", # 放在所有示例之前的指令(System Instruction), 相当于任务描述,告诉模型总体要做什么
suffix="单词: {input}\\n反义词:", # 放在所有示例之后,包含用户当前输入的引导语, 这是关键的"诱导"部分。它以 单词: {input}\n反义词: 结尾,强行将模型的生成模式锁定为"只输出反义词"
input_variables=["input"], # 声明用户输入变量的名称
example_separator="\\n", # 示例之间的分隔符
)
prompt_text = few_shot_prompt.format(input="粗")
print(prompt_text)
print('*' * 80)
# 给出每个单词的反义词
# 单词: 开心
# 反义词: 难过
# 单词: 高
# 反义词: 矮
# 单词: 粗
# 反义词:
# # 调用模型: 将构建好的长文本发送给 LLM
print(model.invoke(prompt_text))
# 细
python
给出每个单词的反义词\n
单词: 开心
反义词: 难过\n
\n
单词: 高
反义词: 矮\n
\n单词: 粗\n反义词:
********************************************************************************
反义词: 细
这段代码演示了 In-Context Learning(上下文学习) 的典型应用。相比于直接问模型"粗的反义词是什么",使用
FewShotPromptTemplate可以显著提高模型输出的格式规范性和准确率,特别是在处理复杂任务或特定格式要求时非常有效
4. Chain组件
在LangChain中,Chains描述了将LLM与其他组件结合起来完成一个应用程序的过程,针对上一小节的提示模版例子,zero-shot里面,可以用链来连接提示模版组件和模型,进而可以实现代码的更改:
代码展示了 LangChain 中 Chain(链) 的核心概念,特别是如何使用
LLMChain将"提示词模板(Prompt)"和"大语言模型(LLM)"组装成一个可执行的流水线代码如下:
python
# 引入了提示词模板、Ollama 模型以及 LLMChain 类
from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain
# 定义提示词模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
# 定义了一个包含占位符 {lastname} 的模板,并将其封装为 PromptTemplate 对象
prompt = PromptTemplate(
input_variables=["lastname"],
template=template,
)
# 初始化了本地的 Qwen2.5-7B 模型作为推理引擎
llm = Ollama(model="qwen2.5:7b")
# 组装 LLMChain
# 核心逻辑:LLMChain 是 LangChain 中最基础的链。
# 它将 llm 和 prompt 绑定在一起。
# 当你调用这个 chain 时,它会自动执行:接收变量 -> 填充模板 -> 发送给模型 -> 返回结果 这一整套流
chain = LLMChain(llm=llm, prompt=prompt)
# LangChain 表达式语言 (LCEL)
# 这是 LangChain 目前最推荐的链式写法(LCEL 语法)。
# 使用管道符 | 将 prompt 和 llm 串联,不仅代码更简洁,而且原生支持流式输出(Streaming)和异步调用。
# 如果采用这种写法,调用时同样需要使用 chain.invoke({"lastname": "王"})
# chain = prompt | llm
# 执行链
# 关于 invoke() 方法:invoke() 是 LangChain 较新版本中统一的标准调用接口。
# 语法纠正:在标准的 LangChain 语法中,使用 invoke() 调用 LLMChain 时,必须传入一个字典(Dictionary),
# 键名需要与模板中的变量名一致。直接传入字符串 "王" 可能会引发参数解析错误。
# 正确的写法应该是:chain.invoke({"lastname": "王"})
# 关于 run() 方法:代码中注释掉的 chain.run("王") 是旧版本的调用方式。
# 在旧版本中,如果模板只有一个输入变量,run() 允许直接传入字符串。但在 LangChain 0.1.x 及之后的版本中,
# run() 方法已被标记为废弃(Deprecated),官方强烈建议全面迁移到 invoke() 方法
# print(chain.run("王"))
print(chain.invoke("王"))
如果想将第一个模型输出的结果,直接作为第二个模型的输入,还可以使用LangChain的SimpleSequentialChain, 代码展示了 LangChain 中 SimpleSequentialChain(简单顺序链) 的核心用法。它允许你将多个
LLMChain串联起来,形成一条自动化的流水线,其中前一个链的输出会自动作为后一个链的输入代码如下:
python
from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain, SimpleSequentialChain
# 创建第一条链
# 作用:定义了流水线的第一个环节。它接收一个姓氏(lastname),并让大模型生成一个正式的名字。
# 输出:模型会返回一个字符串(例如:"王浩然")。在 SimpleSequentialChain 中,这个输出会直接作为纯文本传递给下一个环节
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
first_prompt = PromptTemplate(
input_variables=["lastname"],
template=template,
)
llm = Ollama(model="qwen2.5:7b")
first_chain = LLMChain(llm=llm, prompt=first_prompt)
# 创建第二条链
# 作用:定义了流水线的第二个环节。它接收一个名字(child_name),并基于这个名字生成一个小名。
# 衔接原理:SimpleSequentialChain 非常"智能",
# 它会自动忽略变量名的差异(即把第一步输出的"王浩然"这个字符串,直接塞进第二步的 {child_name} 占位符中)
second_prompt = PromptTemplate(
input_variables=["child_name"],
template="邻居的儿子名字叫{child_name},给他起一个小名",
)
second_chain = LLMChain(llm=llm, prompt=second_prompt)
# 链接两条链: 组装并执行顺序链
# 组装:将两条链按执行顺序放入一个列表中。
# verbose=False:设置为 False 表示在控制台隐藏中间的执行日志。
# 如果改为 True,你可以清晰地看到第一步生成了什么,以及第二步是如何接收并处理的
overall_chain = SimpleSequentialChain(chains=[first_chain, second_chain], verbose=False)
print(overall_chain)
print('*' * 80)
# 执行链,只需要传入第一个参数
# 运行 SimpleSequentialChain 时,只需要传入整个流水线的初始输入(即第一个链需要的变量 "王"
catchphrase = overall_chain.run("王")
print(catchphrase)
python
chains=[LLMChain(prompt=PromptTemplate(input_variables=['lastname'], template='我的邻居姓{lastname},他生了个儿子,给他儿子起个名字'), llm=Ollama(model='qwen2.5:7b')), LLMChain(prompt=PromptTemplate(input_variables=['child_name'], template='邻居的儿子名字叫{child_name},给他起一个小名'), llm=Ollama(model='qwen2.5:7b'))]
********************************************************************************
为宝宝起小名是一件非常温馨且富有创意的事情,它往往承载着家人对宝宝的爱与祝福。考虑到您邻居的名字是"王",可以结合以下建议给出一个既有文化寓意又温馨的小名:
1. 小翔:灵感来源于"王浩翔"的名字,"小翔"简洁明了,表达了希望孩子自由翱翔、勇敢向前的美好愿望。
2. 淳淳:这个小名简单好记,寓意宝宝如同淳朴的民风一样善良纯真。同时,"淳淳"也有着重复音节的特点,听起来更加柔和悦耳。
3. 瑞儿(或者瑞瑞):瑞在古代有吉祥、幸福之意,加上"儿"字不仅显得亲切可爱,还增添了几分温馨和喜悦感。"瑞瑞"两个相同的音节读起来也很上口。
另外,还可以考虑结合家族传统或文化背景来寻找灵感。例如,"王家"可以联想到中国的龙凤呈祥等吉祥图案;或者从《诗经》、唐诗宋词中汲取灵感,选用一些富有诗意的字眼作为小名。总之,在起小名时要尽量选择寓意美好且容易记忆的名字,这样不仅能够表达家人对宝宝的美好祝愿,还能让宝宝在成长的过程中时刻感受到来自家庭的温暖与爱意。
SimpleSequentialChain 的局限性 :这种链要求流水线中的每一个环节都必须是严格的单输入、单输出 13。如果你在未来的任务中需要同时保留第一步的"大名"和第二步的"小名",或者某一步需要多个输入,就需要升级为
SequentialChain或者使用目前最推荐的 LCEL(LangChain Expression Language) 语法(如prompt | llm
5. Agents组件
在 LangChain 中 Agents 的作用就是根据用户的需求,来**访问一些第三方工具(**比如:搜索引擎或者 数据库),进而来解决相关需求问题
那么 为什么要借助第三方库呢?
因为大模型虽然非常强大,但是也具备一定的局限性,比如不能回答实时信息 、处理数学逻辑问题仍 然非常的初级等等,因此,可以借助第三方工具来辅助大模型的应用

现在实现一个使用代理的例子:可以使用多个代理工具,让Agents选择执行,代码如下 :
代码含义: 使用 LangChain 构建一个 Agent(智能体),并赋予它使用外部工具(如计算器)来解决大模型自身不擅长的问题(如精确的数学计算)
python
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain_community.llms import Ollama
from langchain_core.prompts import PromptTemplate
from langchain_community.agent_toolkits.load_tools import load_tools
# 实例化大模型
llm = Ollama(model="qwen2.5:7b")
# 设置工具
# "serpapi"实时联网搜素工具、"math": 数学计算的工具
# tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 作用:大模型本身在精确数学计算上容易产生"幻觉"。llm-math 是一个内置工具,
# 它允许 Agent 将复杂的数学问题转化为 Python 的 numexpr 表达式来执行,从而获得绝对准确的结果
# 原理:Agent 会根据工具的描述,自主决定何时调用这个数学工具
tools = load_tools(["llm-math"], llm=llm)
# 初始化 Agent, 实例化代理Agent:返回 AgentExecutor 类型的实例
# initialize_agent:这是 LangChain 中用于创建 Agent 的经典函数,它会将工具和大模型绑定,并返回一个 AgentExecutor(代理执行器)
# AgentType.ZERO_SHOT_REACT_DESCRIPTION:这是最常用的 Agent 类型。
# 它采用了 ReAct(Reasoning + Acting) 框架。
# 在这种模式下,Agent 会进行"思考(Thought) -> 行动(Action) -> 观察结果(Observation)"的循环,仅根据工具的描述(零样本)来决定如何使用工具.
# verbose=True:开启详细日志。这会在控制台打印出 Agent 内部的思考和调用过程,对于调试和理解 Agent 的工作流非常有帮助
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
print('agent', agent)
print('*' * 80)
# 准备提示词
prompt_template = """解以下方程:3x + 4(x + 2) - 84 = y; 其中x为3,请问y是多少?"""
prompt = PromptTemplate.from_template(prompt_template)
# print('prompt-->', prompt)
print('*' * 80)
# 1. 先格式化为纯字符串
formatted_query = prompt_template.format(equation="3x + 4(x + 2) - 84 = y")
# 代理Agent工作
# 执行逻辑:当把这道数学题传给 Agent 时,Agent 会意识到自己无法心算,于是触发 llm-math 工具。
# 工具计算出准确结果后,Agent 再将结果整合成自然语言返回
result = agent.run(prompt_template)
print(f'result-->{result}')
代码优化与避坑提示
- 多余的 PromptTemplate :代码中创建了
prompt = PromptTemplate.from_template(prompt_template),但这行代码实际上并没有被使用 。在agent.run()中,你直接传入了原始字符串prompt_template。对于 Agent 来说,直接传入字符串即可,不需要手动格式化 PromptTemplate。- API 版本兼容性 :与之前的 Chain 类似,
initialize_agent和agent.run()在 LangChain 较新版本中已被标记为废弃(Deprecated)。
- 新写法建议 :推荐使用
create_react_agent配合 LCEL 语法,并使用agent.invoke({"input": prompt_template})来替代run()6。- 本地模型的能力要求 :
ZERO_SHOT_REACT_DESCRIPTION对大模型的逻辑推理和指令遵循能力要求较高。Qwen2.5-7B 能够胜任,但如果发现 Agent 陷入死循环或无法正确解析工具输出,可以尝试换用参数量更大的模型(如 14B 或 72B)
查询langchain支持的工具,代码如下 :
python
# from langchain.agents import get_all_tool_names
from langchain_community.agent_toolkits.load_tools import get_all_tool_names
results = get_all_tool_names()
print(results)
print(len(results))
# ['python_repl', 'requests', 'requests_get', 'requests_post', 'requests_patch', 'requests_put', 'requests_delete', 'terminal', 'sleep', 'wolfram-alpha', 'google-search', 'google-search-results-json', 'searx-search-results-json', 'bing-search', 'metaphor-search', 'ddg-search', 'google-serper', 'google-scholar', 'google-serper-results-json', 'searchapi', 'searchapi-results-json', 'serpapi', 'dalle-image-generator', 'twilio', 'searx-search', 'wikipedia', 'arxiv', 'golden-query', 'pubmed', 'human', 'awslambda', 'sceneXplain', 'graphql', 'openweathermap-api', 'dataforseo-api-search', 'dataforseo-api-search-json', 'eleven_labs_text2speech', 'google_cloud_texttospeech', 'news-api', 'tmdb-api', 'podcast-api', 'memorize', 'llm-math', 'open-meteo-api']
python
['sleep', 'wolfram-alpha', 'google-search', 'google-search-results-json', 'searx-search-results-json', 'bing-search', 'metaphor-search', 'ddg-search', 'google-lens', 'google-serper', 'google-scholar', 'google-finance', 'google-trends', 'google-jobs', 'google-serper-results-json', 'searchapi', 'searchapi-results-json', 'serpapi', 'dalle-image-generator', 'twilio', 'searx-search', 'merriam-webster', 'wikipedia', 'arxiv', 'golden-query', 'pubmed', 'human', 'awslambda', 'stackexchange', 'sceneXplain', 'graphql', 'openweathermap-api', 'dataforseo-api-search', 'dataforseo-api-search-json', 'eleven_labs_text2speech', 'google_cloud_texttospeech', 'read_file', 'reddit_search', 'news-api', 'tmdb-api', 'podcast-api', 'memorize', 'llm-math', 'open-meteo-api', 'requests', 'requests_get', 'requests_post', 'requests_patch', 'requests_put', 'requests_delete', 'terminal']
51
LangChain支持的工具如下:

6. Memory组件
大模型本身不具备上下文的概念,它并不保存上次交互的内容,ChatGPT之所以能够和人正常沟通对话,因为它进行了一层封装,将历史记录回传给了模型, 因此 LangChain也提供了Memory组件, Memory分为两种类型 :短期记忆 和长期记忆,短期记忆一般指单一会话时传递数据 ,长期记忆则是处理多个会话时获取和更新信息
目前的Memory组件只需要考虑ChatMessageHistory,举例分析:
python
# 使用消息存储容器 ChatMessageHistory 来手动管理对话历史
from langchain.memory import ChatMessageHistory
# 初始化:创建了一个 history 实例。它本质上就像一个列表(List),专门用来按顺序存放用户和 AI 的消息对象
history = ChatMessageHistory()
# 添加对话消息
# add_user_message():将用户的输入添加到历史记录中,底层会自动将其封装为 HumanMessage 对象。
# add_ai_message():将 AI 的回复添加到历史记录中,底层会自动将其封装为 AIMessage 对象
history.add_user_message("在吗?")
history.add_ai_message("有什么事?")
# messages 属性:这是 ChatMessageHistory 的核心属性,它会返回一个包含所有消息对象的列表
print(history.messages)
核心概念与进阶提示
- 手动管理的痛点 :正如这段代码所展示的,
ChatMessageHistory需要开发者手动将每一轮的用户输入和 AI 回复追加进去,如果对话轮数变多,代码会变得非常繁琐。- 内存限制 :
ChatMessageHistory默认将数据保存在内存中,程序一旦重启,历史对话就会丢失- 如何自动管理? :在实际开发中,通常不会直接手动调用
add_user_message,而是将其与 LangChain 的Memory模块(如**ConversationBufferMemory)或RunnableWithMessageHistory结合使用,这样,Chain 在执行invoke()** 时,会自动完成"读取历史 -> 拼接 Prompt -> 调用模型 -> 保存新对话"的全套流程
和qwen结合,直接使用ConversationChain, 代码如下:代码展示了 LangChain 中 ConversationChain(对话链) 的核心用法,它结合了大语言模型和记忆组件,让 AI 能够"记住"之前的对话内容,从而实现多轮连贯对话
python
# 引入了 ConversationChain,这是 LangChain 封装好的专门用于多轮对话的链
from langchain import ConversationChain
from langchain_community.llms import Ollama
# 实例化大模型:
# 初始化了本地的 Qwen2.5-7B 模型作为推理引擎
llm = Ollama(model="qwen2.5:7b")
# 实例化对话链
# 核心逻辑:虽然代码中没有显式传入 memory 参数,但 ConversationChain 默认自带 ConversationBufferMemory(对话缓冲区记忆)。
# 工作原理:它会在后台维护一个列表,自动将你每次的输入(Human)和模型的输出(AI)追加到这个列表中。
# 在每次调用模型前,它会把完整的对话历史拼接成 Prompt 发给大模型
conversation = ConversationChain(llm=llm)
resut1 = conversation.predict(input="小明有1只猫")
print(resut1)
print('*'*80)
resut2 = conversation.predict(input="小刚有2只狗")
print(resut2)
print('*'*80)
resut3 = conversation.predict(input="小明和小刚一共有几只宠物?")
print(resut3)
print('*'*80)
python
小明有一只可爱的猫咪!你想要知道关于这只猫的更多信息吗?比如它的名字、品种或者是它的一些有趣的故事呢?
********************************************************************************
小刚有两个忠诚的小伙伴!你想了解更多关于他的狗狗们的信息吗?比如他们的名字、品种或者是一些它们共同度过的趣事呢?
********************************************************************************
小明和小刚一共有3只宠物。小明有1只猫,小刚有2只狗。
********************************************************************************
如果要像chatGPT一样,长期保存历史消息,可以使用`**messages_to_dict`**方法, 代码如下:
代码演示了 LangChain 中一个非常关键的高级概念:消息的序列化(Serialization)与反序列化(Deserialization)
在实际的 AI 应用开发中,对话历史不能永远只存在内存里(程序一关就没了),需要把它们转换成可以存储的格式(如 JSON 字符串),存到本地文件或数据库中,下次再读取出来恢复成 LangChain 能认识的消息对象
python
# ChatMessageHistory:用于在内存中管理对话消息的基础容器。
# messages_to_dict:将 LangChain 的消息对象(如 HumanMessage)转换为普通的 Python 字典。这是为了能够使用 json.dump() 写入文件。
# messages_from_dict:将普通的 Python 字典还原为 LangChain 的消息对象。这是为了在读取文件后,Chain 依然能识别这些历史消息
from langchain.memory import ChatMessageHistory
from langchain.schema import messages_from_dict, messages_to_dict
from langchain_community.llms import Ollama
# 实例化大模型
llm = Ollama(model="qwen2.5:7b")
# 执行逻辑:首先向内存中添加了一轮对话,然后通过 messages_to_dict 将消息列表转换成了字典列表
history = ChatMessageHistory()
history.add_user_message("hi!")
history.add_ai_message("whats up?")
dicts = messages_to_dict(history.messages)
# 预期输出:你会看到每个消息都被加上了 type 标记(如 'human' 和 'ai'),并且内容被包裹在 data 字段中。
# 这种结构保证了在反序列化时,LangChain 能准确知道哪条是用户说的,哪条是 AI 说的
print(dicts)
# [{'type': 'human', 'data': {'content': 'hi!', 'additional_kwargs': {}}},
# {'type': 'ai', 'data': {'content': 'whats up?', 'additional_kwargs': {}}}]
# 读取历史消息
# 执行逻辑:将刚才转换好的字典列表,重新还原为 LangChain 的消息对象列表
new_messages = messages_from_dict(dicts)
print(new_messages)
这段代码是构建长期记忆(Long-term Memory) 的基石。在实际生产环境中,你通常会结合
json模块来实现本地文件存储
python
import json
# 1. 保存对话历史到本地文件
with open("chat_history.json", "w", encoding="utf-8") as f:
json.dump(dicts, f, ensure_ascii=False, indent=2)
# 2. 从本地文件读取并恢复对话历史
with open("chat_history.json", "r", encoding="utf-8") as f:
loaded_dicts = json.load(f)
restored_messages = messages_from_dict(loaded_dicts)
掌握了这个机制后,就可以轻松实现跨会话的记忆,或者自定义基于 Redis/MySQL 的持久化存储类
7. Indexes组件
Indexes组件的目的是让LangChain具备处理文档处理的能力,包括:文档加载、检索等。注意,这里的文档不局限于txt、pdf等文本类内容 ,还涵盖email、区块链、视频等内容
- 文档加载器
- 文本分割器
- VectorStores(向量数据库)
- 检索器
文档加载器
文档加载器主要基于`Unstructured` 包,`Unstructured` 是一个python包,可以把各种类型的文件转换成文本,文档加载器使用起来很简单,只需要引入相应的loader工具,代码如下:
代码展示了 LangChain 中两种不同文档加载器(
TextLoader和UnstructuredFileLoader)在处理同一个纯文本文件(衣服属性.txt)时的区别

python
# # 使用 TextLoader 加载 TXT 文件
# # TextLoader 是专为加载纯文本文件(.txt)设计的加载器
# # 它会将整个文件作为一个整体读取,默认返回一个包含单个 Document 对象的列
from langchain_community.document_loaders import TextLoader
loader = TextLoader('衣服属性.txt', encoding='utf8')
docs = loader.load()
# 输出预期:len(docs) 通常为 1。docs.page_content 包含文件中的全部原始文本,metadata 中仅包含文件路径(source)
print(docs) # [Document(metadata={'source': '衣服属性.txt'}, page_content='身高:160-170cm, 体重:90-115斤,建议尺码M。\n身高:165-175cm, 体重:115-135斤,建议尺码L。\n身高:170-178cm, 体重:130-150斤,建议尺码XL。\n身高:175-182cm, 体重:145-165斤,建议尺码2XL。\n身高:178-185cm, 体重:160-180斤,建议尺码3XL。\n身高:180-190cm, 体重:180-210斤,建议尺码4XL。\n面料分类:其他\n图案:纯色\n领型:翻领\n衣门襟:单排扣\n颜色:黑色 卡其色 粉色 杏色\n袖型:收口袖\n适用季节:冬季\n袖长:长袖\n厚薄:厚款\n适用场景:其他休闲\n衣长:常规款\n版型:宽松型\n款式细节:假两件\n工艺处理:免烫处理\n适用对象:青年\n面料功能:保暖\n穿搭方式:外穿\n销售渠道类型:纯电商(只在线上销售)\n材质成分:棉100%')]
print(len(docs)) # 1
a = docs[0].page_content[:4]
print(a) # 身高:1
print('*'*80)
# UnstructuredFileLoader 是一个"万能"加载器,它底层利用了 unstructured 库,能够自动检测文件类型并尝试提取有意义的信息
# 虽然它也能处理 TXT 文件,但它会尝试对文本进行"元素级(Elements)"的分析
from langchain_community.document_loaders import UnstructuredFileLoader
loader = UnstructuredFileLoader('衣服属性.txt', encoding='utf8')
docs = loader.load()
# 输出预期:len(docs) 的长度可能大于 1。如果 unstructured 库将文本按段落或句子进行了拆分,
# 它会返回多个 Document 对象,每个对象代表一个逻辑段落
print(docs)
print(len(docs))
a = docs[0].page_content[:4]
print(a)
LangChain支持的文档加载器 (部分):

文档分割器
由于模型对输入的字符长度有限制,在碰到很长的文本时,需要把文本分割成多个小的文本片段
文本分割最简单的方式是按照字符长度进行分割,但是这会带来很多问题, 比如说如果文本是一 段代码,一个函数被分割到两段之后就成了没有意义的字符,所以整体的原则是把语义相关的文本片段放在一起
LangChain中最基本的文本分割器是CharacterTextSplitter,它按照指定的分隔符(默认"\n\n ")进行分割,并且考虑文本片段的最大长度
代码如下:
代码展示了 LangChain 中最基础的文本分割器 **
CharacterTextSplitter**的用法。它的作用是将长文本按照指定的分隔符(如空格、换行符)切分成大小适中的文本块(Chunk),这是构建 RAG(检索增强生成)系统时非常关键的一步
python
from langchain.text_splitter import CharacterTextSplitter
# 初始化分割器
text_splitter = CharacterTextSplitter(
separator=" ", # 空格分割,但是空格也属于字符
chunk_size=5, # 每个文本块的最大长度(字符数)为 5
chunk_overlap=1, # 相邻的两个文本块之间会有 1 个字符的重叠。这在 RAG 中非常重要,可以防止一句话被硬生生切断,从而保留上下文语义
)
# print("a b c d e f".split('c'))
# 一句分割
# 执行逻辑:首先按空格将字符串切分为 ['a', 'b', 'c', 'd', 'e', 'f']。
# 然后,分割器会尝试将这些单词拼接起来,直到长度接近 chunk_size=5
a = text_splitter.split_text("a b c d e f")
print(a) # ['a b c', 'c d e', 'e f'], 由于 chunk_overlap=1,上一个块的结尾字符 c 和 e 会作为下一个块的开头
# 多句话分割(文档分割)
# create_documents 方法不仅可以分割文本,还会将分割后的纯文本字符串自动封装成 LangChain 的 Document 对象列表
texts = text_splitter.create_documents(["a b c d e f", "e f g h"], )
"""
[
Document(page_content='a b c', metadata={}),
Document(page_content='c d e', metadata={}),
Document(page_content='e f', metadata={}),
Document(page_content='e f', metadata={}),
Document(page_content='f g h', metadata={})
]
"""
print(texts)
- 关于
separator的坑 :你在代码注释中提到"空格也属于字符"。确实如此,CharacterTextSplitter在计算chunk_size时,分隔符本身也会被计算在内。如果文本中没有指定的分隔符,它可能会退化为按字符强行截断。split_textvscreate_documents:
split_text返回的是纯字符串列表List[str]。create_documents返回的是List[Document]对象。在实际的 RAG 流程中,我们通常使用create_documents或split_documents,因为Document对象可以携带metadata(如文件来源、页码等),方便后续存入向量数据库。- 更推荐的分割器 :
CharacterTextSplitter比较基础,如果文本中没有足够的空格或换行符,它可能会切出不符合预期的块。在实际开发中,LangChain 官方更推荐使用RecursiveCharacterTextSplitter(递归字符分割器) ,它会依次尝试["\n\n", "\n", " ", ""]等多种分隔符,能更好地保持段落的语义完整性
除了CharacterTextSplitter分割器,LangChain还支持其他文档分割器 (部分):

VectorStores(向量数据库)
VectorStores是一种特殊类型的数据库,它的作用是存储由嵌入创建的向量,提供相似查询等功能,使用其中一个 Chroma 组件作为例子(pip install chromadb):
代码如下:
代码演示了如何基于提供的网页内容,使用 LangChain 和 Chroma 构建一个简易的检索增强生成(RAG)系统
它的核心流程是:将文本切块 -> 向量化 -> 存入向量数据库 -> 根据问题进行相似度检索
python
from langchain_community.embeddings import OllamaEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import Chroma
# 读取并切分文本
# pku.txt内容:<https://www.pku.edu.cn/about.html>
with open('./pku.txt') as f: # 代码从 pku.txt 文件中读取了网页的全部文本内容
state_of_the_union = f.read()
# 使用 CharacterTextSplitter 将长文本按字符数切分成多个小块(Chunk)。
# 这里设置了 chunk_size=100,意味着每个文本块的长度不超过100个字符。chunk_overlap=0 表示块与块之间没有重叠
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
# 结果:texts 变量将是一个包含多个短文本字符串的列表
texts = text_splitter.split_text(state_of_the_union)
print(f'texts-->{texts}')
print(f'len(texts)-->{len(texts)}')
# 文本向量化并存入数据库
# 初始化嵌入模型:使用 OllamaEmbeddings 加载本地的 mxbai-embed-large 模型。
# 这个模型的作用是将文本(字符串)转换成计算机可以理解的向量(一串数字)
embeddings = OllamaEmbeddings(model="mxbai-embed-large")
# 创建向量数据库:Chroma.from_texts() 会遍历 texts 列表中的每一个文本块,
# 调用嵌入模型将其转换为向量,然后将这些向量和原始文本一起存储在内存中的 Chroma 数据库里
docsearch = Chroma.from_texts(texts, embeddings)
# 执行相似度检索
# 定义问题:query 是你想要查询的问题
query = "发现了啥子事"
"""
相似度搜索:similarity_search 方法会做以下几件事:
1. 将问题 query 也通过同样的嵌入模型转换成向量
2. 在 Chroma 数据库中,计算问题向量与所有已存储的文本块向量的相似度
3. 根据相似度从高到低排序,返回最相关的前 k 个结果。这里 k=1,所以只返回最相关的一个
"""
docs = docsearch.similarity_search(query, k=1)
# 预期输出:docs 将是一个包含一个 Document 对象的列表。这个对象里包含了从 pku.txt 中找到的、与"发现了啥子事"最相关的文本片段
print(f'docs==>{docs}')
print(f'len(docs)==>{len(docs)}')
优化建议
CharacterTextSplitter的局限性
- 使用的
CharacterTextSplitter是最基础的分割器,它可能会在单词或句子的中间进行硬切分,破坏语义的完整性- 推荐 :在实际项目中,更推荐使用**
RecursiveCharacterTextSplitter**。它会智能地尝试按段落(\n\n)、句子(\n)、单词()等顺序进行切分,能更好地保持文本块的语义。
chunk_overlap的重要性
- 代码中设置了
chunk_overlap=0, 这可能导致一个完整的句子被切分到两个不同的块中,使得每个块的信息都不完整- 推荐 :设置一个适当的
chunk_overlap(例如 20-50 个字符),让相邻的文本块之间有少量重叠。这有助于保留上下文的连贯性,提高检索的准确性持久化向量数据库
- 当前代码创建的
Chroma数据库是临时的,程序运行结束后数据就会丢失- 推荐 :可以通过指定
persist_directory参数将数据库保存到本地磁盘,下次运行时可以直接加载,无需重新处理文本
pythondocsearch = Chroma.from_texts(texts, embeddings, persist_directory="./chroma_db") # 下次运行时加载 # docsearch = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
LangChain支持的VectorStore如下:

检索器
检索器是一种便于模型查询的存储数据的方式,LangChain约定检索器组件至少有一个方法**`get_relevant_texts`,** 这个方法接收查询字符串,返回一组文档pip install faiss-cpu)
代码如下:
代码非常完整且标准地展示了如何使用LangChain 和 FAISS 构建一个基础的 RAG(检索增强生成) 系统的检索部分
python
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import OllamaEmbeddings
# 加载文档
# 使用 TextLoader 将本地的 pku.txt 文件读取并封装成 LangChain 的 Document 对象列表
loader = TextLoader('./pku.txt')
documents = loader.load()
print(f'documents--》{documents}')
# 文本切块(Chunking)
# 将长文本切分为适合向量化的短文本块。这里使用了 split_documents 方法,
# 它的优点是能够自动保留原文档的 metadata(如 {'source': './pku.txt'})到切分后的每一个小块中,这对于后续溯源非常重要
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
print(f'texts--》{texts}')
print(f'len(texts)--》{len(texts)}')
# 向量化与存入 FAISS
# 调用本地的 Ollama 嵌入模型将文本块转换为向量,并使用 Meta 开源的 FAISS 库在内存中建立向量索引。
# FAISS 的特点是高性能且纯 Python 实现,非常适合本地开发
embeddings = OllamaEmbeddings(model="mxbai-embed-large")
db = FAISS.from_documents(texts, embeddings)
# 创建检索器并查询
# 将向量数据库转换为 LangChain 标准的 Retriever 接口。
# 当输入问题时,它会将问题向量化,并在 FAISS 索引中计算余弦相似度,最终返回最相关的 1 个文档块
retriever = db.as_retriever(search_kwargs={'k': 1})
docs = retriever.get_relevant_documents("发现了啥子事")
print(docs)
# 打印结果:
'''
[Document(metadata={'source': './pku.txt'}, page_content='xxx')]
'''
核心优化与避坑建议
API 版本更新提示
retriever.get_relevant_documents()是 LangChain 的旧版 API,在较新的版本中,该方法已被废弃,官方推荐统一使用invoke()方法新写法:
1docs = retriever.invoke("北京大学什么时候成立的")文本分割器的选择
使用的
CharacterTextSplitter是按固定字符数硬切分的,如果切分点刚好落在一个词或一句话中间,可能会破坏语义推荐 :在实际项目中,强烈建议使用**
RecursiveCharacterTextSplitter(递归字符分割器)**,它会智能地优先按\n\n(段落)、\n(换行)、(空格)等顺序进行切分,能最大程度保持文本的逻辑完整性设置
chunk_overlap(文本重叠)代码中
chunk_overlap=0意味着相邻文本块之间没有交集,这容易导致上下文在边界处被截断推荐 :建议设置一个合理的重叠值(例如
chunk_overlap=20)。这样相邻的文本块会共享 20 个字符,有助于保留连贯的语义,提高检索的准确度
python# 保存索引 db.save_local("faiss_index") # 下次直接加载(无需重新向量化) new_db = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)掌握了这套检索流程后,下一步只需要将检索到的
docs拼接成 Prompt,连同用户的问题一起喂给大语言模型(LLM),一个完整的本地知识库问答系统就诞生了!
LangChain支持的检索器组件如下:

8. LangChain应用场景
- 个人助手
- 聊天机器人
- API交互
- 输入标题问答系统
- Tabular数据查询
- 信息提取
- 文档总结
【上一篇】【AI大模型应用开发】【基础】6.LLM的提示词工程应用-金融行业动态方向评估项目
【下一篇】