1、LangChain是什么

LangChain是一个结构,用于开发由LLM驱动的运用程序。能够简略认为是LLM范畴的Spring,以及开源版的ChatGPT插件系统。中心的2个功能为:

1)能够将 LLM 模型与外部数据源进行连接。

2)答应与 LLM 模型与环境进行交互,经过Agent运用东西。

LangChain:打造自己的LLM应用 | 京东云技术团队

2、LangChain中心组件

LangChain供给了各种不同的组件帮助运用LLM,如下图所示,中心组件有Models、Indexes、Chains、Memory以及Agent。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.1 Models

LangChain自身不供给LLM,供给通用的接口拜访LLM,能够很便利的替换底层的LLM以及自定义自己的LLM。首要有2大类的Models:

1)LLM:将文本字符串作为输入并回来文本字符串的模型,相似OpenAI的text-davinci-003

2)Chat Models:由语言模型支撑但将谈天消息列表作为输入并回来谈天消息的模型。一般运用的ChatGPT以及Claude为Chat Models。

与模型交互的,根本上是经过给与Prompt的办法,LangChain经过PromptTemplate的办法便利我们构建以及复用Prompt。

from langchain import PromptTemplate
prompt_template = '''作为一个资深修改,请针对 >>> 和 <<< 中心的文本写一段摘要。 
>>> {text} <<<
'''
prompt = PromptTemplate(template=prompt_template, input_variables=["text"])
print(prompt.format_prompt(text="我爱北京天安门"))

2.2 Indexes

索引和外部数据进行集成,用于从外部数据获取答案。如下图所示,首要的过程有

1)经过Document Loaders加载各种不同类型的数据源,

2)经过Text Splitters进行文本语义切割

3)经过Vectorstore进行非结构化数据的向量存储

4)经过Retriever进行文档数据检索

LangChain:打造自己的LLM应用 | 京东云技术团队

2.2.1 Document Loaders

LangChain经过Loader加载外部的文档,转化为规范的Document类型。Document类型首要包括两个特点:page_content 包括该文档的内容。meta_data 为文档相关的描绘性数据,相似文档所在的途径等。

如下图所示:LangChain现在支撑结构化、非结构化以及公开以及私有的各种数据

LangChain:打造自己的LLM应用 | 京东云技术团队

2.2.2 Text Splitters

LLM一般都会约束上下文窗口的巨细,有4k、16k、32k等。针对大文本就需求进行文本切割,常用的文本切割器为RecursiveCharacterTextSplitter,能够经过separators指定分隔符。其先经过第一个分隔符进行切割,不满足巨细的情况下迭代切割。

文本切割首要有2个考虑:

1)将语义相关的语句放在一块构成一个chunk。一般依据不同的文档类型定义不同的分隔符,或者能够挑选经过模型进行切割。

2)chunk控制在必定的巨细,能够经过函数去计算。默许经过len函数计算,模型内部一般都是运用token进行计算。token一般指的是将文本或序列数据划分红的小的单元或符号,便于机器了解和处理。运用OpenAI相关的大模型,能够经过tiktoken包去计算其token巨细。

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-3.5-turb
    allowed_special="all",
    separators=["\n\n", "\n", "。", ","],
    chunk_size=7000,
    chunk_overlap=0
)
docs = text_splitter.create_documents(["文本在这里"])
print(docs)

2.2.3 Vectorstore

经过Text Embedding models,将文本转为向量,能够进行语义搜索,在向量空间中找到最相似的文本片段。现在支撑常用的向量存储有Faiss、Chroma等。

Embedding模型支撑OpenAIEmbeddings、HuggingFaceEmbeddings等。经过HuggingFaceEmbeddings加载本地模型能够节约embedding的调用费用。

#经过cache_folder加载本地模型
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="本地模型地址")
embeddings = embeddings_model.embed_documents(
    [
        "我爱北京天安门!",
        "Hello world!"
    ]
)

2.2.4 Retriever

Retriever接口用于依据非结构化的查询获取文档,一般情况下是文档存储在向量数据库中。能够调用 get_relevant_documents 办法来检索与查询相关的文档。

from langchain import FAISS
from langchain.document_loaders import WebBaseLoader
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
loader = WebBaseLoader("https://in.m.jd.com/help/app/register_info.html")
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-3.5-turbo",
    allowed_special="all",
    separators=["\n\n", "\n", "。", ","],
    chunk_size=800,
    chunk_overlap=0
)
docs = text_splitter.split_documents(data)
#经过cache_folder设置自己的本地模型途径
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="models")
vectorstore = FAISS.from_documents(docs, embeddings)
result = vectorstore.as_retriever().get_relevant_documents("用户注册资历")
print(result)
print(len(result))

2.3 Chains

Langchain经过chain将各个组件进行链接,以及chain之间进行链接,用于简化复杂运用程序的完成。其间首要有LLMChain、Sequential Chain以及Route Chain

2.3.1 LLMChain

最根本的链为LLMChain,由PromptTemplate、LLM和OutputParser组成。LLM的输出一般为文本,OutputParser用于让LLM结构化输出并进行成果解析,便利后续的调用。

LangChain:打造自己的LLM应用 | 京东云技术团队

相似下面的示例,给评论进行关键词提早以及心情分析,经过LLMChain组合PromptTemplate、LLM以及OutputParser,能够很简略的完成一个之前经过依赖小模型不断需求调优的工作。

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
from azure_chat_llm import llm
#output parser
keyword_schema = ResponseSchema(name="keyword", description="评论的关键词列表")
emotion_schema = ResponseSchema(name="emotion", description="评论的心情,正向为1,中性为0,负向为-1")
response_schemas = [keyword_schema, emotion_schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()
#prompt template
prompt_template_txt = '''
作为资深客服,请针对 >>> 和 <<< 中心的文本辨认其间的关键词,以及包括的心情是正向、负向还是中性。
>>> {text} <<<
RESPONSE:
{format_instructions}
'''
prompt = PromptTemplate(template=prompt_template_txt, input_variables=["text"],
                        partial_variables={"format_instructions": format_instructions})
#llmchain
llm_chain = LLMChain(prompt=prompt, llm=llm)
comment = "京东物流没的说,速度态度都是杠杠滴!这款路由器颜值贼高,怎么说呢,便是泰裤辣!这线条,这质感,这速度,嘎嘎快!以后妈妈再也不必担心家里的网速了!"
result = llm_chain.run(comment)
data = output_parser.parse(result)
print(f"type={type(data)}, keyword={data['keyword']}, emotion={data['emotion']}")

输出:

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.2 Sequential Chain

SequentialChains是按预定义次序履行的链。SimpleSequentialChain为次序链的最简略办法,其间每个过程都有一个单一的输入/输出,一个过程的输出是下一个过程的输入。SequentialChain 为次序链更通用的办法,答应多个输入/输出。

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains import SimpleSequentialChain
first_prompt = PromptTemplate.from_template(
    "翻译下面的内容到中文:"
    "\n\n{content}"
)
# chain 1: 输入:Review 输出: 英文的 Review
chain_trans = LLMChain(llm=llm, prompt=first_prompt, output_key="content_zh")
second_prompt = PromptTemplate.from_template(
    "一句话总结下面的内容:"
    "\n\n{content_zh}"
)
chain_summary = LLMChain(llm=llm, prompt=second_prompt)
overall_simple_chain = SimpleSequentialChain(chains=[chain_trans, chain_summary],verbose=True)
content = '''In a blog post authored back in 2011, Marc Andreessen warned that, “Software is eating the world.” Over a decade later, we are witnessing the emergence of a new type of technology that’s consuming the world with even greater voracity: generative artificial intelligence (AI). This innovative AI includes a unique class of large language models (LLM), derived from a decade of groundbreaking research, that are capable of out-performing humans at certain tasks. And you don’t have to have a PhD in machine learning to build with LLMs—developers are already building software with LLMs with basic HTTP requests and natural language prompts.
In this article, we’ll tell the story of GitHub’s work with LLMs to help other developers learn how to best make use of this technology. This post consists of two main sections: the first will describe at a high level how LLMs function and how to build LLM-based applications. The second will dig into an important example of an LLM-based application: GitHub Copilot code completions.
Others have done an impressive job of cataloging our work from the outside. Now, we’re excited to share some of the thought processes that have led to the ongoing success of GitHub Copilot.
'''
result = overall_simple_chain.run(content)
print(f'result={result}')

输出:

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.3 Router Chain

RouterChain是依据输入动态的挑选下一个链,每条链处理特定类型的输入。

RouterChain由两个组件组成:

1)路由器链自身,担任挑选要调用的下一个链,首要有2种RouterChain,其间LLMRouterChain经过LLM进行路由决议计划,EmbeddingRouterChain 经过向量搜索的办法进行路由决议计划。

2)方针链列表,路由器链能够路由到的子链。

初始化RouterChain以及destination_chains完成后,经过MultiPromptChain将两者结合起来运用。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.4 Documents Chain

下面的4种Chain首要用于Document的处理,在根据文档生成摘要、根据文档的问答等场景中经常会用到,在后续的落地实践里也会有所体现。

2.3.4.1 Stuff

StuffDocumentsChain这种链最简略直接,是将一切获取到的文档作为context放入到Prompt中,传递到LLM获取答案。

这种办法能够完好的保留上下文,调用LLM的次数也比较少,建议能运用stuff的就运用这种办法。其适合文档拆分的比较小,一次获取文档比较少的场景,不然容易超过token的约束。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.4.2 Refine

RefineDocumentsChain是经过迭代更新的办法获取答案。先处理第一个文档,作为context传递给llm,获取中心成果intermediate answer。然后将第一个文档的中心成果以及第二个文档发给llm进行处理,后续的文档相似处理。

Refine这种办法能部分保留上下文,以及token的运用能控制在必定范围。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.4.3 MapReduce

MapReduceDocumentsChain先经过LLM对每个document进行处理,然后将一切文档的答案在经过LLM进行兼并处理,得到最终的成果。

MapReduce的办法将每个document单独处理,能够并发进行调用。但是每个文档之间缺少上下文。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.3.4.4 MapRerank

MapRerankDocumentsChain和MapReduceDocumentsChain相似,先经过LLM对每个document进行处理,每个答案都会回来一个score,最终挑选score最高的答案。

MapRerank和MapReduce相似,会大批量的调用LLM,每个document之间是独立处理。

LangChain:打造自己的LLM应用 | 京东云技术团队

2.4 Memory

正常情况下Chain无状况的,每次交互都是独立的,无法知道之前前史交互的信息。LangChain运用Memory组件保存和办理前史消息,这样能够跨多轮进行对话,在当前会话中保留前史会话的上下文。Memory组件支撑多种存储介质,能够与Monogo、Redis、SQLite等进行集成,以及简略直接办法便是Buffer Memory。常用的Buffer Memory有

1)ConversationSummaryMemory :以摘要的信息保存记载

2)ConversationBufferWindowMemory:以原始办法保存最新的n条记载

3)ConversationBufferMemory:以原始办法保存一切记载

经过检查chain的prompt,能够发现{history}变量传递了从memory获取的会话上下文。下面的示例演示了Memory的运用办法,能够很明细看到,答案是从之前的问题里获取的。

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
from azure_chat_llm import llm
memory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=memory, verbose=True)
print(conversation.prompt)
print(conversation.predict(input="我的姓名是tiger"))
print(conversation.predict(input="1+1=?"))
print(conversation.predict(input="我的姓名是什么"))

输出:

LangChain:打造自己的LLM应用 | 京东云技术团队

2.5 Agent

Agent字面意义便是署理,如果说LLM是大脑,Agent便是署理大脑运用东西Tools。现在的大模型一般都存在知识过时、逻辑计算能力低一级问题,经过Agent拜访东西,能够去解决这些问题。现在这个范畴特别活跃,诞生了相似AutoGPT、BabyAGI、AgentGPT等一堆优异的项目。传统运用LLM,需求给定Prompt一步一步的到达方针,经过Agent是给定方针,其会主动规划并到达方针。

2.5.1 Agent中心组件

Agent:署理,担任调用LLM以及决议下一步的Action。其间LLM的prompt有必要包括agent_scratchpad变量,记载履行的中心过程

Tools:东西,Agent能够调用的办法。LangChain已有许多内置的东西,也能够自定义东西。留意Tools的description特点,LLM会经过描绘决议是否运用该东西。

ToolKits:东西集,为特定意图的东西集合。相似Office365、Gmail东西集等

Agent Executor:Agent履行器,担任进行实际的履行。

2.5.2 Agent的类型

一般经过initialize_agent函数进行Agent的初始化,除了llm、tools等参数,还需求指定AgentType。

agent = initialize_agent(agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
                tools=tools,
                llm=llm,
                verbose=True)
print(agent.agent.llm_chain.prompt.template)

该Agent为一个zero-shot-react-description类型的Agent,其间zero-shot标明只考虑当前的操作,不会记载以及参阅之前的操作。react标明经过ReAct结构进行推理,description标明经过东西的description进行是否运用的决议计划。

其他的类型还有chat-conversational-react-description、conversational-react-description、react-docstore、self-ask-with-search等,相似chat-conversational-react-description经过memory记载之前的对话,应对会参阅之前的操作。

能够经过agent.agent.llm_chain.prompt.template办法,获取其推理决议计划所运用的模板。

2.5.3 自定义Tool

有多种办法能够自定义Tool,最简略的办法是经过@tool装饰器,将一个函数转为Tool。留意函数有必要得有docString,其为Tool的描绘。

from azure_chat_llm import llm
from langchain.agents import load_tools, initialize_agent, tool
from langchain.agents.agent_types import AgentType
from datetime import date
@tool
def time(text: str) -> str:
    """
    回来今天的日期。
    """
    return str(date.today())
tools = load_tools(['llm-math'], llm=llm)
tools.append(time)
agent_math = initialize_agent(agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
                                   tools=tools,
                                   llm=llm,
                                   verbose=True)
print(agent_math("计算45 * 54"))
print(agent_math("今天是哪天?"))

输出为:

LangChain:打造自己的LLM应用 | 京东云技术团队

3、LangChain落地实践

3.1 文档生成总结

1)经过Loader加载长途文档

2)经过Splitter根据Token进行文档拆分

3)加载summarize链,链类型为refine,迭代进行总结

from langchain.prompts import PromptTemplate
from langchain.document_loaders import PlaywrightURLLoader
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from azure_chat_llm import llm
loader = PlaywrightURLLoader(urls=["https://content.jr.jd.com/article/index.html?pageId=708258989"])
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-3.5-turbo",
    allowed_special="all",
    separators=["\n\n", "\n", "。", ","],
    chunk_size=7000,
    chunk_overlap=0
)
prompt_template = '''
作为一个资深修改,请针对 >>> 和 <<< 中心的文本写一段摘要。 
>>> {text} <<<
'''
refine_template = '''
作为一个资深修改,根据已有的一段摘要:{existing_answer},针对 >>> 和 <<< 中心的文本完善现有的摘要。 
>>> {text} <<<
'''
PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
REFINE_PROMPT = PromptTemplate(
    template=refine_template, input_variables=["existing_answer", "text"]
)
chain = load_summarize_chain(llm, chain_type="refine", question_prompt=PROMPT, refine_prompt=REFINE_PROMPT, verbose=False)
docs = text_splitter.split_documents(data)
result = chain.run(docs)
print(result)

3.2 根据外部文档的问答

1)经过Loader加载长途文档

2)经过Splitter根据Token进行文档拆分

3)经过FAISS向量存储文档,embedding加载HuggingFace的text2vec-base-chinese模型

4)自定义QA的prompt,经过RetrievalQA回答相关的问题

from langchain.chains import RetrievalQA
from langchain.document_loaders import WebBaseLoader
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.prompts import PromptTemplate
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from azure_chat_llm import llm
loader = WebBaseLoader("https://in.m.jd.com/help/app/register_info.html")
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    model_name="gpt-3.5-turbo",
    allowed_special="all",
    separators=["\n\n", "\n", "。", ","],
    chunk_size=800,
    chunk_overlap=0
)
docs = text_splitter.split_documents(data)
#设置自己的模型途径
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="model")
vectorstore = FAISS.from_documents(docs, embeddings)
template = """请运用下面供给的布景信息来回答最终的问题。 如果你不知道答案,请直接说不知道,不要试图凭空编造答案。
回答时最多运用三个语句,坚持回答尽可能简洁。 回答结束时,请必定要说"谢谢你的发问!"
{context}
问题: {question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context", "question"], template=template)
qa_chain = RetrievalQA.from_chain_type(llm, retriever=vectorstore.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt": QA_CHAIN_PROMPT})
result = qa_chain({"query": "用户注册资历"})
print(result["result"])
print(len(result['source_documents']))

4、未来开展方向

跟着大模型的开展,LangChain应该是现在最火的LLM开发结构,能和外部数据源交互、能集成各种常用的组件等等,大大下降了LLM运用开发的门槛。其创始人Harrison Chase也和Andrew Ng联合开发了2门短课程,帮助我们快速把握LangChain的运用。

现在大模型的迭代升级特别快,作为一个结构,LangChain也得坚持特别快的迭代速度。其开发特别拼,每天都会提交很多的commit,根本隔几天就会发布一个新版本,其Contributor也到达了1200多人,特别活跃。

个人认为,除了和事务结合落地LLM运用外,还有2个大的方向能够进一步去探索:

1)经过低代码的办法进一步下降LLM运用的开发门槛。相似langflow这样的可视化编排东西开展也很快

2)打造更加强大的Agent。Agent之于大模型,个人觉得相似SQL之于DB,能大幅度提高LLM的运用场景

5、参阅资料

1、python.langchain.com/docs/get_st…

2、github.com/liaokongVFX…

3、www.deeplearning.ai/short-cours…

4、lilianweng.github.io/posts/2023-…

5、mp.weixin.qq.com/s/3coFhAdzr…

6、github.com/langchain-a…

作者:京东科技 杨虎

来历:京东云开发者社区