langchain 基于 0.0.109 版本
一个基于LLMs的应用程序开发框架, 通过可组合性来使用LLM构建应用程序. 其重点在于"可组合性"
大型语言模型 (LLM) 正在作为一种变革性技术出现,使开发人员能够构建他们以前无法构建的应用程序。但是单独使用这些 LLM 通常不足以创建真正强大的应用程序,当可以将它们与其他计算或知识来源相结合时,就有真的价值了。LangChain 旨在协助开发这些类型的应用程序.
其主要包含六个部分:
- LLMs和prompt, 对所有大模型的通用交互接口, 以及prompt管理,优化等等
- chains, 一系列的调用(LLMs或者其他, 如网络, 操作系统), chains提供了标准的接口和设置来组合这些调用.
- data augmented generation 基于特定数据的内容生成, 一种特殊的chain, 提供了一种能力: 先从外部的源获取信息, 然后喂给LLMs
- agents, 代理, 非常重要的一环, 关于对LLMs做何种action, 如何做
- memory 标准的接口, 在chains/call之间保存状态
- Evaluation 提供了一些prompts/chains来利用模型来评估自身
prompt templates
ChatGPT 提供了通过 prompts 来进行提示的方法,也就是在发起请求时,可以带上一段信息。由于是一个聊天接口,因此可以包含多个聊天的内容。其中包括来自系统的提示:例如用来描述一下 ChatGPT 现在是什么角色,应该具有什么样的语言风格等。另外还可以包含一些用户的历史聊天记录,就像背景知识一类的,都可以作为用户的输入带进去,这样可以使得 ChatGPT 在本次聊天中具有了领域知识与上下文信息。通过这种 prompts 的方式,可以对 ChatGPT 有一定的定制能力,并使用其大模型的自然语言能力来组织回答信息。
prompt template是简化和用户的交互, 用户提出核心问题, template 渲染问题, 增加上下文信息, 历史聊天信息, 背景知识等等.
chains
简单应用可能对LLM进行一次调用即可, 而复杂应用往往需要串联LLMs(相互连接或者和其他的专家系统). langchain为此提供了一套标准的接口和通用的实现.
chain还细分为两类: 通用任务chain 和 专有工具chain ,前者更多用来组织任务顺序, 后者则专注在对某个工具的调用上.
- LLMChain: 简单接受template和用户输入, 调用LLM, 返回输出
- SequentialChain: 组合chains, 发起一系列且有顺序的调用请求
SimpleSequentialChain(chains=[chain, chain_two], verbose=True)
- BashChain: 使用LLMs 以及 调用bash命令
- LLMRequestsChain: 发起调用, 之后将结果输送给后来的chain.
- .........
- 自定义chain:
- 继承Chain
- 实现input_keys和output_keys (前者接收先前chains的输出, 后者给到后来chains作为输入)
- 补全调用实现_call ( _call是chain运行会调用的方法)
chain可以很简单地理解为 过程的抽象, chains的可组合性, 就是过程的组合.
agents
use LLM to determine which actions to take and in what order. An action can either be using a tool and observing its output, or returning to the user.
搭配上能理解用户输入的大模型, agents接受大模型输出的指令, 可以打造强大的个人助理程序.
concepts
Tool : A function that performs a specific duty. This can be things like: Google Search, Database lookup, Python REPL, other chains. The interface for a tool is currently a function that is expected to have a string as an input, with a string as an output.
工具, 可以执行某种特定任务. 当下, 可以理解为一个 string => string的函数. 内置的工具:
https://langchain.readthedocs.io/en/latest/modules/agents/tools.html
可以: 发起调用, http请求, 搜索内容, 执行代码(python), etc.
LLM : The language model powering the agent.
Agent : The agent to use. This should be a string that references a support agent class. Because this notebook focuses on the simplest, highest level API, this only covers using the standard supported agents. If you want to implement a custom agent, see the documentation for custom agents (coming soon).
用来调用工具的代理, 如果标准库里没有合适的工具代理, 可以自定义.
内置代理类型:
- zero-shot-react-description 根据工具的描述, 和请求的string 来决定使用哪个工具
- react-docstore 使用react框架, 和docstore交互, 使用
Search
和Lookup
工具, 前者用来搜, 后者寻找term, 举例: Wipipedia工具 - self-ask-with-search 此代理只使用一个工具: Intermediate Answer, 它会为问题寻找事实答案(指的非gpt生成的答案, 而是在网络中,文本中已存在的), 如
Google search API
工具 - conversational-react-description 为会话设置而设计的代理, 它的prompt会被设计的具有会话性, 且还是会使用 ReAct框架来决定使用来个工具, 并且将过往的会话交互存入内存.
https://langchain.readthedocs.io/en/latest/modules/agents/agents.html
举例
与向量数据库交互
希望应用程序, 在使用LLM的过程中, 和向量数据库交互(其实, 不用langchain库, 自己编写很简单的代码就可以做到) 只是langchain库在多数向量库之上, 包装了一层统一的交互接口.
https://langchain.readthedocs.io/en/latest/modules/agents/examples/agent_vectorstore.html
如下代码所示 , 两个tool被创建, 组合成工具包, 两个工具, 分别是"SOU的qa"和 "Ruff的qa", 他们会分别阅读SOU和Ruff网站的内容, 并且调用LLM的向量接口, 生成向量, 存于本地数据库. 然后使用特定种类的agent作为某种路由, 可以按工具描述使用他们.
tools = [
Tool(
name = "State of Union QA System",
func=state_of_union.run,
description="useful for when you need to answer questions about the most recent state of the union address. Input should be a fully formed question."
),
Tool(
name = "Ruff QA System",
func=ruff.run,
description="useful for when you need to answer questions about ruff (a python linter). Input should be a fully formed question."
),
]
agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
agent.run("What did biden say about ketanji brown jackson is the state of the union address?")
先搜再问 - data agumented generation
对于某些大模型没有的信息或者知识, 如果要补充这些信息, 需要重新训练模型, 成本比较高, 但是可以通过prompt的方式给到它, langchain为了方便上层开发应用, 设计了self-ask-with-search代理, 即先到某个知识库去获取相关的信息和知识, 然后利用LLM来理解这些知识和信息,然后回答用户的问题.
memory
chain和agent是无状态的, LLM模型也是, 所以需要prompt来进行历史提示.
Chains and Agents are stateless, meaning that they treat each incoming query independently (as are the underlying LLMs and chat models).
memory模块提供了两种能力:
- 模块化管理和操作先前的对话的工具
- 将这些工具集成到chain里的设施
示例
https://langchain.readthedocs.io/en/latest/modules/memory/types/buffer.html
从示例中可以看出, langchain将对话保存在模块化的memory中, 并且在predict的时候, 自动带上历史会话, 作为prompt.
总结
关于agent和chains的差异,尤其是utils chain
agent是关于对LLM做何种action, 怎么做action, 在于挑选工具. chain重点是对输入做处理 , 并且组织各个过程的顺序.
data augemented generation
LLMs是基于大量非结构化的语料训练的, 所以对通用的nlp任务有很好的的效果, 然而很多时候, 我们需要的不是在利用通用数据来生成结果, 而是基于特定的数据来产生结果.
- Summarization of a specific piece of text (a website, a private document, etc.)
- Question answering over a specific piece of text (a website, a private document, etc.)
- Question answering over multiple pieces of text (multiple websites, multiple private documents, etc.)
- Using the results of some external call to an API (results from a SQL query, etc.)
即, 不希望模型仅仅通过其训练的数据来生成文本, 而要把某些外部的数据也结合进去, 所以步骤可以拆解为两步:
- fetching: 取回
- user provided
- document retrival
- api querying
- augmenting: 传递给LLM
fetching
在fetching过程中, 比较重要的是取回的文档不能太大, 因为目前的模型都对输入的长度有限制, 所以 langchain提供了各种工具来split文档成一片一片, 并且控制每片中的内容重叠(保持上下文). 另外一个是, 不能取回太多的文档, 最好只选取和问题相关的文档, 即相关度要高, 有比较多的方式来做这件事, 当下比较流行的是:
在语义搜索和Q&A系统中, 将语料的doc切分成chunk, 将chunk向量化, 然后存储, 之后用户的输入到来后, 首先进行向量化的相关性搜索, 将搜索的结果以及用户数据一起作为prompt作为输入喂给LLM, 这是目前常见的做法, 但业界也在考虑转为大模型设计的数据结构和索引技术, 详见 LlamaIndex
几个开源项目:
- https://github.com/arc53/docsgpt
-
https://github.com/GanymedeNil/document.ai
都是用的 data augement generation 来做的.
LlamaIndex -> 专注在数据层
对于私有数据, 受限于LLM的无状态, 训练代价大, token个数限制, 甚至fine-tune的接口不开放等等, 对于私有数据上的内容生成, 现在常见的做法是embedding文档, 先搜后问, 也即上文提到的langchain的一个核心模块: data augementing generation. 与此同时, LlamaIndex在考虑为LLM设计的数据结构和索引.
现在想要增强LLM在私有数据上的表现能力, 有两种方式: fine-tune 和 in-context learning (即将上下文放入输入的prompt中) .
为了更好地(高效,便宜)进行data augmentation, 想要解决: 数据摄取和索引. LlamaIndex提供的工具:
- data connectors : 连接到数据源, 和不同的数据格式
- 利用LLM来给结构化,非结构化数据做索引. 简化了in-context learning过程中繁琐的细节: prompt长度, 文本拆分,etc
- 用户优化的索引query 接口 和 模型调用接口的结合
- 一个权衡成本和性能的全面的工具集
不同于langchain的全面开发, 均衡发展策略, llama-index更像是专注在data augmentation generation, 围绕它来开发周边对应的能力. 即丰富的数据源和数据格式的读取器, 统一的index表示, 花式的index读取, 写入.
smart agents -> 专注在agents
Build natural language agents that connect to your data, talk to APIs, and solve complex problems.
和Llama-index类似, 不过专注在agents, 准备构建一个agents market, 在大模型之上构建一个软件系统, 可以和其它系统交互, 完成复杂任务.
目前资料较少
总结
GPT Index vs LangChain 的区别:
根本上是因为 大语言模型支持的context有限,比如ChatGPT的Davinci model只有 4096 tokens,对应中文,可能只有2000
“A big limitation of LLMs is context size (e.g. Davinci's limit is 4096 tokens. Large, but not infinite).”
如果单纯的跟GPT模型对接,那直接用 GPT 的 Davinci 模型直接对话就行;ChatGPT 只是 GPT 其中一个 chat-model 而已
如果需要借助GPT语言模型+私有数据,那就需要突破 4096 tokens 的限制,也就是 feed "knowledge" to LLMs,所以需要用上 GPT Index
与此同时,在用 ChatGPT 时,单次输入的 prompt 也有限制,所以 GPT Index 可以简化这个 feed 喂数据的过程。
- 如果 GPT 直接就满足要求,可以用 GPT Index,就够了。
那为什么还有用上 LangChain 呢?就是因为 LLMs 不止 OpenAI 的 GPT 模型,LangChain 可以对接多种模型,即 Lang
而 Chain 的意思就是把多个 LLM 调用,而且是调用序列,标准化,集成等工作,最后串起来
- LangChain 还做了很多框架层面的工作:Prompt、Loader、Chain、Agent、Memory
比如 Loader 部分,它也推出了跟 https://llamahub.ai 类似的 https://github.com/hwchase17/langchain-hub,用来集成外部数据。区别就在于 GPT Index 能用的,LangChain 都能用,LangChain 的 Loader 能加载其他语言模型,是 GPT 的超集。
再比如 Memory 部分,就是用来持久化 内存 状态,所以能实现 ChatGPT 聊天机器人这样的功能,记住以前的交互非常重要,无论是短期的还是长期的。
Agent 部分就更有趣了,可以根据用户输入,再来决定调用这些工具中的哪一个,比如 LangChain 的 GPT+WolframAlpha 示例,甚至还可以根据输入去调用 WolframAlpha,解答你的数学提问,弥补GPT 数学弱智的问题。
当然,它也可以去做 Google 搜索、数据库查找 等操作,通过需要跟 Document Loader 结合起来用,你可以找到类似 https://llamahub.ai/l/file-pdf 等不少例子。
应用
- chatpdf : 和书籍对话, 也是类似llama index的做法, 将内容embedding, 利用LLM进行提炼总结.
- chatexcel: https://chatexcel.com/convert, 上传excel, 利用自然语言描述需求, 自动改表, 总结内容. (私人表格助手)