LangChain 框架核心模块与使用指南
LangChain 是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序或各类 Agent。它提供了一套工具、组件和接口,可简化创建应用程序的过程。LangChain 可以轻松管理与 LLM 的交互,将多个组件链接在一起,并集成额外的资源。以下介绍 LangChain 框架提供的几个主要模块,这些模块按照逐渐增加的复杂性排列如下:
LangChain 是构建语言模型应用的框架,涵盖模型、提示、内存、索引、链和代理六大模块。通过标准化接口简化组件集成,支持检索增强生成(RAG)、多步任务编排及自主代理决策。各模块功能、代码实现及最佳实践,帮助开发者快速上手构建端到端 AI 应用。

LangChain 是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序或各类 Agent。它提供了一套工具、组件和接口,可简化创建应用程序的过程。LangChain 可以轻松管理与 LLM 的交互,将多个组件链接在一起,并集成额外的资源。以下介绍 LangChain 框架提供的几个主要模块,这些模块按照逐渐增加的复杂性排列如下:
LangChain 支持的各种模型类型和模型集成。
llm = OpenAI(model_name="text-ada-001", n=2, best_of=2)
# 生成文本:LLM 最基本的功能就是能够调用它,传入一个字符串并返回一个字符串。
result = llm("Tell me a joke")
print(result)
# 类似的还可以传入数组,得到 llm_result.generations[] 的各种信息
chat = ChatOpenAI(temperature=0)
messages = [HumanMessage(content="Translate this sentence from English to French. I love programming.")]
response = chat(messages)
# 响应将是一条消息。LangChain 目前支持的消息类型包括 AIMessage、HumanMessage、SystemMessage 和 ChatMessage。
print(response.content)
Embedding 类是一个用于与嵌入进行交互的类。有许多嵌入提供商(OpenAI、Cohere、Hugging Face 等)。这个类旨在为所有这些提供商提供一个标准接口。嵌入会创建文本的向量表示。这使我们可以在向量空间中执行诸如语义搜索之类的操作,寻找最相似的文本片段。
LangChain 中的基本 Embedding 类公开了两种方法:embed_documents 和 embed_query。最大的区别在于这两种方法具有不同的接口:一个适用于多个文档,而另一个适用于单个文档。
Prompt 是一种向语言模型提供特定的输入或指令,以此来引导模型生成用户期望的特定输出的提示词。通常这个提示词不仅仅是一个硬编码的字符串,而是一个模板、一些例子和用户输入的组合。提示词模板可能包含:
LangChain 提供了几个相关的提示模板,以便轻松构建和处理提示。包括 ChatPromptTemplate、PromptTemplate、SystemMessagePromptTemplate、AIMessagePromptTemplate、HumanMessagePromptTemplate 等。
官方文档提供的示例可以使用 from_template 方法直接将自定义 template 文本作为参数建立提示词模板,也可以将 PromptTemplate 实例化后作为参数传递给 MessagePromptTemplates。
template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
prompt = PromptTemplate(
template="You are a helpful assistant that translates {input_language} to {output_language}.",
input_variables=["input_language", "output_language"],
)
system_message_prompt_2 = SystemMessagePromptTemplate(prompt=prompt)
assert system_message_prompt == system_message_prompt_2
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
# get a chat completion from the formatted messages
messages = chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages()
Few Shot Examples 是一组示例,可用于帮助语言模型生成更好的响应。要使用 few shot examples 生成提示,可以使用 FewShotPromptTemplate。这个类接受一个 PromptTemplate 和一个 few shot examples 列表。然后,它将用 few shot examples 格式化提示模板。
如果在构建 prompt 过程中,如果有很多 example 示例,可以使用 ExampleSelector 类进行 select_examples,该方法接受输入变量,然后返回一个示例列表。该方法根据示例 example 与输入的相似度等选择示例。它通过查找嵌入与输入的余弦相似度最大的示例来实现此目的。使用方法示例如下:
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
Chroma,
k=1
)
similar_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="Give the antonym of every input",
suffix="Input: {adjective}\nOutput:",
input_variables=["adjective"],
)
输出解析器也是提示工程中的重要一环。一般来说 LLM 语言模型输出文本,但是很多时候需要获得比文本更结构化的信息。这就是输出解析器的作用。
输出解析器是帮助结构化语言模型响应的类。如逗号分隔列表:
['Vanilla', 'Chocolate', 'Strawberry', 'Mint Chocolate Chip', 'Cookies and Cream']
或者定义好我们想要接受的响应格式,并将模式作为参数传递给 prompt 模板,最终得到的大模型响应结果就可以按照预先定义的格式来。例如:
response_schemas = [
ResponseSchema(name="answer", description="answer to the user's question"),
ResponseSchema(name="source", description="source used to answer the user's question, should be a website.")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 进行调用后
parsed_output = output_parser.parse(output.content)
# 结果
# {'answer': 'Paris', 'source': 'https://en.wikipedia.org/wiki/Paris'}
序列化提示模板,可以将 PromptTemplate 保存到本地文件系统中。LangChain 会自动通过文件扩展名推断文件格式。当前,LangChain 支持将模板保存为 YAML 和 JSON 文件。
底层的 LLMs 和聊天模型是无状态的,因此每个请求都是独立地处理。但在某些应用程序中(如聊天机器人),记住以前的交互非常重要,无论是在短期还是长期层面上。因此需要一定的 memory 来存储过程中的交互数据。Memory 中可以保存最近 n 个对话和以前对话的消息摘要。
ConversationBufferWindowMemory 函数,保留了对话随时间推移的交互列表。它仅使用最后 K 个交互。这可以用于保持最近交互的滑动窗口,以便缓冲区不会过大。K 值作为参数可以自定义。ConversationEntityMemory,通过该函数来总结并记住特定实体的信息。它使用 LLMs 提取实体的信息,并移逐渐建立对实体的了解(通过 LLMs 的能力)。ConversationSummaryMemory 这种记忆类型可以创建关于对话的摘要,有助于从对话中概括信息。概括能力仍然需要 LLM。ConversationSummaryBufferMemory 结合了前两个想法。它将最近的交互记录缓存在内存中,但不仅仅是完全清除旧的交互,而是将它们编译成一份摘要并同时使用。不过,与之前的实现不同,它使用 token 长度而不是交互数量 K 来确定何时清除交互。ConversationTokenBufferMemory 会在内存中保留最近的对话内容,并使用 token 长度而不是对话数量来决定何时刷新对话。可以将历史记录作为消息列表。VectorStoreRetrieverMemory 将记忆存储在 VectorDB 中,并在每次调用时查询最重要的 K 个文档。与大多数其他记忆类不同的是,它不明确跟踪交互的顺序。在这种情况下,'文档'是先前的对话片段。这可以用来提到 AI 在对话中早期被告知的相关信息。主要关注于构建索引,目标是使用它们作为检索器。我们主要关注的检索器类型是 Vectorstore 检索器。它提供一系列能力将文件等非结构化数据存储起来并提供索引以供检索,更好的与大模型交互。
通过文件回答问题包括四个步骤:
首先可以使用 VectorstoreIndexCreator 创建索引,然后用它来询问数据问题,示例代码如下:
from langchain.indexes import VectorstoreIndexCreator
index = VectorstoreIndexCreator().from_loaders([loader])
query = "What did the president say about Ketanji Brown Jackson"
result = index.query(query)
# 下述方法可以返回查询的数据来源 sources 地址
sources = index.query_with_sources(query)
其中这个 VectorstoreIndexCreator 背后的主要功能如下:
加载文件后有三个主要步骤:
VectorstoreIndexCreator 只是所有这些逻辑的包装器。它可以在它使用的文本分割器、它使用的嵌入以及它使用的向量存储中进行配置。配置方法如下:
index_creator = VectorstoreIndexCreator(
vectorstore_cls=Chroma,
embedding=OpenAIEmbeddings(),
text_splitter=CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
)
与向量存储相关的高级功能如下:
docsearch = Chroma.from_texts(texts, embeddings)
query = "What did the president say about Ketanji Brown Jackson"
# 搜索
docs = docsearch.similarity_search(query)
# 添加文本
docsearch.add_texts(["Ankush went to Princeton"])
# 从文档初始化向量存储。使用文本拆分器方法直接获取文档
documents = text_splitter.create_documents([state_of_the_union], metadatas=[{"source": "State of the Union"}])
向量存储完成后,需要使用检索器来进行下一步查询。LangChain 最支持的索引,因此也是最支持的检索器是 VectorStoreRetriever。正如其名称所示,此检索器主要由 VectorStore 支持。
# 从向量数据库 db 中初始化一个检索器
retriever = db.as_retriever()
# 默认情况下,vectorstore 检索器使用相似性搜索。如果底层的 vectorstore 支持最大边际相关性搜索,则可以指定该搜索类型。
retriever = db.as_retriever(search_type="mmr")
docs = retriever.get_relevant_documents("what did he say about ketanji brown jackson")
使用单独的 LLM 对于一些简单的应用程序来说是可以的,但许多更复杂的应用程序需要链接 LLM——无论是相互链接还是与其他专家链接。LangChain 为链提供了标准接口,以及一些常见的链实现,以便于使用。链允许我们将多个组件组合在一起,创建一个单一的、一致的应用程序。例如,我们可以创建一个链,该链接接受用户输入,使用 PromptTemplate 对其进行格式化,然后将格式化后的响应传递给 LLM。我们可以通过将多个链组合在一起,或者通过将链与其他组件组合在一起,来构建更复杂的链。
LLMChain 是一个简单的链,它接受一个大模型 + 一个提示模板(可以是自定义的 PromptTemplate),也可以使用 chatllm + ChatPromptTemplate;然后将信息发个大模型并得到返回。
调用 Chain 的方式: 可以将 chain 作为一个 function 集成在 Tool 中,从而构建代理。代码示例如下:
tools.append(
Tool(
name="Calculator",
func=llm_math_chain.run,
description="在需要回答数学问题时非常有用",
args_schema=CalculatorInput
)
)
向链中添加内存:
Chain 支持将 BaseMemory 对象作为其内存参数,允许 Chain 对象跨多个调用持久存储数据。换句话说,它使 Chain 成为一个有状态对象。
调试链: 因为大多数 Chain 对象都涉及大量的输入提示预处理和 LLM 输出后处理,所以很难单独从它的输出调试 Chain 对象。如果详细设置为 True,将在 Chain 对象运行时打印出它的一些内部状态。
组合 Chain:
我们可以组合这两个 LLMChains,这样我们就可以在一个步骤中创建完成两个不同的任务,示例代码如下:
from langchain.chains import SimpleSequentialChain
overall_chain = SimpleSequentialChain(chains=[chain, chain_two], verbose=True)
# Run the chain specifying only the input variable for the first chain.
catchphrase = overall_chain.run("colorful socks")
print(catchphrase)
问答与来源: 如果我们想通过 chain 对一系列文档进行带来源的问答,首先,我们需要准备数据。在此示例中,我们在向量数据库上进行相似性搜索,但这些文档可以以任何方式获取(本教程的重点是强调在获取文档后要做什么)。可以使用如下代码思路:
# 准备问题
query = "What did the president say about Justice Breyer"
# 准备文档数据源&向量化存储
docsearch = Chroma.from_texts(texts, embeddings, metadatas=[{"source": str(i)} for i in range(len(texts))])
docs = docsearch.similarity_search(query)
# 使用链
chain = load_qa_with_sources_chain(OpenAI(temperature=0), chain_type="stuff")
chain({"input_documents": docs, "question": query}, return_only_outputs=True)
进一步的,可以使用向量数据进行索引对问题进行基于来源的问答。它通过使用 RetrievalQAWithSourcesChain 来完成从索引中查找文档的工作。代码如下:
docsearch = Chroma.from_texts(texts, embeddings, metadatas=[{"source": f"{i}-pl"} for i in range(len(texts))])
from langchain import OpenAI
chain = RetrievalQAWithSourcesChain.from_chain_type(OpenAI(temperature=0), chain_type="stuff", retriever=docsearch.as_retriever())
chain({"question": "What did the president say about Justice Breyer"}, return_only_outputs=True)
Agent 也可以称为'智能体'或'智能业务助理',在大模型技术驱动下,它通过'大模型 + 插件 + 执行流程 / 思维链'的方式,对应控制端 (Brain / 大脑)、感知端 (Perception)、执行端 (Action) 环节,实现了复杂的功能。一个代理 (Agent) 至少由三个部分组成:
Agent 的核心在于让 LLM 自主决定调用哪个工具以及调用的顺序。常见的 Agent 类型包括:
构建一个简单的 Agent 示例:
from langchain.agents import initialize_agent, Tool
from langchain.llms import OpenAI
llm = OpenAI(temperature=0)
tools = [
Tool(
name="Search",
func=search_tool.run,
description="Useful for when you need to answer questions about current events."
),
Tool(
name="Calculator",
func=calculator_tool.run,
description="Useful for when you need to answer questions about math."
)
]
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("Who is the CEO of Tesla? What is his net worth?")
在实际应用中,Agent 可以极大地扩展 LLM 的能力边界,使其不仅能回答问题,还能执行操作、访问外部 API 或处理复杂的工作流。
LangChain 提供了一个完整的生态系统,使得开发基于大语言模型的应用变得更加模块化、可扩展和易于维护。通过理解模型、提示、内存、索引、链和代理这六大核心模块,开发者可以根据具体需求灵活组合,构建出功能强大的 AI 应用。随着生态系统的不断演进,LangChain 将继续降低 AI 开发的门槛,推动更多创新场景的实现。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online