LangChain 框架详解与大语言模型应用实践
LangChain 是一个用于构建基于大型语言模型应用的开源框架。它通过组件化设计,将 LLM 与数据源、计算逻辑及外部工具连接,实现复杂应用开发。核心模块包括 Model I/O、Data Connection、Chains、Memory 和 Agent。本文详细介绍了各模块功能,提供了图片生成、智能答疑、结构化输出及聊天机器人构建的代码示例,并探讨了未来发展趋势与生产环境最佳实践。

LangChain 是一个用于构建基于大型语言模型应用的开源框架。它通过组件化设计,将 LLM 与数据源、计算逻辑及外部工具连接,实现复杂应用开发。核心模块包括 Model I/O、Data Connection、Chains、Memory 和 Agent。本文详细介绍了各模块功能,提供了图片生成、智能答疑、结构化输出及聊天机器人构建的代码示例,并探讨了未来发展趋势与生产环境最佳实践。

近期,大型语言模型(LLM)如 GPT 系列模型引领了人工智能领域的一场技术革命。开发者们都在利用这些 LLM 进行各种尝试,虽然已经产生了许多有趣的应用,但是单独使用这些 LLM 往往难以构建功能强大的实用应用。
LangChain 通过将大型语言模型与其他知识库、计算逻辑相结合,实现了功能更加强大的人工智能应用。简单来说,LangChain 可以被视为开源版的 GPT 插件,它提供了丰富的大语言模型工具,可以在开源模型的基础上快速增强模型的能力。
在此,总结了 LangChain 的学习内容,旨在与更多朋友交流。LangChain 使得语言技术的运用更加活跃多元,有望在人工智能领域发挥重要作用,推动工作效率的变革。
LangChain 源于 Harrison 与领域内一些人的交谈,这些人正在构建复杂的 LLM 应用,他在开发方式上看到了一些可以抽象的部分。一个应用可能需要多次提示 LLM 并解析其输出,因此需要编写大量的复制粘贴代码。
LangChain 使这个开发过程更加简单。一经推出后,在社区被广泛采纳,不仅有众多用户,还有许多贡献者参与开源工作。
主要特性:
主要价值:
这一部分第一次接触是在 4 月份,那个时候 LangChain 在 v0.0.6x 的版本,最近新增了一些功能,当然最近新增的功能看起来更加的合理,往好的方向发展,但是主要模块变化不大。

以下核心部分模块,都有对应的实践代码放在本仓库中,执行代码需要做的一些准备:
OPENAI_API_KEY=
HUG_API_KEY=
SERPAPI_API_KEY=
WANDB_API_KEY=
另外本次案例,一些比较重要的模块安装:
pip install openai python-dotenv langchain google-search-results tiktoken sentence_transformers chromadb redis faiss-cpu playwright wandb langflow
| 模块 | 说明 | 安装命令 |
|---|---|---|
| openai python-dotenv langchain | 主要的 LangChain 模块 | pip install openai python-dotenv langchain |
| google-search-results | 使用 Google 搜索的接口 | pip install google-search-results |
| tiktoken | 进行 summary 的时候,需要进行分割 | pip install tiktoken |
| sentence_transformers | 进行文本 Embedding | pip install sentence_transformers |
| chromadb | 向量数据库,存储文本嵌入向量 | pip install chromadb |
| redis | 如果 chromadb 有 bug,使用 redis 存储向量也可以 | pip install redis |
| faiss-cpu | Facebook 的相似性向量搜索库 | pip install faiss-cpu |
| playwright | 浏览器测试工具,Agent 测试时候用 | pip install playwright |
| wandb | LangChain 调试工具 | pip install wandb |
| langflow | LangChain 可视化配置工具 | pip install langflow |
和大模型交互的部分,LangChain 为我们抽象了三个组件,模型输入、模型、模型输出解析器:

LangChain 的一个核心价值就是它提供了标准的模型接口;然后我们可以自由的切换不同的模型,当前主要有两种类型的模型,LLMs(语言模型)和 Chat Models(聊天模型)。说到模型,大家就理解模型就是 ChatGPT 就可以。单纯的模型只能生成文本内容。

面向模型编程,其实就是写 Prompt。Prompt 是模型的输入,高质量的 Prompt 对于充分发挥 AI 的能力至关重要。LangChain 提供了两个工具:


语言模型输出的是文本。但很多时候,我们想要获得更结构化的信息。输出解析器可以帮助我们结构化语言模型的输出。
输出解析器有两个主要方法:

| 名称 | 说明 |
|---|---|
| 文档加载器 (Document loaders) | 用于从各种数据源(如文本文件、网页、视频等)中提取文本数据,并将这些数据以一种标准化的形式(即'文档')进行管理和使用。 |
| 文档转换器 (Document transformers) | 在加载了文档之后,对它们进行转换,以便更好地适应应用。例如,将一个长文档分割成可以适应模型上下文窗口的小块。 |
| 嵌入 (Embeddings) | 将一段文本转化为一个向量表示,可以做一些语义搜索,相似性搜索。在 LangChain 中,基础的 Embeddings 类提供了两种方法:嵌入文档和嵌入查询。 |
| 向量存储库 (Vector Store) | 负责存储嵌入数据并执行向量搜索。查询'最相似'的嵌入向量。 |
| Retriever | 一个接口,它可以根据非结构化查询返回文档。它比向量存储更为通用。Retriever 不需要存储文档,只需要返回(或检索)文档。向量存储可以作为 Retriever 的基础。 |

代码案例可以在仓库中看到。
Chain 是一种用于构建复杂 LLM 应用的工具,可以将多个语言模型(LLMs)或其他组件链接在一起。Chain 基本的接口包括一个内存(memory)属性,一个回调(callbacks)属性,以及一个 __call__ 方法,这个方法接受输入,返回一个字典。目前内置的几种常用 Chain:

LangChain 也已经内置了一些专门用作特定功能的 Chain,在处理数据上定义的几种不同形式的 Chain_Type。
| 名称 | 说明 |
|---|---|
| Stuff Documents Chain | 这是最直接的文档链。它接收一系列文档,将它们全部插入到一个提示中,然后将该提示传递给一个 LLM。这个链适合于文档较小且大多数调用只传入少量文档的应用。 |
| Refine Documents Chain | 这个链通过循环处理输入文档并迭代更新其答案来构建响应。对于每个文档,它将所有非文档输入、当前文档和最新的中间答案传递给一个 LLM 链以获取新的答案。这个链适合需要分析比模型上下文可以容纳的更多文档的任务。 |
| Map Reduce Documents Chain | 这个链首先将一个 LLM 链单独应用到每个文档上(Map 步骤),将链输出视为新的文档。然后,它将所有新的文档传递给一个单独的 combine documents 链,以获取单一的输出(Reduce 步骤)。如果需要,它可以首先压缩或折叠映射的文档,以确保它们适合在 combine documents 链中。 |
| Map Re-rank Documents Chain | 这个链首先在每个文档上运行一个初始提示,该提示不仅试图完成任务,而且还给出了对其答案的确定程度的评分。返回得分最高的响应。 |

Chains 和 Agents 默认是无状态的,也就是每次对话都是独立的。但是在某些应用中,如聊天机器人,记住之前的交互是至关重要的,无论是短期还是长期。这就是 Memory 的作用。
LangChain 也提供一些不同类型的 Memory,方便用在不同的场景中,用在 Chain 或者 Agent 中;

Agent 的核心思想是使用语言模型(LLM)来选择要执行的一系列动作。在链(chains)中,动作序列是硬编码的(在代码中)。在 agents 中,语言模型被用作推理引擎,以确定要执行哪些动作以及执行的顺序。几个关键组件:
Agent 根据 LLM 判断应该采用那个 Tool,然后调用 Tool,再向用户输出响应。


有两种类型的 Agent:
在初始化 Agent 的时候,指定 Agent 的 Type,关于 agent 的 Type。主要会有 Action 的 Agent 比较多
initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
一些 Action Agent 的类型:
| 名称 | 说明 |
|---|---|
| Zero-shot ReAct | 仅根据工具的描述来确定使用哪个工具。要求为每个 Tool 提供一个描述,不限制 Tool 数量。 |
| Structured input ReAct | 能够使用多输入工具,结构化的参数输入。 |
| Conversational | 为对话设置设计的 Agent,使用 Memory 来记住之前的对话交互。 |
| Self ask with search | 自问自答,会使用 Google 搜索工具。 |
| ReAct document store | 用于和文档进行交互的 Agent。必须提供两个 Tool:一个搜索工具和一个查找工具。搜索工具应该搜索文档,而查找工具应该在最近找到的文档中查找一个术语。 |
| OpenAI Functions | 某些 OpenAI 模型(如 gpt-3.5-turbo-0613 和 gpt-4-0613)已经明确地进行了微调,如果使用这些模型,可以考虑使用 OpenAI Functions 的 AgentType。 |
LangChain 是一个方便开发大语言模型(LLM)应用和代理(Agents)的工具。然而,将 LLM 应用部署到生产环境可能会遇到许多困难。需要对你的提示(prompts)、链(chains)和其他组件进行大量的定制和迭代,才能创建出高质量的产品。
最简单的调试方式:设置 langchain.debug 和 langchain.verbose。
LangChain 官方推出了 LangSmith:用于更方便的构建生产级别的 LLM 应用。它允许您调试、测试、评估和监控基于任何 LLM 框架构建的链和智能代理,并与 LangChain 无缝集成。除了 LangSmith,还有另外一个工具 WanDB 用于方便我们调试大模型的应用。
关于 WanDB
os.environ["LANGCHAIN_WANDB_TRACING"] = "true" 使用 wandb_tracing_enabled() 追踪特定块的代码。
有时候写 LLM 应用,发现返回的不符合预期,可以从这里看到输入的 Prompt,了解每个过程;或者想要学习专家们是如何写 Prompt 的都可以在这里看到。


实现了一个基于语言模型的文本生成图片工具,调用不同的工具函数来最终生成图片。主要提供了以下几个工具:
random_poem:随机返回中文的诗词。prompt_generate:根据中文提示词生成对应的英文提示词。generate_image:根据英文提示词生成对应的图片。import base64
import json
import os
from io import BytesIO
import requests
from PIL import Image
from pydantic import BaseModel, Field
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI
from langchain.tools import BaseTool, StructuredTool, Tool, tool
from langchain import LLMMathChain, SerpAPIWrapper
def generate_image(prompt: str) -> str:
"""
根据提示词生成对应的图片
Args:
prompt (str): 英文提示词
Returns:
str: 图片的路径
"""
url = "http://127.0.0.1:7860/sdapi/v1/txt2img"
headers = {
"accept": "application/json",
"Content-Type": "application/json"
}
data = {
"prompt": prompt,
"negative_prompt": "(worst quality:2), (low quality:2),disfigured, ugly, old, wrong finger",
"steps": 20,
"sampler_index": "Euler a",
"sd_model_checkpoint": "cheeseDaddys_35.safetensors [98084dd1db]",
# "sd_model_checkpoint": "anything-v3-fp16-pruned.safetensors [d1facd9a2b]",
"batch_size": 1,
"restore_faces": True
}
response = requests.post(url, headers=headers, data=json.dumps(data))
if response.status_code == 200:
response_data = response.json()
images = response_data['images']
for index, image_data in enumerate(images):
img_data = base64.b64decode(image_data)
img = Image.open(BytesIO(img_data))
file_name = f"image_{index}.png"
file_path = os.path.join(os.getcwd(), file_name)
img.save(file_path)
print(f"Generated image saved at {file_path}")
return file_path
else:
print(f"Request failed with status code {response.status_code}")
def random_poem(arg: str) -> str:
"""
随机返回中文的诗词
Returns:
str: 随机的中文诗词
"""
llm = OpenAI(temperature=0.9)
text = """
能否帮我从中国的诗词数据库中随机挑选一首诗给我,希望是有风景,有画面的诗:
比如:山重水复疑无路,柳暗花明又一村。
"""
return llm(text)
def prompt_generate(idea: str) -> str:
"""
生成图片需要对应的英文提示词
Args:
idea (str): 中文提示词
Returns:
str: 英文提示词
"""
llm = OpenAI(temperature=0, max_tokens=2048)
res = llm(f"""
Stable Diffusion is an AI art generation model similar to DALLE-2.
Below is a list of prompts that can be used to generate images with Stable Diffusion:
- portait of a homer simpson archer shooting arrow at forest monster, front game card, drark, marvel comics, dark, intricate, highly detailed, smooth, artstation, digital illustration by ruan jia and mandy jurgens and artgerm and wayne barlowe and greg rutkowski and zdislav beksinski
- pirate, concept art, deep focus, fantasy, intricate, highly detailed, digital painting, artstation, matte, sharp focus, illustration, art by magali villeneuve, chippy, ryan yee, rk post, clint cearley, daniel ljunggren, zoltan boros, gabor szikszai, howard lyon, steve argyle, winona nelson
- ghost inside a hunted room, art by lois van baarle and loish and ross tran and rossdraws and sam yang and samdoesarts and artgerm, digital art, highly detailed, intricate, sharp focus, Trending on Artstation HQ, deviantart, unreal engine 5, 4K UHD image
- red dead redemption 2, cinematic view, epic sky, detailed, concept art, low angle, high detail, warm lighting, volumetric, godrays, vivid, beautiful, trending on artstation, by jordan grimmer, huge scene, grass, art greg rutkowski
- a fantasy style portrait painting of rachel lane / alison brie hybrid in the style of francois boucher oil painting unreal 5 daz. rpg portrait, extremely detailed artgerm greg rutkowski alphonse mucha greg hildebrandt tim hildebrandt
- athena, greek goddess, claudia black, art by artgerm and greg rutkowski and magali villeneuve, bronze greek armor, owl crown, d & d, fantasy, intricate, portrait, highly detailed, headshot, digital painting, trending on artstation, concept art, sharp focus, illustration
- closeup portrait shot of a large strong female biomechanic woman in a scenic scifi environment, intricate, elegant, highly detailed, centered, digital painting, artstation, concept art, smooth, sharp focus, warframe, illustration, thomas kinkade, tomasz alen kopera, peter mohrbacher, donato giancola, leyendecker, boris vallejo
- ultra realistic illustration of steve urkle as the hulk, intricate, elegant, highly detailed, digital painting, artstation, concept art, smooth, sharp focus, illustration, art by artgerm and greg rutkowski and alphonse mucha
I want you to write me a list of detailed prompts exactly about the idea written after IDEA. Follow the structure of the example prompts. This means a very short description of the scene, followed by modifiers divided by commas to alter the mood, style, lighting, and more.
IDEA: {idea}""")
return res
class PromptGenerateInput(BaseModel):
"""
生成英文提示词所需的输入模型类
"""
idea: str = Field()
class GenerateImageInput(BaseModel):
"""
生成图片所需的输入模型类
"""
prompt: str = Field(description="英文提示词")
tools = [
Tool.from_function(
func=random_poem,
name="诗歌获取",
description="随机返回中文的诗词"
),
Tool.from_function(
func=prompt_generate,
name="提示词生成",
description="生成图片需要对应的英文提示词,当前工具可以将输入转换为英文提示词,以便方便生成",
args_schema=PromptGenerateInput
),
Tool.from_function(
func=generate_image,
name="图片生成",
description="根据提示词生成对应的图片,提示词需要是英文的,返回是图片的路径",
args_schema=GenerateImageInput
),
]
def main():
"""
主函数,初始化代理并执行对话
"""
llm = OpenAI(temperature=0)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("帮我生成一张诗词的图片?")
if __name__ == '__main__':
main()


import os
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.indexes import VectorstoreIndexCreator
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.llms import OpenAI
# 设置代理
os.environ['HTTP_PROXY'] = 'socks5h://127.0.0.1:13659'
os.environ['HTTPS_PROXY'] = 'socks5h://127.0.0.1:13659'
# 创建文本加载器
loader = TextLoader('/Users/aihe/Downloads/demo.txt', encoding='utf8')
# 加载文档
documents = loader.load()
# 文本分块
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
# 计算嵌入向量
embeddings = OpenAIEmbeddings()
# 创建向量库
db = Chroma.from_documents(texts, embeddings)
# 将向量库转换为检索器
retriever = db.as_retriever()
# 创建检索问答系统
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=retriever)
# 运行问题答案检索
query = "如何申请租户?"
print(qa.run(query))
print(qa.run("能否说明下你可以提供的功能?"))

import requests
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI
from langchain.tools import StructuredTool
from pydantic import BaseModel, Field
def post_message(type: str, param: dict) -> str:
"""
当需要生成人群、分析画像、咨询问题时,使用如下的指示:url 固定为:http://localhost:3001/
如果请求是生成人群,请求的 type 为 crowd; 如果请求是分析画像,请求的 type 为 analyze; 如果是其他或者答疑,请求的 type 为 question;
请求 body 的 param 把用户指定的条件传进来即可
"""
result = requests.post("http://localhost:3001/", json={"type": type, "param": param})
return f"Status: {result.status_code} - {result.text}"
class PostInput(BaseModel):
# body: dict = Field(description="""格式:{"type":"","param":{}}""")
type: str = Field(description="请求的类型,人群为 crowd,画像为 analyze")
param: dict = Field(description="请求的具体描述")
llm = ChatOpenAI(temperature=0)
tools = [
StructuredTool.from_function(post_message)
]
agent = initialize_agent(tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("我想生成一个性别为男并且在 180 天访问过淘特的人群?")

原本做聊天机器人,需要一些前端代码,但是已经有相应的开源工具,帮我们把 LangChian 的各种组件做了可视化,直接拖拽即可,我们直接使用 LangFlow;
pip install langflow
然后运行命令:
langflow
在界面上配置 LangChain 的三个组件:在最右下角是对应的聊天窗口,输入下 openai 的 key。

开始聊天验证下我们的配置:
全程基本上不用怎么写代码,只需要了解 LangChain 的组件是做什么的,基本上就可以搭出一款简单的聊天机器人。
其它的 LangChain 组件代理,内存,数据索引也是都可以使用的。
可以参考本仓库的 practice 目录。
其它可以尝试的应用:
在实际生产环境中使用 LangChain 时,需要注意以下几点以确保系统的稳定性和性能:
ainvoke 和 astream 等方法。Refine 或 Map-Reduce 策略,避免超出上下文窗口导致额外费用。本文介绍了 LangChain 框架,它能够将大型语言模型与其他计算或知识来源相结合,从而实现功能更加强大的应用。接着,对 LangChain 的关键概念进行了详细说明,并基于该框架进行了一些案例尝试,旨在帮助读者更轻松地理解 LangChain 的工作原理。
展望未来,LangChain 有望在各个领域发挥巨大作用,促进我们工作效率的变革。随着更多的工具和资源与 LangChain 进行集成,大语言模型对人的生产力将会有更大的提升。我们正处于 AI 爆发的前夜,积极拥抱新技术将会带来完全不同的感觉。

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