大模型开发框架LangChain
如果你想快速上手一个能让大模型应用开发事半功倍的框架,LangChain绝对是首选。它由 Harrison Chase 于2022年10月创建,核心思路是为各种大语言模型(LLMs)提供统一的接口,把相关的组件像搭乐高一样“链接”起来,从而大幅降低开发门槛,让复杂应用的构建变得高效。
一、简述
1 什么是LangChain
LangChain围绕LLMs建立了一个框架,核心理念是为各种LLMs实现通用接口,将LLMs相关的组件“链接”在一起,简化开发难度,方便开发者快速开发复杂的LLMs应用。
LangChain官网提供了完整的入门文档。LangChain在LLM应用的每个生命周期阶段都做了简化:
- :使用开源组件和第三方集成构建应用,通过LangGraph构建支持一流流式和人机交互的状态智能体。
开发
- :借助LangSmith检查、监控和评估应用,方便持续优化和部署。
生产化
- :利用LangGraph平台将应用转变为可用于生产的API和助手。
部署
2 主要组件
- :模型,各种类型的模型和模型集成,比如GPT-4。
Models
- :提示,包括提示管理、提示优化和提示序列化。
Prompts
- :链,一系列对各种组件的调用。
Chains
- :记忆,用来保存和模型交互时的上下文状态。
Memory
- :索引,用来结构化文档,以便和模型交互。
Indexes
- :智能体,决定模型采取哪些行动,执行并观察流程,直到完成为止。
Agents
3 LangChain核心包
- :聊天模型和其他组件的基础抽象。
langchain-core
- (例如 langchain-openai、langchain-anthropic 等):重要的集成被拆分为轻量级的独立包,由LangChain团队和集成方共同维护。
集成包
- :包含链(chains)、智能体(agents)和检索策略,构成应用的认知架构。
langchain
- :由社区维护的第三方集成。
langchain-community
- :一个编排框架,用于将LangChain组件组合成可用于生产的应用,支持持久化、流式处理及其他关键特性。
langgraph
4 环境准备
本课程以LangChain+Qwen进行学习,需要提前安装相关依赖。借助阿里云-百炼平台(需要申请API Key 以及Secret Key)来调用Qwen模型。
二、Models
现在市面上的模型多如牛毛,各种新模型层出不穷。LangChain模型组件提供了与各种模型的集成,并为所有模型提供一个精简的统一接口。
LangChain目前支持三种类型的模型:LLMs、Chat Models(聊天模型)、Embeddings Models(嵌入模型)。
- :大语言模型接收文本字符作为输入,返回的也是文本字符。
LLMs
- :基于LLMs,不同的是它接收聊天消息(一种特定格式的数据)作为输入,返回的也是聊天消息。
聊天模型
- :接收文本作为输入,返回的是浮点数列表。
文本嵌入模型
这三类模型的使用场景、输入和输出各不相同,开发者需要根据项目需求选择相应的模型。
1 LLMs
LLMs的应用场景最为广泛。下面以Qwen为例进行讲解。
模型调用有两种方式:
通过ChatOpenAI调用
from langchain_openai import ChatOpenAI
import os
# 实例化模型
model = ChatOpenAI(
base_url=os.environ.get('base_url','https://dashscope.aliyuncs.com/compatible-mode/v1'),
model='qwen-plus',
openai_api_key=os.environ.get('api_key','sk-XXXXXX'),
max_tokens=1000,
temperature=0
)
# 获取问答结果
result = model.invoke("帮我讲个笑话吧")
print(result.content)
通过Ollama调用
# from langchain_community.llms import Ollama # Langchain 0.x版本使用
from langchain_ollama import OllamaLLM
# 实例化模型
model = OllamaLLM(model="qwen2.5:7b")
# 获取问答结果
result = model.invoke("请给我讲个笑话吧")
print(result)
2 Chat Models
聊天模型接收的聊天消息包含以下几种类型,使用时需要按约定传入合适的值:
- :AI输出的消息,可以是针对问题的回答。
AIMessage
- :人类消息,由人给出的提示信息,比如“实现一个快速排序方法”。
HumanMessage
- :用于指定模型所处的环境和背景,如角色扮演。你可以在这里给出具体指示,比如“作为一个代码专家”,或者“返回json格式”。
SystemMessage
- :Chat消息可以接受任意角色的参数,但大多数情况下应使用上面三种类型。
ChatMessage
LangChain支持大量的聊天模型,可以通过官方文档或LangChain源码查看所有支持的模型。
SystemMessage + HumanMessage + AIMessage
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_ollama import ChatOllama
# 实例化模型
model = ChatOllama(model="qwen2.5:7b")
# 定义提示词
messages = [
SystemMessage(content="现在你是一个著名的诗人"),
HumanMessage(content="给我写一首唐诗")
]
# 获取问答结果
result = model.invoke(messages)
print(result.content)
3 Embeddings Models
嵌入模型的特点是:将字符串作为输入,返回一个浮点数列表。在NLP中,Embedding的作用就是将数据进行文本向量化。
不同的Embedding模型在多语言支持和文本类型上有不同特点:
- :
多语言支持
text-embedding-ada-002:支持多种语言,但对中文等亚洲语言的支持相对较弱。bge-large-zh:对中文有很好的支持。multilingual-e5-large:对多语言都有较好的支持。mxbai-embed-large:也是一种选择。
- :
文本类型适用性
- 代码文本:建议使用专门的代码Embedding模型,如
CodeBERT。 - 通用文本:可以使用
text-embedding-ada-002或bge-large-zh。 - 专业领域文本:建议使用该领域的专门模型。
- 代码文本:建议使用专门的代码Embedding模型,如
可以参考MTEB(大规模文本嵌入基准)排行榜获取最新模型效果。
接下来以一个文本嵌入模型的例子进行说明:
# from langchain_community.embeddings import OllamaEmbeddings # Langchain 0.x版本使用
from langchain_ollama import OllamaEmbeddings
# 初始化Ollama嵌入模型,使用mxbai-embed-large模型,温度设置为0
model = OllamaEmbeddings(model="mxbai-embed-large", temperature=0)
# 对单个查询文本进行嵌入编码
res1 = model.embed_query('这是第一个测试文档')
print(f'result1->{res1}')
print(f'result1的长度->{len(res1)}')
# 对多个文档进行批量嵌入编码
res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档'])
print(res2)
运行结果:

三、Prompts
1 通用prompt
Prompt是指用户输入信息时加入的提示,形式可以是zero-shot或few-shot等,目的是让模型理解更复杂的业务场景,从而更好地解决问题。
提示模板:如果你已经有了一个起作用的提示,你可能想把它作为模板用于解决其他问题。LangChain提供了PromptTemplates组件,帮助更方便地构建提示。
zero-shot提示方式
from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
# 定义模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
prompt = PromptTemplate(input_variables=["lastname"], template=template)
prompt_text = prompt.format(lastname="王")
print(prompt_text)
# result: 我的邻居姓王,他生了个儿子,给他儿子起个名字
result = model.invoke(prompt_text)
print(result)
运行结果:

few-shot提示方式
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
examples = [
{"word": "开心", "antonym": "难过"},
{"word": "高", "antonym": "矮"}
]
example_template = """
单词: {word}
反义词: {antonym}\n
"""
example_prompt = PromptTemplate(input_variables=["word", "antonym"], template=example_template)
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="给出每个单词的反义词",
suffix="单词: {input}\n反义词:",
input_variables=["input"],
example_separator="\n",
)
prompt_text = few_shot_prompt.format(input="粗")
print(model.invoke(prompt_text))
# 细
2 ChatPrompts
适合交互式对话应用,如聊天机器人、智能客服等,这些应用需要处理用户和LLM之间的多轮对话。
直接提问
提示模板就是把常见的提示整理成模板,用户只需要修改模板中特定的词语,就能快速准确地告诉模型自己的需求。看个例子:
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
template_str = "帮我讲个关于{name}笑话吧"
prompt_template = ChatPromptTemplate.from_template(template_str)
prompt = prompt_template.format_messages(name="气球")
print(f'prompt-->{prompt}')
result = model.invoke(prompt)
print(f'result-->{result}')
zero-shot提示方式
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
system_prompt = SystemMessage("你是取名专家。")
human_str = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字。"
human_template = HumanMessagePromptTemplate.from_template(human_str)
chat_template = ChatPromptTemplate.from_messages([system_prompt, human_template])
prompt = chat_template.format_messages(lastname="王")
print(f'prompt-->{prompt}')
result = model.invoke(prompt)
print(f'result-->{result}')
few-shot提示方式
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
prompt_template = ChatPromptTemplate.from_messages([
("system", "给出每个单词的反义词"),
MessagesPlaceholder("history"),
("human", "{question}")
])
history = [("human", "开心"), ("ai", "难过"), ("human", "高"), ("ai", "矮")]
prompt = prompt_template.format_messages(history=history, question="富有")
print(f"prompt-->{prompt}")
result = model.invoke(prompt)
print(f'result-->{result}')
四、Chains
在LangChain中,Chains描述了将LLM与其他组件结合起来完成一个应用程序的过程。针对上一小节的提示模版例子(zero-shot),我们可以用链来连接提示模版组件和模型,从而实现代码的更改。主要使用LCEL方法。
LCEL(Lang Chain Expression Language)是一种声明式的方法,用于轻松组合链条。基本语法规则是使用|符号将不同的组件连接起来,形成一个链式结构。|符号类似于Unix的管道操作符,将一个组件的输出作为下一个组件的输入,实现数据的传递和处理。
上一个组件的输出作为下一个组件的输入,输出和输入的类型必须保持一致,否则不能连接。
from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM
# 定义模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
prompt = PromptTemplate(input_variables=["lastname"], template=template)
# 实例化模型
llm = OllamaLLM(model="qwen2.5:7b")
chain = prompt | llm
# 执行链
print(chain.invoke("王"))
如果你想将第一个模型输出的结果直接作为第二个模型的输入,直接使用管道符:
from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM
# 创建第一条链
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
first_prompt = PromptTemplate(input_variables=["lastname"], template=template)
llm = OllamaLLM(model="qwen2.5:7b")
first_chain = first_prompt | llm
# 创建第二条链
second_prompt = PromptTemplate(
input_variables=["child_name"],
template="邻居的儿子名字叫{child_name},给他起一个小名"
)
second_chain = second_prompt | llm
# 链接两条链
overall_chain = first_chain | second_chain
print(overall_chain)
print('*'*80)
# 执行链,只需要传入第一个参数
catchphrase = overall_chain.invoke("王")
print(catchphrase)
五、output_parsers
LLM的输出是自然语言文本,但在应用开发中,我们经常需要将这些文本转换为结构化的数据格式,如列表、字典或对象。LangChain输出解析器负责获取LLM的输出并将其转换为更合适的格式。
| 解析器名称 | 核心功能 | 输出的 Python 类型 | 工业级应用场景 |
|---|---|---|---|
| StrOutputParser | 默认解析器。将 LLM 的输出直接解析为字符串。 | str | 只需要原始回答时(如问答任务、对话场景) |
| CommaSeparatedListParser | 将 LLM 输出的、用逗号分隔的文本解析为列表。 | list[str] | 列表/枚举型输出 |
| JsonOutputParser | 极其常用。将 LLM 输出的 JSON 字符串解析为 Python 字典。 | dict | 结构化 JSON 输出 |
| PydanticOutputParser | 极其常用。将 LLM 输出解析为预先定义的 Pydantic 对象,提供类型安全和数据验证。 | 自定义的 pydantic.BaseModel 对象 | 输出需要严格结构化(JSON-like)数据时 |
| DatetimeOutputParser | 从文本中智能地解析出日期和时间信息。 | datetime.datetime | 需要时间格式时 |
1 字符串解析器
StrOutputParser,最简单的解析器,用于提取模型返回的原始文本:
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
prompt = ChatPromptTemplate.from_template("解释{topic}是什么?回答控制20字以内")
chain1 = prompt | model
result1 = chain1.invoke({"topic": "ai"})
print(f"result1-->{result1}")
parser = StrOutputParser()
chain2 = prompt | model | parser
result2 = chain2.invoke({"topic": "ai"})
print(f"result2-->{result2}")
2 列表解析器
CommaSeparatedListOutputParser,将逗号分隔的文本转换为Python列表:
from langchain_core.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
parser = CommaSeparatedListOutputParser()
format_instructions = parser.get_format_instructions()
prompt = ChatPromptTemplate.from_template("用中文列出{topic}的五个最重要特点。\n{format_instructions}")
chain = prompt | model | parser
result = chain.invoke({"topic": "大模型", "format_instructions": format_instructions})
print(result)
3 JSON解析器
JsonOutputParser,将JSON格式文本转换为Python字典或列表:
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
json_parser = JsonOutputParser()
json_format_instructions = json_parser.get_format_instructions()
json_prompt = ChatPromptTemplate.from_template(
"生成一个包含{person}基本信息的JSON。应包括姓名、职业、年龄和技能列表, 不要包含任何注释或额外说明。\n{format_instructions}"
)
json_chain = json_prompt | model | json_parser
result = json_chain.invoke({"person": "雷军", "format_instructions": json_format_instructions})
print(result)
4 Pydantic解析器
PydanticOutputParser,使用Pydantic模型定义输出结构:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
class Movie(BaseModel):
title: str = Field(description="电影标题")
director: str = Field(description="导演姓名")
year: int = Field(description="上映年份")
genre: List[str] = Field(description="电影类型")
rating: float = Field(description="评分(1-10)")
pydantic_parser = PydanticOutputParser(pydantic_object=Movie)
format_instructions = pydantic_parser.get_format_instructions()
pydantic_prompt = ChatPromptTemplate.from_template("生成一部{genre}电影的信息。\n{format_instructions}")
pydantic_chain = pydantic_prompt | model | pydantic_parser
movie_data = pydantic_chain.invoke({"genre": "科幻", "format_instructions": format_instructions})
print(movie_data)
5 自定义解析器
创建自定义输出解析器:
from langchain_core.output_parsers import BaseOutputParser
from typing import Dict, Any
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM
model = OllamaLLM(model="qwen2.5:7b")
class CustomKeyValueParser(BaseOutputParser[Dict[str, Any]]):
"""解析形如'key: value'的文本"""
def parse(self, text: str) -> Dict[str, Any]:
"""从文本中解析键值对"""
result = {}
lines = text.strip().split('\n')
for line in lines:
if ':' in line:
key, value = line.split(':', 1)
result[key.strip()] = value.strip()
return result
def get_format_instructions(self) -> str:
"""提供格式指导给模型"""
return """请以'键: 值'的格式返回信息,每行一个键值对。例如:
名称: 爱因斯坦
职业: 物理学家
贡献: 相对论"""
custom_parser = CustomKeyValueParser()
custom_prompt = ChatPromptTemplate.from_template("提供关于{person}的基本信息。\n{format_instructions}")
custom_chain = custom_prompt | model | custom_parser
result = custom_chain.invoke({"person": "屠呦呦", "format_instructions": custom_parser.get_format_instructions()})
print(result)
六、Memory
大模型本身不具备上下文的概念,它并不保存上次交互的内容。ChatGPT之所以能够和人正常对话,是因为它进行了一层封装,将历史记录回传给了模型。因此LangChain也提供了Memory组件。Memory分为两种类型:短期记忆和长期记忆。短期记忆一般指单一会话时传递数据,长期记忆则是处理多个会话时获取和更新信息。
使用 ChatMessageHistory 手动添加上下文
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import messages_to_dict, messages_from_dict
import json
# 1.创建一个ChatMessageHistory对象,用来存储对话信息
history = ChatMessageHistory()
history.add_user_message("在吗?")
history.add_ai_message("在")
print(f'history.messages-->{history.messages}')
# 2.可以将history.messages中的信息保存到字典中,然后保存到数据库或者文件中
dicts = messages_to_dict(history.messages)
print(f'dicts-->{dicts}')
# 2.2 保存到文件
with open('history.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dicts, indent=2, ensure_ascii=False))
# 3.从文件中读取并转换回消息
messages = json.load(open('history.json', 'r', encoding='utf-8'))
chat_messages = messages_from_dict(messages)
print(f'chat_messages-->{chat_messages}')
LangChain v1.0版本对Memory组件进行了深度优化与工程化重构,使其不仅支持多轮对话上下文管理,更成为构建生产级智能体(Agent)不可或缺的核心能力之一。在LangChain从“实验性框架”迈向“企业级平台”的关键转型中,Memory模块被赋予了更清晰的职责边界、更灵活的策略机制以及更强的可扩展性,从而支撑复杂任务场景下的长期记忆、状态追踪与个性化交互。
1 短期记忆(Short-term Memory)
短期记忆的本质是线程级状态管理。在LangGraph中:
(1)状态(State)
通常是一个包含 messages 字段的字典或 Pydantic 模型(如 MessagesState 或自定义 CustomState),用于存储当前会话的所有消息、中间变量、工具调用结果等。
(2)检查点器(Checkpointer)
负责将状态序列化并持久化到内存、SQLite、PostgreSQL 等后端。每次状态变更(如新增一条消息)都会触发一次检查点保存。
(3)会话ID(thread_id)
作为会话的唯一标识符,确保不同用户或不同对话之间的状态完全隔离。即使多个用户并发交互,也不会发生记忆混淆。
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySa ver
from langchain.messages import HumanMessage
from langchain_ollama import OllamaLLM
import time
model = OllamaLLM(model="qwen2.5:7b")
checkpointer = InMemorySa ver()
timestamp = time.time()
config = {"configurable": {"thread_id": f"{int(timestamp)}"}}
agent = create_agent(
model=model,
tools=[],
checkpointer=checkpointer,
system_prompt="你是一个翻译官,擅长中英互译。"
)
input_1 = {"messages": [HumanMessage("你好,我叫小呆。")]}
response_a = agent.invoke(input=input_1, config=config)
input_2 = {"messages": [HumanMessage("你好,我叫什么?")]}
config_2 = {"configurable": {"thread_id": f"{int(time.time())}"}}
response_b = agent.invoke(input=input_2, config=config_2)
response_c = agent.invoke(input=input_2, config=config)
print("Response A (第一次对话):")
print(response_a)
print("\nResponse B (新线程,无记忆):")
print(response_b)
print("\nResponse C (回到原线程,有记忆):")
print(response_c)
代码运行逻辑:
- :这是LangGraph区别于传统简单API调用的关键。它允许Agent在多次invoke调用之间保存状态。
checkpointer (记忆核心)
- :你可以把thread_id想象成数据库中的主键。Response A向ID为100的记录里写入了名字;Response B向ID为200的新记录提问,因为200是空的,所以Agent不知道名字;Response C又回到ID为100的记录提问,Agent读取了历史记录,所以知道名字。
thread_id (记忆索引)
- :虽然输入是在对话,但因为设定了“你是一个翻译官”,Agent可能会试图在回答的同时进行翻译,或者在回复格式上符合翻译官的身份。
System Prompt
2 长期记忆
对于需要长期运行和可靠记忆的应用,推荐使用数据库进行持久化。详见后面阶段LangGraph部分。
七、Indexes
Indexes组件的目的是让LangChain具备处理文档处理的能力,包括:文档加载、检索等。注意,这里的文档不局限于txt、pdf等文本类内容,还涵盖email、区块链、视频等内容。
Indexes组件主要包含类型:
- 文档加载器
- 文本分割器
- VectorStores
- 检索器
1 文档加载器
文档加载器主要基于Unstructured 包,它是把各种类型的文件转换成文本的Python包。使用起来很简单,只需要引入相应的loader工具。
LangChain支持的文档加载器(部分):

示例代码:
from langchain_unstructured import UnstructuredLoader
loader = UnstructuredLoader('./data/衣服属性.txt', encoding='utf8')
docs = loader.load()
print(f'docs-->{docs}')
print(f'len-->{len(docs)}')
print(f'第一行数据-->{docs[0].page_content}')
print('*' * 100)
from langchain_community.document_loaders import TextLoader
loader = TextLoader('./data/衣服属性.txt', encoding='utf8')
docs = loader.load()
print(f'docs-->{docs}')
print(f'len-->{len(docs)}')
print('第一行数据-->{}'.format(docs[0].page_content.split('\n')[0]))
2 文档分割器
由于模型对输入的字符长度有限制,我们在碰到很长的文本时,需要把文本分割成多个小的文本片段。
文本分割最简单的方式是按照字符长度进行分割,但这样会带来很多问题,比如如果文本是一段代码,一个函数被分割到两段之后就成了没有意义的字符,所以整体的原则是把语义相关的文本片段放在一起。
LangChain中最基本的文本分割器是CharacterTextSplitter,它按照指定的分隔符(默认“\n\n”)进行分割,并且考虑文本片段的最大长度。看个例子:
from langchain_core.documents import Document
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter(separator=" ", chunk_size=5, chunk_overlap=1)
result1 = text_splitter.split_text("a b c d e f")
print(f'result1--->{result1}')
result2 = text_splitter.create_documents(["a b c d e f", "e f g h"])
print(f'result2--->{result2}')
result3 = text_splitter.split_documents([Document(page_content="a b c d e f", metadata={"id": "1"})])
print(f'result3--->{result3}')
除了CharacterTextSplitter,LangChain还支持其他文档分割器(部分):
| 分割器名称 | 功能描述 | 类型 | 工业场景应用 |
|---|---|---|---|
| CharacterTextSplitter | 简单按指定分隔符(如换行、逗号)直接分割。 | 基础字符解析 | 简单字符串或CSV数据处理,如传感器数据日志。 |
| RecursiveCharacterTextSplitter | 递归按字符分割,先尝试自然边界(如段落、句子),太大则继续细分。 | 通用字符解析 | 通用文本处理,如日志、报告、PDF文档分割,便于RAG检索。 |
| TokenTextSplitter | 按 token(词元)分割,支持LLM token计数。 | Token 基于解析 | LLM输入优化,如处理API响应或长查询,控制token限制。 |
| SentenceTextSplitter | 按句子边界分割,使用NLP识别句子(包括标点)。 | 语义解析 | 自然语言文本,如文章或对话分析,保持句子完整。 |
| SpacyTextSplitter | 使用SpaCy NLP库按句子或实体分割(需安装SpaCy)。 | 语义解析 | 高级NLP场景,如实体提取或生物医学文本。 |
| NLTKTextSplitter | 使用NLTK库按句子或词分割(需安装NLTK)。 | 语义解析 | 文本研究或分析,如时间序列数据描述。 |
| MarkdownHeaderTextSplitter | 按Markdown结构(如标题、列表)智能分割。 | 结构化解析 | Markdown文档分割,保留语义结构,用于知识库构建。 |
| HTMLSplitter | 按HTML标签(如 、 )分割网页内容。 | 结构化解析 | 网页数据爬取,如在线技术文档或新闻提取。 |
| LatexTextSplitter | 按LaTeX结构(如章节、公式)分割。 | 结构化解析 | 学术论文或数学文档处理。 |
| PythonCodeTextSplitter | 按Python代码结构(如函数、类)分割。 | 代码解析 | 源代码文件分析,如脚本调试或代码库管理。 |
下面就几个重要的分割器进行讲解。
递归字符文本分割器(RecursiveCharacterTextSplitter)
语义文档分割器(SemanticChunker)
MarkdownHeaderTextSplitter(Markdown文档切割器)
其他拓展知识可以在实际使用中参考更多资料。
3 VectorStores
VectorStores是一种特殊类型的数据库,它的作用是存储由嵌入创建的向量,提供相似查询等功能。
LangChain支持的VectorStore种类丰富,常见的如下:

from langchain_text_splitters import CharacterTextSplitter
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_ollama import OllamaEmbeddings
# 1.加载文档
loader = TextLoader('./data/pku.txt', encoding='utf-8')
docs = loader.load()
# 2.将文档进行分块
text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=200, chunk_overlap=30)
split_docs = text_splitter.split_documents(docs)
print(f'split_docs-->{split_docs}')
# 3.将分割后的文档存储到向量数据库中
embedding = OllamaEmbeddings(model="mxbai-embed-large")
chromadaDB = Chroma.from_documents(documents=split_docs, embedding=embedding, persist_directory='./chroma_db')
# 假如你的向量数据库已经存在,那么可以直接加载
# chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)
# 4.使用向量数据库进行查询
query = "1937年北京大学发生了什么?"
result = chromadaDB.similarity_search(query, k=2)
print(f'result-->{result}')
4 检索器
4.1 LangChain的检索器定义
检索器是 LangChain 中负责信息检索的模块,通常与索引模块(如向量存储、嵌入模型)结合使用。它的核心功能是:
- :接收用户查询(通常是文本)。
输入
- :根据查询从数据源中检索相关内容。
处理
- :返回一组相关文档或文本片段(通常是 Document 对象列表)。
输出
检索器在以下场景中扮演关键角色:
- 问答系统:从文档或知识库中检索答案的上下文。
- 语义搜索:根据查询的语义返回相关结果。
- 上下文增强:为语言模型提供外部知识,解决其知识局限。
4.2 检索器的工作原理
检索器通常与向量存储配合,通过嵌入模型将查询和文档转为向量,基于相似性进行检索。工作流程可以分为以下步骤:
- :将用户查询通过嵌入模型转为向量表示。
查询嵌入
- :在向量存储中查找与查询向量最相似的文档向量。
相似性搜索
- :返回匹配的文档(包含内容、元数据等)。
文档返回
- :对检索结果进行排序、过滤或重新排名。
后处理(可选)
检索器的核心依赖:
- :将文本转为向量(如 OpenAIEmbeddings, HuggingFaceEmbeddings)。
嵌入模型
- :存储文档向量(如 Chroma、FAISS、Pinecone)。
向量存储
- :如余弦相似度、欧几里得距离。
相似性度量
4.3 检索器类型
LangChain支持很多检索器,部分如下:

此处我们讲解VectorStoreRetriever。
在 LangChain 中,as_retriever() 方法的 search_type 参数决定了向量检索的具体算法和行为。
retriever = vector_store.as_retriever(
search_type="similarity", # 可选 "similarity"|"mmr"|"similarity_score_threshold"
search_kwargs={
"k": 5,
"score_threshold": 0.7, # 仅当search_type="similarity_score_threshold"时有效
"filter": {"source": "重要文档.pdf"}, # 元数据过滤
"lambda_mult": 0.25 # 仅MMR搜索有效:接近0强调相关性,接近1强调差异性
}
)
以下是三种搜索类型的对比:

示例代码:
from langchain_chroma import Chroma
from langchain_ollama import OllamaEmbeddings
embedding = OllamaEmbeddings(model="mxbai-embed-large")
chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)
query = "1937年北京大学发生了什么?"
retriever = chromadaDB.as_retriever(search_kwargs={"k":2})
result = retriever.invoke(query)
print(f'result-->{result}')
4.4 拓展
其他几种常用的检索器介绍如下。
TFIDFRetriever
BM25Retriever
MultiQueryRetriever
EnsembleRetriever
ContextualCompressionRetriever
Custom Retriever
八、Agents
1 Agent 概念
Agent(智能体)是一种能够感知环境、进行决策和执行动作的智能实体。不同于传统的人工智能,Agent具备通过主动思考、调用工具去逐步完成给定目标的能力。
为什么要调用工具?因为大模型虽然非常强大,但也存在局限性,比如不能回答实时信息、处理数学逻辑问题仍然很初级等。因此,可以借助第三方工具来辅助大模型的应用。
从大模型的角度来看,Agent其实就是基于大模型的语义理解和推理能力,让大模型拥有解决复杂问题时的任务规划能力,并调用外部工具来执行各种任务,利用向量数据库保留“记忆”的一个智能体。
工作流程概述:
- 用户提出任务。
- Agent 启动:将用户输入与预设的“提示词模板”结合,并结合当前的“上下文”和“变量”,形成一个完整的输入发送给大模型。
- 大模型思考与决策(循环):
- 大模型接收输入后,根据内置的逻辑和提示词的指导,进行“思考”。
- 判断完成当前任务是否需要继续使用工具来获取更多信息/执行操作,还是已经可以直接生成最终答案。
- 如果需要工具:大模型会根据任务需求和对工具的描述,选择合适的工具,并生成执行该工具所需的输入参数。
- 工具执行:选定的工具被调用,执行其功能。
- 结果反馈:工具执行的结果返回给Agent,并用来更新“上下文”和“变量”。
- 循环:Agent将更新后的“上下文”、“变量”以及工具执行结果再次反馈给大模型,大模型继续新一轮的“思考-行动”循环,直到任务完成。
- 如果直接回答:当大模型判断任务已完成,或无需额外工具即可回答时,它会生成最终的答案。
- 用户输出:最终答案被呈现给用户。
2 Agent关键组成部分

- :Agent需要提前将一项复杂任务拆解为多个更小、更易于处理的子任务,从而实现对复杂任务的高效处理。
任务规划(Planning)
- :聊天上下文,长期保留和回忆信息。
长短期记忆(Memory)
- :根据拆分好的子任务,调用外部提供好的专业API解决专业问题,完成一个个具体的子任务,并把处理结果返回给大模型。
工具&执行(Tools&Action)
3 LangChain实现Agent
LangChain提供了不同类型的智能体(主要罗列以下三种):
Zero-shot ReAct Description
- 基于 ReAct 框架(推理 + 行动),仅依赖工具的来决定调用哪个工具。
描述
- 特点:无需额外示例(zero-shot),但,每次推理都独立进行。
不具备记忆能力
- 使用场景:简单任务,工具选择完全靠工具描述即可。
- 基于 ReAct 框架(推理 + 行动),仅依赖工具的
Structured Chat Zero-shot ReAct Description
- 同样基于 ReAct 框架,但可以处理,即支持带多个参数的工具(类似函数调用)。
结构化输入
- 特点:不仅能像第一种智能体那样根据描述选择工具,还能正确组织并传递复杂参数。
- 使用场景:调用接口类工具、需要多参数输入的任务。
- 同样基于 ReAct 框架,但可以处理
Conversational ReAct Description
- 在 ReAct 框架基础上,增强了。
对话记忆能力
- 特点:能根据上下文对话历史来做出工具选择和回应,更适合持续性对话场景。
- 使用场景:多轮对话,用户可能引用之前的内容或需要长期上下文跟踪。
- 在 ReAct 框架基础上,增强了
LangChain中集成了很多工具,可以通过下面的方式查询:
from langchain_community.agent_toolkits.load_tools import get_all_tool_names
results = get_all_tool_names()
print(results)
运行结果:
['sleep', 'wolfram-alpha', 'google-search', 'google-search-results-json', 'searx-search-results-json', 'bing-search', 'metaphor-search', 'ddg-search', 'google-books', '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']
接下来,通过一个示例来学习Agent的基本使用。
- 问题1:计算一下300的25%是多少?
- 问题2:请帮我介绍一下故宫
示例代码:
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySa ver
from langchain.agents import create_agent
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain_openai import ChatOpenAI
import os
model = ChatOpenAI(
base_url=os.environ.get('base_url','https://dashscope.aliyuncs.com/compatible-mode/v1'),
model='qwen-plus',
openai_api_key=os.environ.get('api_key','sk-XXXXXXXX'),
max_tokens=1000,
temperature=0
)
memory = MemorySa ver()
tools = load_tools(['wikipedia', 'llm-math'], llm=model)
agent_executor = create_agent(model, tools, checkpointer=memory)
config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
{"messages": [HumanMessage(content="计算一下300的25%是多少?")]}, config
):
print(chunk)
print("----")
九、LangChain使用场景
- 个人助手
- 基于文档的问答系统
- 聊天机器人
- Tabular数据查询
- API交互
- 信息提取
- 文档总结