LangChain入门

LangChain

概述

LangChain 是一个用于构建基于大语言模型(LLM)的应用程序的 Python 框架,它的核心目标是让我们能更容易地把 LLM 与数据、工具、记忆等组件连接起来,构建复杂的、可组合的 AI 应用。

大语言模型很强,但原生 API 只支持「问一句 → 回一句」的简单用法,如果我们想实现有记忆的多轮对话、自动调用工具(如搜索、数据库、浏览器)或者智能体(Agent)自动解决问题这类较为复杂的操作的话我们就需要 LangChain ,事实上它就是为了解决这些问题而设计的。

LangChain简化了LLM应用程序生命周期的各个阶段:

开发阶段:使用LangChain的开源构建块和组件构建应用程序,利用第三方集成和模板快速启动。

生产化阶段:使用LangSmith检查、监控和评估您的链,从而可以自信地持续优化和部署。

部署阶段:使用LangServe将任何链转化为API。

LangChain的六大组件

LangChain 的设计思想是“组件化 + 链式组合”,他有六个主要的组件:

  • 模型(Models):包含各大语言模型的LangChain接口和调用细节,以及输出解析机制。
  • 提示模板(Prompts):使提示工程流线化,进一步激发大语言模型的潜力。
  • 数据检索(Indexes):构建并操作文档的方法,接受用户的查询并返回最相关的文档,轻松搭建本地知识库。
  • 记忆(Memory):通过短时记忆和长时记忆,在对话过程中存储和检索数据,让ChatBot记住你。
  • 链(Chains):LangChain中的核心机制,以特定方式封装各种功能,并通过一系列的组合,自动而灵活地完成任务。
  • 代理(Agents):另一个LangChain中的核心机制,通过“代理”让大模型自主调用外部工具和内部工具,使智能Agent成为可能。

LangChain的工作流程大概长这样:

User Input
   ↓
PromptTemplate(拼 Prompt)
   ↓
LLM 调用(OpenAI/HuggingFace)
   ↓
Memory / Tools / Retrievers(可选)
   ↓
输出或继续下一步 Chain / Agent

开源库组成

LangChain主要由以下开源库组成:

  • langchain-core :基础抽象和LangChain表达式语言
  • langchain-community :第三方集成。合作伙伴包(如langchain-openai、langchain-anthropic等),一些集成已经进一步拆分为自己的轻量级包,只依赖于langchain-core
  • langchain :构成应用程序认知架构的链、代理和检索策略
  • langgraph:通过将步骤建模为图中的边和节点,使用 LLMs 构建健壮且有状态的多参与者应用程序
  • langserve:将 LangChain 链部署为 REST API
  • LangSmith:一个开发者平台,可让您调试、测试、评估和监控LLM应用程序,并与LangChain无缝集成

LangChain基本使用

安装与配置

首先第一步当然是安装LangChain,命令如下:

python -m pip install langchain

这个过程里会下载非常多的组件,覆盖我们需要的常见开源库,接着我们需要去安装LangChain时包括常用的开源LLM(大语言模型) 库,比如openai:

python -m pip install openai

接着安装第三方集成库,以使用OpenAI:

python -m pip install langchain langchain_openai

最简单的demo

如果我们想要使用OpenAI,首先需要配置OpenAI环境变量,导入接口和key,这个东西可以单独在一个文件里设置然后导入,也可以直接在我们的代码的基础上引入,这里我就使用第二种方式,这里我用的不是原生的openapi,用的是中转的:https://gptgod.site/

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    api_key="sk-XXXXXX",
    base_url="https://api.gptgod.online/v1/"
)

print(llm.invoke("永雏塔菲是什么?"))

然后就可以获得llm的返回结果:

使用提示模板

LangChain 中的「提示模板(PromptTemplate)」功能可以把用户的原始输入包装成结构化、有上下文的提示,指导 LLM 生成更符合预期的回答。

比如我们可以按这个格式创建提示模板:

from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
    ("system", "您是世界级的二次元高手。"),
    ("user", "{input}")
])

其中这个 system 可以给 LLM 设定角色/风格,比如这里是”您是世界级的二次元高手”,这会影响回答的语气、组织方式。接着 user {input} 是占位符,用于之后动态传入用户输入。

比如我们现在和之前一样传入 chain.invoke({"input": "永雏塔菲是什么?"}),实际上传给llm的东西就变成了:

System: 您是世界级的二次元高手。
User: 永雏塔菲是什么?

最后我们需要构造一个构造 LLM 链(Chain),格式为:

chain = prompt | llm

这是 LangChain 的「管道写法」,它把 prompt 输出的结构化提示作为输入交给 llm 处理,最后返回 AI 的回答,流程也就是:promptllm ➜ 输出答案,现在完整的代码如下:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOpenAI(
    api_key="sk-XXXXX",
    base_url="https://api.gptgod.online/v1/"
)

# 创建提示模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "您是世界级的二次元高手。"),
    ("user", "{input}")
])

# 组合成一个简单的 LLM 链
chain = prompt | llm 

# 使用LLM链
print(chain.invoke({"input": "永雏塔菲是什么?"}))

可以现在的回复就比之前唐了点,会提到塔菲来自于二次元。

使用输出解析器

输出解析器(StrOutputParser)可以把 LLM 返回的结构化消息(如 ChatMessage 对象)解析成一个简单的字符串,便于后续处理或展示,我们只需要加一句:

output_parser = StrOutputParser()
chain = prompt | llm | output_parser

这样再调用它并提出同样的问题,答案就是一个字符串,而不是ChatMessage:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(
    api_key="sk-XXXXX",
    base_url="https://api.gptgod.online/v1/"
)

# 创建提示模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "您是世界级的二次元高手。"),
    ("user", "{input}")
])

# 使用输出解析器
output_parser = StrOutputParser()

# 将其添加到上一个链中
chain = prompt | llm | output_parser

# 调用它并提出同样的问题。答案是一个字符串,而不是ChatMessage
print(chain.invoke({"input": "永雏塔菲是什么?"}))

向量存储

利用向量存储,我们可以把网页内容变成向量表示并存入 FAISS 向量库,以后 LLM 可以通过语义搜索查找这些内容作为参考,这样就实现了RAG(Retrieval-Augmented Generation),首先安一个东西:

python -m pip install langchain_community

想要加载索引的数据,首先我们需要安装 beautifulsoup 和本地向量存储 FAISS(Facebook 开源的本地向量数据库,用于存储和查询向量)

python -m pip install beautifulsoup4 faiss-cpu

想要加载网页文档,我们需要利用 WebBaseLoader 抓取指定网页,然后用 BeautifulSoup 解析内容,最后得到一组“文档对象”(LangChain 的标准格式)

from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://baike.baidu.com/item/%E6%B0%B8%E9%9B%8F%E5%A1%94%E8%8F%B2/61675407")
docs = loader.load()

接着初始化嵌入模型,这里我们使用OpenAI 提供的嵌入模型(如 text-embedding-ada-002)把文本转换为“向量”:

from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()

然后需要对文本分割(切块),因为一整页网页太长,不能直接做嵌入或查询,要拆成一段一段的小文本,RecursiveCharacterTextSplitter 会自动按结构切分,比如按段落、句子、字符:

from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

最后创建向量存储(FAISS),把每段文档转换为向量用 FAISS 存起来,后续可以用向量相似度查找这些内容:

from langchain_community.vectorstores import FAISS

vector = FAISS.from_documents(documents, embeddings)

通过上面的操作,我们就建好了一个本地向量数据库 vector,它可以将结果反馈给 LLM 作为上下文参考,根据用户输入(如问题)生成嵌入向量,然后在其中查找最相似的文档段落,这就是 RAG 的检索部分,流程大概长这样:

网页 ➜ BeautifulSoup ➜ 文本段落 ➜ 嵌入模型 ➜ 向量表示 ➜ FAISS 向量库

完整的代码如下:

# 导入和使用 WebBaseLoader
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://baike.baidu.com/item/%E6%B0%B8%E9%9B%8F%E5%A1%94%E8%8F%B2/61675407")
docs = loader.load()

# 对于嵌入模型,这里通过 API调用
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()

#使用此嵌入模型将文档摄取到矢量存储中
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 使用分割器分割文档
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)
# 向量存储
vector = FAISS.from_documents(documents, embeddings)

检索链

在上面的步骤里,我们已在向量存储中索引了这些数据,接下来要创建一个检索链。该链将接收一个传入的问题,查找相关文档,然后将这些文档与原始问题一起传递给LLM,要求它回答原始问题。

现在我们就可以要求llm只能从我们上面设置好的数据库里进行回答,完整代码如下:

import os

# 导入模块
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate

# 1. 加载网页文档(永雏塔菲词条)
loader = WebBaseLoader("https://baike.baidu.com/item/%E6%B0%B8%E9%9B%8F%E5%A1%94%E8%8F%B2/61675407")
docs = loader.load()

# 2. 文本分割
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

# 3. 嵌入模型
embeddings = OpenAIEmbeddings(
    api_key="sk-xxx",
    base_url="https://api.gptgod.online/v1/"
)

# 4. 向量数据库构建
vector = FAISS.from_documents(documents, embeddings)

# 5. 创建 LLM 和 Prompt
llm = ChatOpenAI(
    api_key="sk-xxx",
    base_url="https://api.gptgod.online/v1/"
)

prompt = ChatPromptTemplate.from_template("""仅根据提供的上下文回答以下问题:

<context>
{context}
</context>

Question: {input}""")

# 6. 创建文档链(负责把多个文档拼成提示,发给 LLM)
document_chain = create_stuff_documents_chain(llm, prompt)

# 7. 创建检索器(从 FAISS 检索)
retriever = vector.as_retriever()

# 8. 创建最终检索链
retrieval_chain = create_retrieval_chain(retriever, document_chain)

# 9. 执行查询
query = "永雏塔菲是谁?"
response = retrieval_chain.invoke({"input": query})

# 10. 打印结果
print("\n【问题】:", query)
print("【回答】:", response["answer"])

现在llm就不会乱说了,而是根据文档回答出正确的内容:

对话检索链

上面的代码是一次性的,这里我们来构建一个对话式问答系统(conversational retrieval QA chain),适合用户连续提问、引用前文上下文的场景。普通检索链只根据当前用户问题去检索相关内容,而对话检索链会参考之前的对话历史,从而生成更准确、更上下文相关的搜索查询。

首先我们创建一个生成检索查询的 Prompt,这样就可以把之前的对话记录 (chat_history) 和当前问题 (input) 一起交给 LLM,最后一句话是提示 LLM:“请根据上下文生成一个适合检索的查询。”:

prompt = ChatPromptTemplate.from_messages([
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
    ("user", "鉴于上述对话,生成一个搜索查询以查找以获取与对话相关的信息")
])

这里我们构建对话感知的 Retriever 链,利用 LLM 来“理解”整个对话上下文,生成一个合适的搜索查询(如:LangSmith 测试方法),然后交给向量检索器(retriever)去找相关文档

retriever_chain = create_history_aware_retriever(llm, retriever, prompt)

我们可以测试这个 retriever_chain,这里的 “告诉我怎么做” 是一个非常模糊的问题。但由于上下文中提到了 “LangSmith 测试”,所以检索链就可以理解未“我想了解如何使用 LangSmith 测试 LLM 应用”:

chat_history = [
    HumanMessage(content="LangSmith 可以帮助测试我的 LLM 应用程序吗?"),
    AIMessage(content="Yes!")
]
retriever_chain.invoke({
    "chat_history": chat_history,
    "input": "告诉我怎么做"
})

构建最终的对话检索链(retrieval_chain),这里用 retriever_chain 动态生成检索结果(基于上下文生成检索关键词),然后把这些文档 + chat history + 用户当前输入一起传给 LLM 回答问题

prompt = ChatPromptTemplate.from_messages([
    ("system", "根据以下上下文回答用户的问题:\n\n{context}"),
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
])
document_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(retriever_chain, document_chain)

最后执行多轮问答,这个请求的意思是:“基于我们之前的对话,告诉我 LangSmith 如何帮助测试”。它会先检索相关内容,再生成回答

chat_history = [
    HumanMessage(content="LangSmith 可以帮助测试我的 LLM 应用程序吗?"),
    AIMessage(content="Yes!")
]
retrieval_chain.invoke({
    "chat_history": chat_history,
    "input": "Tell me how"
})

完整的代码:

import os

# LangChain 模块
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# 构建链用的模块
from langchain.chains import create_retrieval_chain, create_history_aware_retriever
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage

# === 1. 加载网页文档 ===
loader = WebBaseLoader("https://baike.baidu.com/item/%E6%B0%B8%E9%9B%8F%E5%A1%94%E8%8F%B2/61675407")
docs = loader.load()

# === 2. 分割文档 ===
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

# === 3. 嵌入模型 & 向量存储 ===
embeddings = OpenAIEmbeddings(
    api_key="你的OpenAI Key",
    base_url="https://api.gptgod.online/v1/"
)
vectorstore = FAISS.from_documents(documents, embeddings)

# === 4. 初始化 LLM ===
llm = ChatOpenAI(
    api_key="你的OpenAI Key",
    base_url="https://api.gptgod.online/v1/"
)

# === 5. 构建历史感知检索器 ===
retriever = vectorstore.as_retriever()

history_prompt = ChatPromptTemplate.from_messages([
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
    ("user", "鉴于上述对话,生成一个搜索查询以查找与对话相关的信息")
])
history_aware_retriever = create_history_aware_retriever(llm, retriever, history_prompt)

# === 6. 构建回答链 ===
response_prompt = ChatPromptTemplate.from_messages([
    ("system", "根据以下上下文回答用户的问题:\n\n{context}"),
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
])
document_chain = create_stuff_documents_chain(llm, response_prompt)

# === 7. 最终对话检索链 ===
conversational_chain = create_retrieval_chain(history_aware_retriever, document_chain)

# === 8. 示例对话 ===
chat_history = [
    HumanMessage(content="永雏塔菲是谁?"),
    AIMessage(content="永雏塔菲是一位虚拟主播。")
]

# 用户继续提问
query = "她的出道时间是?"

# === 9. 执行查询 ===
response = conversational_chain.invoke({
    "chat_history": chat_history,
    "input": query
})

# === 10. 输出结果 ===
print("\n【问题】:", query)
print("【回答】:", response["answer"])

可以看到虽然我们用了”她的出道时间是?”这种模糊的表达,llm还是识别出来我们问的其实是永雏塔菲:

代理的使用

代理是 LangChain中的核心机制,通过“代理”让大模型自主调用外部工具和内部工具,使智能Agent成为可能。

创建搜索工具

访问Tavily,注册账号登录并创建API秘钥,然后配置环境变量

import os

os.environ["TAVILY_API_KEY"] = 'tvly-ScxxxxxxxM8'

安装tavily-python库

pip install -U langchain-community tavily-python

创建工具

from langchain_community.tools.tavily_search import TavilySearchResults

search = TavilySearchResults()

完整的Agent代码

import os
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType

# 配置 API KEY 与 BASE
OPENAI_API_KEY = "sk-xx"
OPENAI_API_BASE = "https://api.gptgod.online/v1/"

os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
os.environ["OPENAI_API_BASE"] = OPENAI_API_BASE
os.environ["TAVILY_API_KEY"] = 'tvly-dev-xxxx'

# 初始化工具
search = TavilySearchResults()
tools = [search]

# 初始化模型
llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    temperature=0,
    api_key=OPENAI_API_KEY,
    base_url=OPENAI_API_BASE
)

# 使用标准 AgentType.ZERO_SHOT_REACT_DESCRIPTION 避免 Function Call
agent_executor = initialize_agent(
    tools,
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# 执行
response = agent_executor.invoke({"input": "成都今天天气情况?"})
print(response)

这样在遇到天气有关的话题,llm就会自动调用创建好的工具完成我们的提问。

LangServe提供服务

LangServe 是 LangChain 提供的一个部署工具,可以将你写的 Chain/Agent 快速包装成一个基于 FastAPI 的 Web 服务,并自动生成:

  • REST API 路由
  • OpenAPI 文档(/docs
  • Chat Playground 界面(/agent/playground/

创建服务

首先安装langserve:

python -m pip install "langserve[all]"

server由三部分组成:

  • 构建的链的定义
  • FastAPI应用程序
  • 为链提供服务的路由的定义,由langserve.add_routes命令完成

我们只需要在原本的agent的基础上添加Web 服务 + 路由(FastAPI)

app = FastAPI(...)

class Input(BaseModel):
    input: str
    chat_history: List[BaseMessage]

class Output(BaseModel):
    output: str

add_routes(
    app,
    agent_executor.with_types(input_type=Input, output_type=Output),
    path="/agent",
)

接着启动服务,这样我们就可以访问/agent/playground/,一个带 UI 的 Agent Playground 来进行交互问答

uvicorn.run(app, host="localhost", port=8000)

完整的代码:

import os
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Any

from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langserve import add_routes

# 环境配置
OPENAI_API_KEY = "sk-xxx"
OPENAI_API_BASE = "https://api.gptgod.online/v1/"

os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
os.environ["OPENAI_API_BASE"] = OPENAI_API_BASE
os.environ["TAVILY_API_KEY"] = "tvly-dev-xxxx"

# 工具和模型初始化
search = TavilySearchResults()
tools = [search]

llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    temperature=0,
    api_key=OPENAI_API_KEY,
    base_url=OPENAI_API_BASE
)

agent_executor = initialize_agent(
    tools,
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True,
    handle_parsing_errors=True 
)

# FastAPI 应用
app = FastAPI(
    title="LangServe Agent",
    version="1.0"
)

# 请求/响应模型
class Input(BaseModel):
    input: str
    chat_history: Any = []

class Output(BaseModel):
    output: str

# 添加 LangServe 路由
add_routes(
    app,
    runnable=agent_executor.with_types(input_type=Input, output_type=Output),
    path="/agent"
)

# 启动入口
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="localhost", port=8000)

启动后访问http://localhost:8000/agent/playground/,就可以在这里进行实时的对话,比如询问”成都今天的天气如何”,就会在页面获得结果:

客户端交互

我们可以使用接口来便捷的获取服务:

import requests

data = {
    "input": {
        "chat_history": [],
        "input": "今天星期几"
    },
}

response = requests.post(
    "http://localhost:8000/agent/invoke",
    json=data
)

print(response.json())

或者直接使用原生的(记得不要挂代理,不然请求不了):

from langserve import RemoteRunnable

remote_chain = RemoteRunnable("http://localhost:8000/agent/")
res = remote_chain.invoke({
    "input": "成都今天天气情况怎样?",
    "chat_history": []
})
print(res)

参考

初识LangChain的快速入门指南

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇