一、LangChain基础入门
1、 LangChain介绍
先看官方的定义
LangChain是一个基于语言模型开发应用程序的框架。它可以实现以下应用程序:
- 数据感知:将语言模型连接到其他数据源
- 自主性:允许语言模型与其环境进行交互
LangChain的主要价值在于:
- 组件化:为使用语言模型提供抽象层,以及每个抽象层的一组实现。组件是模块化且易于使用的,无论您是否使用LangChain框架的其余部分。
- 现成的链:结构化的组件集合,用于完成特定的高级任务
现成的链使得入门变得容易。对于更复杂的应用程序和微妙的用例,组件化使得定制现有链或构建新链变得更容易。
所以,LangChain是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序。LangChain通过将大型语言模型与其他知识库、计算逻辑相结合,实现了功能更加强大的人工智能应用。
2、 LangChain组成部分
2.1 LangChain库
Python 和 JavaScript 库。包含接口和集成多种组件的运行时基础,以及现成的链和代理的实现。LangChain 库本身由几个不同的包组成。
- langchain-core:基础抽象和 LangChain 表达语言。
- langchain-community:第三方集成,主要包括 langchain 集成的第三方组件。
- langchain:主要包括链 (chain)、代理(agent) 和检索策略。
2.2 LangChain任务处理流程
langChain 提供一套提示词模板 (prompt template) 管理工具,负责处理提示词,然后传递给大模型处理,最后处理大模型返回的结果,
LangChain 对大模型的封装主要包括 LLM 和 Chat Model 两种类型。
- LLM - 问答模型,模型接收一个文本输入,然后返回一个文本结果。
- Chat Model - 对话模型,接收一组对话消息,然后返回对话消息,类似聊天消息一样。
3、 LangChain快速入门
3.1 安装LangChain
要安装LangChain,可以使用Pip和Conda进行安装。以下是安装LangChain的步骤:
pip install langchain
3.2 初始化模型
在使用LangChain之前,需要导入LangChain x OpenAI集成包,并设置API密钥作为环境变量或直接传递给OpenAI LLM类。
首先,获取阿里云的API密钥,可以通过[创建账户并申请API]来获取。然后,可以将API密钥设置为环境变量,方法如下:
lua
import os
os.environ["DASHSCOPE_API_KEY"] = "替换API模型"
接下来,初始化模型:
ini
from langchain_openaiimportChatOpenAI
llm = ChatOpenAI()
以上是关于LLM链的介绍,希望能帮助您更好地理解如何安装LangChain并构建不同类型的链。
ini
fromlangchain_openaiimportChatOpenAI
fromopenaiimportOpenAI
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
llm = ChatOpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-plus"
)
3.3 使用LLM
使用LLM来回答问题非常简单。可以直接调用LLM的invoke方法,并传入问题作为参数。此外,还可以通过提示模板(prompt template)生成提示词,用于向模型(LLM)发送指令。
下面演示了如何构建一个简单的LLM链(chains):
ini
from langchain_core.prompts import ChatPromptTemplate
# 创建一个提示模板(prompt template)
prompt = ChatPromptTemplate.from_messages([
("system", "你是AI智能助手"),
("user", "{input}")
])
# 编排了工作流,返回llm执行结果。
chain = prompt|llm
开始chain定义的步骤开始逐步执行。
chain.invoke({"input": "帮我写一篇关于AI的技术文章,100个字"})
3.4 输出转换
LLM的输出通常是一条消息,为了更方便处理结果,可以将消息转换为字符串。下面展示如何将LLM的输出消息转换为字符串:
ini
fromlangchain_core.output_parsersimportStrOutputParser
# 创建一个字符串输出解析器
output_parser = StrOutputParser()
# 将输出解析器添加到LLM链中
chain = prompt|llm|output_parser
# 调用LLM链并提出问题
chain.invoke({"input": "帮我写一篇langchain的技术文章,100个字"})
以上是关于LLM链的介绍,希望能帮助您更好地理解如何安装LangChain并构建不同类型的链。
二、LangChain提示词工程
1、 提示词模板简介
在LangChain中,提示模板(Prompt Templates)扮演着至关重要的角色,它们允许开发者以结构化的方式向语言模型提供输入,从而引导模型生成所需的输出。
1.1 提示词模板的内容
提示词模板本质上跟平时大家使用的邮件模板、短信模板没什么区别,就是一个字符串模板,模板可以包含一组模板参数,通过模板参数值可以替换模板对应的参数。
一个提示词模板可以包含下面内容:
- 发给大语言模型(LLM)的指令。
- 一组问答示例,以提醒AI以什么格式返回请求。
- 发给语言模型的问题。
1.2 提示模板在LangChain中的作用
提示模板在LangChain中的作用是定义一个结构化的输入格式,该格式包含了模型在生成输出时所需的所有信息。通过使用提示模板,开发者可以确保向模型提供的输入是清晰、一致且易于理解的,从而提高模型的输出质量。
2 、提示词模板实战
2.1 字符串提示词模板
在LangChain中,可以使用 PromptTemplate 类创建简单的提示词。提示词模板可以内嵌任意数量的模板参数,然后通过参数值格式化模板内容。
python
from langchain.prompts import PromptTemplate
# 定义一个提示模板,包含adjective和content两个模板变量,模板变量使用{}包括起来
prompt_template = PromptTemplate.from_template(
"给我讲一个关于{content}的{adjective}故事。"
)
# 通过模板参数格式化提示模板
result = prompt_template.format(adjective="童话", content="一千零一夜")
print(result)
2.2 聊天消息提示词模板
聊天模型(Chat Model)以聊天消息列表作为输入,这个聊天消息列表的消息内容也可以通过提示词模板进行管理。这些聊天消息与原始字符串不同,因为每个消息都与"角色(role)"相关联。
在OpenAI的聊天模型中,给不同的聊天消息定义了三种角色类型分别是助手(assistant)、人类(human)或系统(system)角色。
- 助手(Assistant) 消息指的是当前消息是AI回答的内容
- 用户(user)消息指的是你发给AI的内容。
- 系统(system)消息通常是用来给AI身份进行描述
python
from langchain_core.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages(
[
("system", "你是一位人工智能助手,你的名字是{name}。"),
("user", "你能做什么"),
("ai", "设计课程,谢谢!"),
("user", "{user_input}"),
]
)
messages = chat_template.format_messages(name="教学助手",
user_input="你的名字叫什么?")
print(messages)
2.3 MessagesPlaceholder
MessagesPlaceholder 提示模板负责在特定位置添加消息列表。 在上面的 ChatPromptTemplate 中,我们看到了如何格式化两条消息,每条消息都是一个字符串。如果我们希望用户传入一个消息列表,就可以通过MessagesPlaceholder 的方式将其插入到特定位置。
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
from langchain_core.messages importHumanMessage
prompt_template = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant"),
#可以传入一组消息
MessagesPlaceholder("msgs")
])
result = prompt_template.invoke({"msgs": [HumanMessage(content="您好!"),
HumanMessage(content="langchain!")]})
print(result)
2.4 提示词追加示例
提示词中包含交互样本的作用是为了帮助模型更好地理解用户的意图,从而更好地回答问题或执行任务。小样本提示模板是指使用一组少量的示例来指导模型处理新的输入。这些示例可以用来训练模型,以便模型可以更好地理解和回答类似的问题。
提示词交互示例:
ini
examples = [
{
"question": "电话和电灯的发明者是否毕业于同一所大学?",
"answer":
"""
这里需要跟进问题吗:是的。
跟进:电话的发明者是谁?
中间答案:电话的发明者是Alexander Graham Bell。
跟进:Alexander Graham Bell毕业于哪所大学?
中间答案:Alexander Graham Bell没有正式大学学位,他在爱丁堡大学短暂学习过。
跟进:电灯的发明者是谁?
中间答案:电灯的发明者是Thomas Edison。
跟进:Thomas Edison毕业于哪所大学?
中间答案:Thomas Edison没有大学学位,他是自学成才的发明家。
所以最终答案是:不是
"""
}
]
告诉模型根据,Q是问题,A是答案,按这种格式进行问答交互。提示词追加示例代码如下。
python
from langchain.prompts import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from prompt_example import examples # examples是交互示例
example_prompt = PromptTemplate(input_variables=["question", "answer"],
template="问题:{question}\n{answer}")
print(example_prompt.format(**examples[0]))
三、LangChain工作流编排
1、 LCEL简介
LangChain 表达式语言 (LangChain Expression Language,简称 LCEL)是 LangChain 框架中的一个核心组件,旨在提供一种简洁、灵活的方式来定义和操作语言模型的工作流。LCEL 允许开发者以声明式的方式构建复杂的语言模型应用,而无需编写大量的样板代码。
1.1 LCEL的特点
首先,LCEL(LangChain Expression Language) 是一种强大的工作流编排 工具,可以从基本组件构建复杂任务链条(chain),并支持诸如流式处理 、并行处理 和日志记录等开箱即用的功能。
以下是LECL的主要优势:
- 异步、批处理和流支持:采用LCEL构建的任何链都将自动、完全的支持同步、异步、批处理和流等能力。
- Fallbacks:由于LLMs的非确定性,使得具备优雅地处理错误的能力变得很重要。
- 并行性:由于LLMs应用涉及(有时长期的)API调用,因此支持并行处理很重要。
- 无缝集成LangSmith:使用LCEL,所有步骤都会自动记录到LangSmith中,可以最大限度的实现可观察性和可调试性。
2 、LCEL 核心组件运行流程与架构解析
2.1 声明式语法概述
LCEL(LangChain 表达式语言)是一种声明式语法,专为 LangChain 框架设计,旨在通过一种直观的方式定义和组合不同类型的组件链。其核心目标是简化复杂应用程序的开发过程,使开发者能够专注于逻辑而非底层实现细节。
2.2 统一接口设计理念
为了支持灵活的组件组合,LCEL 提供了一个统一接口设计方案。该方案允许所有组件共享相同的调用模式,无论是代理、工具还是数据源,均可以通过一致的方法进行交互。这种一致性显著降低了学习成本,并提高了系统的可扩展性和易维护性。
2.3 工作流程详解
以下是 LCEL 的核心工作流程分解:
- 输入解析阶段:输入被传递到 LCEL 解析器中,后者会依据预设的语言规则对其进行分析。此过程中涉及的关键技术包括语言解析和模式匹配,这些机制共同作用以识别输入中的语义结构。
- 组件映射阶段:完成输入解析后,系统将根据解析结果动态生成对应的 LangChain 组件实例。这一环节依赖于预先配置好的映射表,其中记录了每种实体类型与其对应的具体实现之间的关系。
- 执行调度阶段 :所有必要的组件准备就绪之后,进入实际的工作流执行阶段。在此期间,各模块按照既定顺序依次激活并完成各自的任务处理。得益于前面提到的统一接口特性,即使面对复杂的多层嵌套场景也能保持清晰流畅的操作体验。
- 输出转换阶段:当整个链条上的活动全部结束时,最终产生的结果会被送入指定的 OutputParser 中进一步加工。例如,在某些情况下可能需要提取最有可能的结果作为返回值;此时可以利用像 StrOutputParser 这样的专用类来达成目的------它负责把原始形式的数据转化为更加简洁实用的文字表述。
综上所述,LCEL 不仅具备强大的功能表现力,而且拥有高度灵活性以及良好的兼容性能优势。LCEL核心组件运行流程如下图所示。

3 、LCEL下核心组件(Prompt+LLM)的实现
3.1 单链结构
字符串模板示例
ini
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
importos
os.environ["DASHSCOPE_API_KEY"] = "API Key"
prompt = ChatPromptTemplate.from_template("给我讲一个关于{topic}的故事!")
llm = ChatOpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-plus"
)
chain = prompt | llm
print(chain.invoke({"topic": "一千零一夜"}))
2 自定义停止输出符
arduino
# 自定义停止输出符为\n
chain = prompt | model.bind(stop=["\n"])
print(chain.invoke({"topic": "一千零一夜"}))
3 输出解析器
python
# 使用StrOutputParser输出字符串格式
from langchain_core.output_parsers import StrOutputParser
chain = prompt | llm | StrOutputParser()
print(chain.invoke({"topic": "一千零一夜"}))
4 兼容OpenAI函数调用形式
ini
functions = [
{
"name": "story",
"description": "故事",
"parameters": {
"type": "object",
"properties": {
"setup": {"type": "string", "description": "故事的开头"},
"punchline": {
"type": "string",
"description": "反转的结尾",
},
},
"required": ["setup", "punchline"],
},
}
]
chain = prompt|llm.bind(function_call={"name": "story"},
functions=functions)
result = chain.invoke({"topic": "童话"})
print(result)
四、LangChain服务部署
1、 LangServe 简介
LangServe 是 LangChain 提供的一个子项目,专注于简化 LangChain 组件(如 Runnables 和 Chains)的部署流程。其核心目标是让开发者能够以最小的努力将这些组件暴露为 REST API 或其他可远程调用的形式。
1.1 LangServe 的强大功能
- REST API 自动化生成 :用户无需手动编写复杂的 API 接口逻辑,LangServe 可以自动生成基于 FastAPI 的 RESTful 接口。因此,LangChain 的 Runnable 或 Chain 都能被轻松地转化为 HTTP 请求/响应的服务端点。
- 高效集成能力:不仅限于 Python 生态,LangServe 还提供了一个 JavaScript 客户端库,允许前端开发人员通过简单的代码调用已部署的服务。这种跨平台的支持极大地增强了系统的灵活性和适用范围。
- 轻量级配置选项:用户只需定义好 LangChain 对象并将其传递给 LangServe 实例即可启动服务。
- 扩展性和定制性:如果默认的行为无法满足需求,还可以进一步调整参数或者引入中间件来增强安全性、性能监控等功能。
1.2 LangServe 的特点
- 高效并发处理:提供 /invoke、/batch 和 /stream 端点,支持高并发请求处理。
- 流事件处理:新增 /stream_events 端点,简化流事件处理。
- 内置 LangSmith Tracing:支持 LangSmith 追踪功能,只需添加 API 密钥即可启用。
2 、环境配置和安装
2.1 客户端和服务器
首先需要安装相应的依赖包。可以通过以下命令完成安装:
css
pip install --upgrade "langserve[all]"
或者对于客户端代码,pip install "langserve[client]",对于服务器代码,pip install "langserve[server]"。
2.2 LangChain CLI
LangChain 提供了一个命令行界面(CLI),用于简化基于大型语言模型的应用程序开发过程。使用 langchain cli 命令创建新应用:
使用 langchain cli 命令创建新应用
arduino
langchain app new langchainserve
3 、LangServe示例应用
3.1 服务器
1 服务器serve端启动聊天模型
ini
from fastapi importFastAPI
from fastapi.middleware.cors import CORSMiddleware
from langchain_openai import ChatOpenAI
from langserve import add_routes
from langchain.prompts import ChatPromptTemplate
import os
os.environ["DASHSCOPE_API_KEY"] = "替换API"
app = FastAPI(
openapi_url="/api/v1/openapi.json",
title="LangChain 服务器",
version="1.0",
description="使用 Langchain 的 Runnable 接口的简单 API 服务器",
)
add_routes(
app,
ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-plus"),
path="/openai",
)
# 设置所有启用 CORS 的来源
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
)
if__name__ == "__main__":
importuvicorn
uvicorn.run(app, host="localhost", port=8000)
2 客户端调用服务端返回结果
python
from langchain.schema.runnable import RunnableMap
from langchain_core.prompts import ChatPromptTemplate
from langserve import RemoteRunnable
openai = RemoteRunnable("http://localhost:8000/openai/")
prompt = ChatPromptTemplate.from_messages(
[("system", "你是一个喜欢故事创作的助手"), ("user", "写一个故事,主题是: {topic}")]
)
# 可以定义自定义链
chain = prompt|RunnableMap({
"openai": openai
})
print("同步调用/openai/invoke结果")
response = chain.invoke([{"topic": "一千零一夜"}])
print(response)
五、LangChain基于RAG实现文档问答
1、 RAG(Retrieval-augmented Generation)是什么?
大语言模型所实现的最强大应用之一是复杂的问答(Q&A)聊天机器人。这些应用能够回答关于特定源信息的问题。这些应用使用一种称为检索增强生成(RAG)的技术。
RAG是一种用额外数据增强大语言模型知识的技术。
大语言模型可以对广泛的主题进行推理,但它们的知识仅限于训练时截止日期前的公开数据。如果你想构建能够对私有数据或模型截止日期后引入的数据进行推理的人工智能应用,你需要用特定信息来增强模型的知识。检索适当信息并将其插入模型提示的过程被称为检索增强生成(RAG)。
LangChain有许多组件旨在帮助构建问答应用,以及更广泛的RAG应用。
2 、RAG工作流
一个典型的RAG应用有两个主要组成部分:
索引(Indexing) :从数据源获取数据并建立索引的管道(pipeline)。这通常在离线状态下进行。
检索和生成(Retrieval and generation) :实际的RAG链,在运行时接收用户查询,从索引中检索相关数据,然后将其传递给模型。
从原始数据到答案的最常见完整顺序如下:
2.1 索引(Indexing)
- 加载(Load) :首先我们需要加载数据。这是通过文档加载器Document Loaders完成的。
- 分割(Split) :文本分割器Text splitters将大型文档(
Documents)分成更小的块(chunks)。这对于索引数据和将其传递给模型都很有用,因为大块数据更难搜索,而且不适合模型有限的上下文窗口。 - 存储(Store) :我们需要一个地方来存储和索引我们的分割(splits),以便后续可以对其进行搜索。这通常使用向量存储VectorStore和嵌入模型Embeddings model来完成。
2.2 检索和生成(Retrieval and generation)
- 检索(Retrieve) :给定用户输入,使用检索器Retriever从存储中检索相关的文本片段。
- 生成(Generate) : ChatModel使用包含问题和检索到的数据的提示来生成答案。
3、 文档问答
3.1 实现流程
一个 RAG 程序的 APP 主要有以下流程:
-
用户在 RAG 客户端上传一个txt文件
-
服务器端接收客户端文件,存储在服务端
-
服务器端程序对文件进行读取
-
对文件内容进行拆分,防止一次性塞给 Embedding 模型超 token 限制
-
把 Embedding 后的内容存储在向量数据库,生成检索器
-
程序准备就绪,允许用户进行提问
-
用户提出问题,大模型调用检索器检索文档,把相关片段找出来后,组织后,回复用户。

4 、代码实现
使用 Streamlit 实现文件上传,我这里只实现了 txt 文件上传,其实这里可以在 type 参数里面设置多个文件类型,在后面的检索器方法里面针对每个类型进行处理即可。
4.1 实现文件上传
ini
importstreamlitasst
# 上传txt文件,允许上传多个文件
uploaded_files = st.sidebar.file_uploader(
label="上传txt文件", type=["txt"], accept_multiple_files=True
)
ifnotuploaded_files:
st.info("请先上传按TXT文档。")
st.stop()
4.2 实现检索器
注意 chunk_size 最大设置数值取决于 Embedding 模型允许单词的最大字符数限制。
python
importtempfile
importos
fromlangchain.document_loadersimportTextLoader
fromlangchain_community.embeddingsimportQianfanEmbeddingsEndpoint
fromlangchain_chromaimportChroma
fromlangchain_text_splittersimportRecursiveCharacterTextSplitter
# 实现检索器
@st.cache_resource(ttl="1h")
defconfigure_retriever(uploaded_files):
# 读取上传的文档,并写入一个临时目录
docs = []
temp_dir = tempfile.TemporaryDirectory(dir=r"D:\")
forfileinuploaded_files:
temp_filepath = os.path.join(temp_dir.name, file.name)
withopen(temp_filepath, "wb") asf:
f.write(file.getvalue())
loader = TextLoader(temp_filepath, encoding="utf-8")
docs.extend(loader.load())
# 进行文档分割
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30)
splits = text_splitter.split_documents(docs)
# 这里使用了OpenAI向量模型
embeddings = OpenAIEmbeddings()
vectordb = Chroma.from_documents(splits, embeddings)
retriever = vectordb.as_retriever()
returnretriever
retriever = configure_retriever(uploaded_files)
4.3 创建检索工具
langchain 提供了 create_retriever_tool 工具,可以直接用。
ini
# 创建检索工具
fromlangchain.tools.retrieverimportcreate_retriever_tool
tool = create_retriever_tool(
retriever,
"文档检索",
"用于检索用户提出的问题,并基于检索到的文档内容进行回复.",
)
tools = [tool]
4.4 创建 React Agent
ini
instructions = """您是一个设计用于查询文档来回答问题的代理。
您可以使用文档检索工具,并基于检索内容来回答问题
您可能不查询文档就知道答案,但是您仍然应该查询文档来获得答案。
如果您从文档中找不到任何信息用于回答问题,则只需返回"抱歉,这个问题我还不知道。"作为答案。
"""
base_prompt_template = """
{instructions}
TOOLS:
------
You have access to the following tools:
{tools}
To use a tool, please use the following format:
•```
Thought: Do I need to use a tool? Yes
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
•```
When you have a response to say to the Human, or if you do not need to use a tool, you MUST use the format:
•```
Thought: Do I need to use a tool? No
Final Answer: [your response here]
•```
Begin!
Previous conversation history:
{chat_history}
New input: {input}
{agent_scratchpad}"""
base_prompt = PromptTemplate.from_template(base_prompt_template)
prompt = base_prompt.partial(instructions=instructions)
# 创建llm
llm = ChatOpenAI()
# 创建react Agent
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, memory=memory, verbose=False)
4.5 实现 Agent 回复
获取用户输入,并回复用户,这里使用 StreamlitCallbackHandler 实现了 React 推理回调,可以让模型的推理过程可见。
lua
# 创建聊天输入框
user_query = st.chat_input(placeholder="请开始提问吧!")
ifuser_query:
st.session_state.messages.append({"role": "user", "content": user_query})
st.chat_message("user").write(user_query)
withst.chat_message("assistant"):
st_cb = StreamlitCallbackHandler(st.container())
config = {"callbacks": [st_cb]}
response = agent_executor.invoke({"input": user_query}, config=config)
st.session_state.messages.append({"role": "assistant", "content": response["output"]})
st.write(response["output"])
4.6 实现效果

总结
LangChain是线性链式执行(A → B → C),适合简单RAG、数据提取、固定流程任务。所以适合如下场景:
- 构建文档问答系统(RAG)
- 结构化数据提取(如从简历中提取信息)
- 简单聊天机器人(无复杂上下文依赖)