一、什么是LangChain

        LangChain由Harrison Chase于2022年10月创建,是一个基于大语言模型(LLMs)构建的开发框架。LLMs通过机器学习算法处理海量数据来实现自然语言的理解与分析,其中GPT3.5、GPT4代表了当前最先进的技术水平,国内如百度的文心一言和阿里的通义千问也属于LLMs范畴。

        该框架的核心价值在于为各类LLMs提供统一接口,通过"链式"整合相关组件来降低开发复杂度,帮助开发者快速构建复杂的LLMs应用。目前提供Python和Node.js两种编程语言的实现版本。

二、LangChain主要组件

一个LangChain的应用是需要多个组件共同实现的,LangChain主要支持6种组件:

• Models:模型,各种类型的模型和模型集成,比如GPT-4
• Prompts:提示,包括提示管理、提示优化和提示序列化
• Memory:记忆,用来保存和模型交互时的上下文状态
• Indexes:索引,用来结构化文档,以便和模型交互
• Chains:链,一系列对各种组件的调用
• Agents:代理,决定模型采取哪些行动,执行并且观察流程,直到完成为止

1 Models

现在市面上的模型多如牛毛,各种各样的模型不断出现,LangChain模型组件提供了与各种模型的集成,并为所有模型提供一个精简的统一接口。
LangChain目前支持三种类型的模型:LLMs、Chat Models(聊天模型)、Embeddings Models(嵌入模型).
• LLMs: 大语言模型接收文本字符作为输入,返回的也是文本字符.
• 聊天模型: 基于LLMs, 不同的是它接收聊天消息(一种特定格式的数据)作为输入,返回的也是聊天消息.
• 文本嵌入模型: 文本嵌入模型接收文本作为输入, 返回的是浮点数列表.
LangChain支持的三类模型,它们的使用场景不同,输入和输出不同,开发者需要根据项目需要选择相应。

1.1 LLMs (大语言模型)

接下来我们借助Ollama工具进行模型的使用:

 第一步:安装必备的工具包

安装langchain库: pip install langchain
安装langchain_community库: pip install langchain_community

第二步:简单的代码实现

from langchain_community.llms import Ollama
model = Ollama(model="qwen2:1.5b", temperature=0)
result = model.invoke("请给我讲个鬼故事")
print(result)

1.2 Chat Models (聊天模型)

聊天消息包含下面几种类型,使用时需要按照约定传入合适的值

AIMessage: 就是 AI 输出的消息,可以是针对问题的回答.
HumanMessage: 人类消息就是用户信息,由人给出的信息发送给LLMs的提示信息,比如“实现一个快速排序方法”.
SystemMessage: 可以用于指定模型具体所处的环境和背景,如角色扮演等。你可以在这里给出具体的指示,比如“作为一个代码专家”,或者“返回json格式”.
ChatMessage: Chat 消息可以接受任意角色的参数,但是在大多数时间,我们应该使用上面的三种类型.

LangChain支持的常见聊天模型有:

模型 描述
ChatOpenAI OpenAI聊天模型
AzureChatOpenAI Azure提供的OpenAI聊天模型
PromptLayerChatOpenAI 基于OpenAI的提示模版平台

简单的代码如下:

from langchain_core.messages import HumanMessage, SystemMessage
from langchain_community.chat_models import ChatOllama
model = ChatOllama(model="qwen2.5:7b", temperature=0)
messages = [
        SystemMessage(content="现在你是一个著名的歌手"),
        HumanMessage(content="给我写一首歌词")
]
res = model(messages)
print(res)
print(res.content)

1.3 提示模板

在之前的示例中,模型默认输出纯文本结果。如需获取特定数据格式(如JSON),可以通过提示模板来实现。

提示模板是将常见指令整理成标准格式,用户只需替换模板中的关键字段,就能快速明确地向模型传达需求。举个例子来说明:

from langchain_community.chat_models import ChatOllama
from langchain.prompts import ChatPromptTemplate


# 创建原始模板
template_str = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
# """


# 根据原始模板创建LangChain提示模板
promp_emplate = ChatPromptTemplate.from_template(template_str)
prompt = promp_emplate.format_messages(price='50', flower_name=["玫瑰"], )
print('prompt-->', prompt)
# prompt--> [HumanMessage(content="您是一位专业的鲜花店文案撰写员。\n\n对于售价为 50 元的 ['玫瑰'] ,您能提供一个吸引人的简短描述吗?\n# ", additional_kwargs={}, response_metadata={})]

# 实例化模型
model = ChatOllama(model="qwen2.5:7b", temperature=0)

# 打印结果
result = model.invoke(prompt)
print(result.content)

1.4 Embeddings Models(嵌入模型)

Embeddings Models特点:将字符串作为输入,返回一个浮动数的列表。在NLP中,Embedding的作用就是将数据进行文本向量化。

Embeddings Models可以为文本创建向量映射,这样就能在向量空间里去考虑文本,执行诸如语义搜索之类的操作,比如说寻找相似的文本片段。

接下来我们以一个qwen文本嵌入模型的例子进行说明:

from langchain_community.embeddings import OllamaEmbeddings

model = OllamaEmbeddings(model="mxbai-embed-large", temperature=0)
res1 = model.embed_query('这是第一个测试文档')
print(res1)

res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档'])
print(res2)

上述代码中,我们分别使用了两种方法来进行文本的向量表示,他们最大不同在于:embed_query()接收一个字符串的输入,而embed_documents可以接收一组字符串。

LangChain集成的文本嵌入模型有:

• AzureOpenAI、Baidu Qianfan、Hugging Face Hub、OpenAI、Llama-cpp、SentenceTransformers

2 Prompts

Prompt是指当用户输入信息给模型时加入的提示,这个提示的形式可以是zero-shot或者few-shot等方式,目的是让模型理解更为复杂的业务场景以便更好的解决问题。

提示模板:如果你有了一个起作用的提示,你可能想把它作为一个模板用于解决其他问题,LangChain就提供了PromptTemplates组件,它可以帮助你更方便的构建提示。

zero-shot提示方式:

from langchain_core.prompts import PromptTemplate
from langchain_community.chat_models import ChatOllama

# 假设后续代码使用了 PromptTemplate
# 这里是示例用法
template = "你是一个专业的翻译家,将下面的文本翻译成{language}: {text}"
prompt_template = PromptTemplate(
    input_variables=["language", "text"],
    template=template
)

model = ChatOllama(model="qwen3:0.6b", temperature=0)
result = model.invoke(prompt_template.format(language="English", text="这是一个测试"))
print(result.content)

few-shot提示方式:

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_community.llms import Ollama
model = Ollama(model="qwen3:0.6b")

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="粗")
result = model.invoke(prompt_text)
print(result)
print('*'*80)

3 Chains(链)

在LangChain中,Chains描述了将LLM与其他组件结合起来完成一个应用程序的过程.

对上一小节的提示模版例子,zero-shot里面,我们可以用链来连接提示模版组件和模型,进而可以实现代码的更改:

from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain

# 定义模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"

prompt = PromptTemplate(
    input_variables=["lastname"],
    template=template,
)
llm = Ollama(model="qwen2.5:7b")

chain = LLMChain(llm = llm,
                  prompt = prompt)
# 执行链
print(chain.run("王"))

注意:在较新版本的 Langchain 中,LLMChain 已经被弃用,推荐使用更现代的方法来构建链式操作。

如果你想将第一个模型输出的结果,直接作为第二个模型的输入,还可以使用LangChain的SimpleSequentialChain, 代码如下:

from langchain import PromptTemplate
from langchain_community.llms import Ollama
from langchain.chains import LLMChain, 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)

# 创建第二条链
second_prompt = PromptTemplate(
    input_variables=["child_name"],
    template="邻居的儿子名字叫{child_name},给他起一个小名",
)

second_chain = LLMChain(llm=llm, prompt=second_prompt)


# 链接两条链
overall_chain = SimpleSequentialChain(chains=[first_chain, second_chain], verbose=True)

print(overall_chain)
print('*'*80)
# 执行链,只需要传入第一个参数
catchphrase = overall_chain.run("王")
print(catchphrase)

4 Agents (代理)

Agents 也就是代理,它的核心思想是利用一个语言模型来选择一系列要执行的动作。

在 LangChain 中 Agents 的作用就是根据用户的需求,来访问一些第三方工具(比如:搜索引擎或者数据库),进而来解决相关需求问题

为什么要借助第三方库?

• 因为大模型虽然非常强大,但是也具备一定的局限性,比如不能回答实时信息、处理数学逻辑问题仍然非常的初级等等。因此,可以借助第三方工具来辅助大模型的应用

几个重要的概念:

  • Agent代理:
  • 制定计划和思考下一步需要采取的行动。
  • 负责控制整段代码的逻辑和执行,代理暴露了一个接口,用来接收用户输入。
  • LangChain 提供了不同类型的代理(以其中三种举例):
    • zero-shot-react-description: 利用 ReAct 框架根据工具的描述来决定使用哪个工具,可以使用多个工具,但需要为每个工具提供描述信息。工具的选择单纯依靠工具的描述信息。
    • structured-chat-zero-shot-react-description:相较于单一字符串作为输入的代理,该类型的代理可以通过工具的参数schema创建结构化的动作输入。
    • conversational-react-description:这类代理专为对话场景设计,使用具有对话性的提示词,利用 ReAct 框架选择工具,并利用记忆功能来保存对话历史。
  • Tool工具:
  • 解决问题的工具
  • 第三方服务的集成,例如计算、网络(谷歌、bing)、代码执行等等

现在我们实现一个使用代理的例子:假设我们想 """解以下方程:3x + 4(x + 2) - 84 = y; 其中x为3,请问y是多少?"""?我们可以使用代理工具,让Agents选择执行。代码如下:

import  os
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain_community.llms import Ollama

#  实例化大模型
llm = Ollama(model="qwen2.5:7b")

#  设置工具
# "serpapi"实时联网搜素工具、"math": 数学计算的工具
# tools = load_tools(["serpapi", "llm-math"], llm=llm)
tools = load_tools(["llm-math"], llm=llm)

# 实例化代理Agent:返回 AgentExecutor 类型的实例
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

print('agent', agent)
# 准备提示词
from langchain_core.prompts import PromptTemplate
prompt_template = """解以下方程:3x + 4(x + 2) - 84 = y; 其中x为3,请问y是多少?"""
prompt = PromptTemplate.from_template(prompt_template)
print('prompt-->', prompt)

# 代理Agent工作
result = agent.run(prompt)
print(result)

注意,如果运行这个示例你要使用serpapi, 需要申请serpapi token,并且设置到环境变量SERPAPI_API_KEY ,然后安装依赖包google-search-results

5 Memory

大模型本身不具备上下文的概念,它并不保存上次交互的内容,ChatGPT之所以能够和人正常沟通对话,因为它进行了一层封装,将历史记录回传给了模型。

因此 LangChain 也提供了Memory组件, Memory分为两种类型:短期记忆和长期记忆。短期记忆一般指单一会话时传递数据,长期记忆则是处理多个会话时获取和更新信息。

目前的Memory组件只需要考虑ChatMessageHistory。举例分析:

from langchain.memory import ChatMessageHistory

history = ChatMessageHistory()
history.add_user_message("在吗?")
history.add_ai_message("有什么事?")

print(history.messages)

如果要像chatGPT一样,长期保存历史消息,,可以使用messages_to_dict 方法

from langchain_classic.memory import ChatMessageHistory
from langchain_classic.schema import messages_from_dict, messages_to_dict


history = ChatMessageHistory()
history.add_user_message("hi!")
history.add_ai_message("whats up?")

dicts = messages_to_dict(history.messages)

print(dicts)

'''
[{'type': 'human', 'data': {'content': 'hi!', 'additional_kwargs': {}, 'type': 'human', 'example': False}}, {'type': 'ai', 'data': {'content': 'whats up?', 'additional_kwargs': {}, 'type': 'ai', 'example': False}}]
'''


# 读取历史消息
new_messages = messages_from_dict(dicts)

print(new_messages)
#[HumanMessage(content='hi!'), AIMessage(content='whats up?')]

6 Indexes (索引)

Indexes组件旨在为LangChain提供文档处理功能,包括文档加载和检索等操作。值得注意的是,这里所指的文档不仅包含txt、pdf等文本格式,还涵盖email、区块链数据以及视频等多种内容类型。

Indexes组件主要包含类型:

• 文档加载器
• 文本分割器
• VectorStores
• 检索器

6.1 文档加载器

文档加载器主要基于Unstructured 包,Unstructured 是一个python包,可以把各种类型的文件转换成文本。

文档加载器使用起来很简单,只需要引入相应的loader工具:

from langchain_classic.document_loaders import UnstructuredFileLoader
from langchain_classic.document_loaders import TextLoader

loader = UnstructuredFileLoader('1.txt', encoding='utf8')
docs = loader.load()
print(docs)
print(len(docs))
first_01 = docs[0].page_content[:4]
print(first_01)
print('*'*80)

loader = TextLoader('1.txt', encoding='utf8')
docs = loader.load()
print(docs)
print(len(docs))
first_01 = docs[0].page_content[:4]
print(first_01)

# 打印结果:
'''
[Document(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%', metadata={'source': '衣服属性.txt'})]
1
身高:1
********************************************************************************
[Document(page_content='身高:160-170cm, 体重:90-115斤,建议尺码M。\n\n身高:165-175cm, 体重:115-135斤,建议尺码L。\n\n身高:170-178cm, 体重:130-150斤,建议尺码XL。\n\n身高:175-182cm, 体重:145-165斤,建议尺码2XL。\n\n身高:178-185cm, 体重:160-180斤,建议尺码3XL。\n\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\n适用场景:其他休闲\n\n衣长:常规款\n\n版型:宽松型\n\n款式细节:假两件\n\n工艺处理:免烫处理\n\n适用对象:青年\n\n面料功能:保暖\n\n穿搭方式:外穿\n\n销售渠道类型:纯电商(只在线上销售)\n\n材质成分:棉100%', metadata={'source': '衣服属性.txt'})]
1
身高:1
'''

LangChain支持的文档加载器 (部分):

CSV CSV问价
JSON Files 加载JSON文件
Jupyter Notebook 加载notebook文件
Markdown 加载markdown文件
Microsoft PowerPoint 加载ppt文件
PDF 加载pdf文件
Images 加载图片
File Directory 加载目录下所有文件
HTML 网页

6.2 文档分割器

由于模型对输入的字符长度有限制,我们在碰到很长的文本时,需要把文本分割成多个小的文本片段。
文本分割最简单的方式是按照字符长度进行分割,但是这会带来很多问题,比如说如果文本是一段代码,一个函数被分割到两段之后就成了没有意义的字符,所以整体的原则是把语义相关的文本片段放在一起。
LangChain中最基本的文本分割器是CharacterTextSplitter ,它按照指定的分隔符(默认“\n\n”)进行分割,并且考虑文本片段的最大长度。我们看个例子:

from langchain_classic.text_splitter import CharacterTextSplitter


text_splitter = CharacterTextSplitter(
    separator = " ", # 空格分割,但是空格也属于字符
    chunk_size = 5,
    chunk_overlap  = 0,
)


# 一句分割
a = text_splitter.split_text("a b c d e f")
print(a)
# ['a b c', 'd e f']

# 多句话分割(文档分割)
texts = text_splitter.create_documents(["a b c d e f", "e f g h"], )
print(texts)
# [Document(page_content='a b c'), Document(page_content='d e f'), Document(page_content='e f g'), Document(page_content='h')]

除了CharacterTextSplitter分割器,LangChain还支持其他文档分割器 (部分):

文档分割器 描述
LatexTextSplitter 沿着Latex标题、标题、枚举等分割文本。
MarkdownTextSplitter 沿着Markdown的标题、代码块或水平规则来分割文本。
TokenTextSplitter 根据openAI的token数进行分割
PythonCodeTextSplitter 沿着Python类和方法的定义分割文本。

6.3 VectorStores

VectorStores是一种特殊类型的数据库,它的作用是存储由嵌入创建的向量,提供相似查询等功

能。我们使用其中一个Chroma 组件pip install chromadb作为例子:

from langchain_community.embeddings import OllamaEmbeddings
from langchain_classic.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:
    state_of_the_union = f.read()

text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union)
print(texts)

embeddings = OllamaEmbeddings(model="mxbai-embed-large")

docsearch = Chroma.from_texts(texts, embeddings)

query = "1937年北京大学发生了什么?"
docs = docsearch.similarity_search(query)
print(docs)

LangChain支持的VectorStore如下:

VectorStore 描述
Chroma 一个开源嵌入式数据库
ElasticSearch ElasticSearch
Milvus 用于存储、索引和管理由深度神经网络和其他机器学习(ML)模型产生的大量嵌入向量的数据库
Redis 基于redis的检索器
FAISS Facebook AI相似性搜索服务
Pinecone 一个具有广泛功能的向量数据库

6.4 检索器

检索器是一种便于模型查询的存储数据的方式,LangChain约定检索器组件至少有一个方法

get_relevant_texts,这个方法接收查询字符串,返回一组文档。

from langchain_classic.document_loaders import TextLoader
from langchain_classic.text_splitter import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import OllamaEmbeddings

loader = TextLoader('./pku.txt')
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

embeddings = OllamaEmbeddings(model="mxbai-embed-large")

db = FAISS.from_documents(texts, embeddings)
retriever = db.as_retriever(search_kwargs={'k': 1})
docs = retriever.get_relevant_documents("北京大学什么时候成立的")
print(docs)

#打印结果:
'''
[Document(metadata={'source': './pku.txt'}, page_content='北京大学创办于1898年,是戊戌变法的产物,也是中华民族救亡图存、兴学图强的结果,初名京师大学堂,是中国近现代第一所国立综合性大学,辛亥革命后,于1912年改为现名。')]
'''

LangChain支持的检索器组件如下:

检索器 介绍
Azure Cognitive Search Retriever Amazon ACS检索服务
ChatGPT Plugin Retriever ChatGPT检索插件
Databerry Databerry检索
ElasticSearch BM25 ElasticSearch检索器
Metal Metal检索器
Pinecone Hybrid Search Pinecone检索服务
SVM Retriever SVM检索器
TF-IDF Retriever TF-IDF检索器
VectorStore Retriever VectorStore检索器
Vespa retriever 一个支持结构化文本和向量搜索的平台
Weaviate Hybrid Search 一个开源的向量搜索引擎
Wikipedia 支持wikipedia内容检索

三、LangChain可以使用到的场景

• 个人助手
• 基于文档的问答系统
• 聊天机器人
• Tabular数据查询
• API交互
• 信息提取
• 文档总结

目录

一、什么是LangChain

二、LangChain主要组件

1 Models

1.1 LLMs (大语言模型)

1.2 Chat Models (聊天模型)

1.3 提示模板

1.4 Embeddings Models(嵌入模型)

2 Prompts

zero-shot提示方式:

few-shot提示方式:

3 Chains(链)

4 Agents (代理)

5 Memory

6 Indexes (索引)

6.1 文档加载器

6.2 文档分割器

6.3 VectorStores

6.4 检索器

三、LangChain可以使用到的场景


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐