有兄弟让我讲讲langchain
。
哈哈,我又没出镜,他怎么看出我说话好听的?不过,我倒是喜欢写大家关心的。下面就聊聊这个langchain
。
langchain
是一个开源项目 github.com/hwchase17/l… 。这个项目在GitHub上已经有45.5K个Star了。此项目由一位叫hwchase17的国外小哥在2022年底发布。
我有理由相信,这个项目是为了对接大语言模型才搞的。
一、企业困境: 如何应用大语言模型
大语言模型(Large Language Model, LLM)如雨后春笋一般,噼里啪啦地陆续露头。一时间,LLM
成为了网络流行语。
1.1 有关上下文
我虽然从事这个行业,但对此类缩写并不敏感。一段时间,我一直以为LLM
是“聊聊吗”的简称。后来,老领导给我发LLM,我问他想聊什么,被批评了。我庆幸没把LLM当成“老流氓”。
看上面那段话,具体LLM是什么,其实跟语境有关系,这个语境就是上下文。
似乎大家更热衷于调戏大语言模型,并不关心什么是上下文。高考出来了,你让AI写高考作文,感觉掌握了最尖端的科技。这没错,作为大众用户这就够了。
但是,作为企业用户他们却愁得慌。自己的企业该如何去跟LLM结合呢?直接在ChatGPT外面套个壳吗?那人家干嘛不直接用官方的呢?
现在市面上的大语言模型都是通用模型。也就是说,你问它泛知识它都知道,然而问它小领域知识,它是不知道的。
1.2 辛弃疾与我
我问ChatGPT:你从哪里了解到辛弃疾的?
它回答:
作为一个人工智能模型,我是通过在多个来源和语料库上的大规模学习来获得知识和信息的。我可以回答辛弃疾是谁以及他的生平事迹。
但是,我问它关于TF男孩的事情,它不知道。
辛弃疾是泛知识,本人(TF男孩)是领域知识(只活跃在掘金社区)。因此它不知道我。
1.3 领域内应用
迁移到垂直行业也是同样的道理。
大语言模型对于泛知识能找到上下文,这源于网络上公开的数据。但是对于领域知识,它的表现可能就差点。因为你们公司的数据,它拿不到。
你问它:我这个月迟到两次,第1次迟到15分钟,第2次35分钟,请问我的工资少发多少?
你这是在为难它,也是在为难你自己。
- 你哪个公司?
- 你们公司考勤是什么制度?
- 你工资多少?由什么构成?
- ……
你既然想让AI服务我们,那就得是面面俱到。因此,它不知道你可以告诉它。告诉它之后,你再问,它就会了。
哎!这就做到了大模型与行业领域结合。你可以问它你们公司的内部资料,比如规章制度。也可以让它去探索你们公司项目和财务数据之间的关联。
但是,这里面会有一些问题。
-
首先,你愿意把这些数据给大模型吗?哈哈!假如你是一家银行,或者就是一个生产皮鞋的,你愿意把生产或者经营数据给大模型吗?
-
其次,不好意思,就算你愿意给,人家大模型不要。你问个三五句话还行,你扔过来近五年的几百份财务报表,大模型是拒绝的。你这堆材料里面,第1份文件的第2段和第206份文件的第3段有关联,老子没工夫帮你整理这个!
哈哈,这老有意思。都说LLM如何如何火,但是企业心里也琢磨:它除了帮员工代写周报、请假理由,它能为我做什么呢?
至此来看,其实大家还是无法更深层次地触摸到LLM。
不过还好,langchain
来了!它带着解决方案过来了!
二、LangChain: 给大语言模型接腿
再声明一下langchain
的相关信息。你看到这儿可以点链接走了,因为我讲的不会比它更权威。
外国小哥写的,所以基本都是英文资料。中文好的朋友,可以留下来听我讲。
它的头条就说,它是一个“基于特定文档问答”的解决方案。
那么,它有什么作用呢?咱们先来文的(讲功能),再来武的(敲代码)。
2.1 给LLM加拉链
首先,它让LLM的调用更加便捷了。
就拿调用ChatGPT
举例。你安装它家的库:pip install openai
。然后去openai
网站买一个key
。这是最基础的,也是GPT本家要求的。
另外,你要安装:pip install langchain
。
然后执行如下python
代码:
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="你的key")
llm("如何成为TF那样优秀的人?")
# ChatGPT:不用费力气了,你做不到的!
这简单程度,就像是一个拉链,拉开就能用。
它的目的不是为了简化GPT的调用流程,是为了更好地替换其他大语言模型。
它可以对接其他大语言模型。假如我出了一个TFboyAI
,那么构建起来也是三句话:
from langchain.llms import TFboyAI
llm = TFboyAI()
llm("如何成为TF那样优秀的人?")
# TFboyAI:傻瓜,你比他更优秀!
2.2 给LLM加助理
有些事情虽然不大,但做起来也很麻烦。比如,端茶倒水、复印打印。大模型是有脾气的,它不屑于做这些小事。
这一点体现在它对上下文的要求上:这位先生,请你明确一下,到底是谁要我到哪里去干什么?
因此langchain
就给它加了一个私人助理的功能。
from langchain.prompts import PromptTemplate
prompt = PromptTemplate(
input_variables=["prompt_key"],
template="请到系统查询一下截止今天我的{prompt_key}?",
)
print(prompt.format(prompt_key="剩余调休"))
# 系统:请到系统查询一下截止今天我的剩余调休?
你在公司喊出一句“剩余调休”,那肯定不是问“请查询隔壁老王的剩余调休”。助理会加工一下,比如补充一些个性信息变成“请到系统查询一下截止今天我的剩余调休?”,然后再去问脾气大的LLM。
from langchain.chains import LLMChain
chain = LLMChain(llm=llm, prompt=prompt)
chain.run("剩余调休")
# 系统:目前为止,您的剩余调休为10600个小时。
这里面有一个LLMChain
链条的概念,那就是按照预设的1、2、3步骤去执行。
langchain
在国内被翻译成“朗链”。其实这是两个词,lang表示“language”的缩写,chain有“链条”、“连环”的意思。
它的威力就在于这个链条上,可以制定行进的路线。
2.3 给LLM加外援
语言大模型不是万能的,尤其面对很多未知的事情。
语言大模型一般会有一个训练数据的截止日期。比如截止到今年3月15日。那么,在这个日期之后发生的事情,它是不知道的。这很好理解,它也是看新闻增长见识。就算LLM具备写高考作文的能力,但是你让他写明天的高考作文,它是不知道题目的。
于是langchain
引入了一个叫Agents
代理的模块。代理可以将很多外部操作融入到业务链条当中。所谓代理就是代为处理。
举个例子。你想了解手里的钱够买几斤金条。这件事大模型搞不定。不是它不够聪明,依然是上下文不充分。
这件事应当分为三步:
- 第一,去网络上查询当前金价。
- 第二,去私人数据库查询余额。
- 第三,让语言大模型计算数量。
这里面会用到代理。去网络上查询信息,需要依托搜索引擎。去查询余额,需要连接私有数据库。这些操作langchain
是支持的。你只需要把它们整合到链条当中就行。
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.llms import OpenAI
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "python_repl", "llm-math"], llm=llm)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("当前金价是多少一克?我的账户余额有多少?我能购买多少斤黄金?")
上面这一顿猛如虎的操作,是由langchain
代为实现的。如果你愿意看详细步骤,只需要verbose=True
会打印出来流程。
> Entering new AgentExecutor chain...
我需要先查询到金价,然后查询到账户余额,最后计算出购买的数量。
Action:Search
Action Input: 当前国际金价?
Observation: 三毛六一斤
……
Thought: 金价是0.36元/斤,你现在有3.6元。
Action: Calculator
Action Input: 3.6/0.36
Observation:Answer: 10.00
Thought: 以您的资产,能购买10斤黄金。
> Finished chain.
langchain
只是一个中间商,代理中用到的能力,是集成别人的。比如serpapi
是谷歌的搜索API。你需要先注册。如果量大的话,还需要花钱购买额度。
python_repl
则是python
的普通命令,可以执行python
代码。
这些都是官方开箱即用的工具。如果觉得不合你的胃口,它也支持自定义工具。
关于agents中tools的更多信息,可以去官方查看:python.langchain.com/en/latest/m…
2.4 给LLM加更多
除了上面那些,langchain
还有其他功能。比如,消息的处理、聊天的处理等等。
我主要是给外行做科普,上面那些就够吹牛的了。再深入的知识,一时半会儿未必说得清。就算说得清,外行看完了反而会心情低落,而内行本来就知道。
总之langchain
给LLM接上了大腿。
LLM还是那个LLM,依然是哪个回答问题的语言大模型。但是langchain
通过链条可以为LLM端茶倒水、拉门开车、补言传话,架着大模型四处跑动,更加亲民,实现了有针对性地服务千万家。
实际上,国内开发者依然会觉得langchain
不够亲民。大家在等着哪国小哥能再封装一层,让langchain
变得更为简单。
这不怪大家。langchain
的文档是全英文的,而且开篇Demo就是对接OpenAI。以前OpenAI只需要海外注册,但现在使用也必须在海外了。这极大地提高了大家的学习门槛。
不过,你真想学习langchain
,这都不是问题。OpenAI只是LLM的一个典型代表。你可以对接国内的其他LLM。甚至说,你可以写一个假的LLM,仅仅是辅助langchain
的学习用。
三、为了学习: 模拟一个假的LLM
为什么要造假?谁给你的底气?谁告诉你的方法?
是langchain
官方,有文档为证 python.langchain.com/en/latest/m…
上面并不是中文文档,只是随便找个浏览器,点了一下全文翻译按钮。
他文档中说:
如何(以及为什么)使用假LLM?
我们公开了一个可用于测试的假 LLM 类。这使您可以模拟对LLM的调用,并模拟如果LLM以某种方式响应会发生什么。
我觉得,这还不够假。于是,我自己写了一个TfboyLLM
。以下是全部代码:
from typing import Any, List, Mapping, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain.llms.base import LLM
import re
class TfboyLLM(LLM):
@property
def _llm_type(self) -> str:
return "custom"
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
) -> str:
print("问题:",prompt)
pattern = re.compile(r'^.*(d+[*/+-]d+).*$')
match = pattern.search(prompt)
if match:
result = eval(match.group(1))
elif "?" in prompt:
rep_args = {"我":"你", "你":"我", "吗":"", "?":"!"}
result = [(rep_args[c] if c in rep_args else c) for c in list(prompt)]
result = ''.join(result)
else:
result = "很抱歉,请换一种问法。比如:1+1等于几"
return result
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {}
我的TfboyLLM
继承了langchain.llms.base
的LLM
类。需要实现它的两个方法:
_call
: 主要的处理方法,对传来的prompt
问题分析,给他return
一个答案。_identifying_params
: 说明LLM
类中的参数和数值。本例中没有类的成员变量。
其实关键要看_call
中实现的逻辑:
- 收到
prompt
先打印出来。 - 对问题正则匹配,规则为:[数字]+[运算符]+[数字]。匹配到,返回计算结果。匹配不到继续执行。
- 判断有没有[?]。如果有,则对文本中字符进行替换,规则为:我->你, 你->我, 吗->””, ?->!。
- 如果都不符合,就返回:“很抱歉,请换一种问法。比如:1+1等于几”。
构建完了之后,调用这个TfboyLLM
也很简单,和调用OpenAI一样。
llm = TfboyLLM()
print("答案:",llm("我能问你问题吗?"))
咱们看看效果如何:
问题: 巴拉巴拉咕嘎咕嘎
-- 很抱歉,请换一种问法。比如:1+1等于几
问题: 我能问你问题吗?
-- 你能问我问题!
问题: 189+981是多少
-- 990
问题: 你能和我结婚吗?
-- 我能和你结婚!
问题: 开玩笑?
-- 开玩笑!
解决了LLM的问题,你就可以继续学习langchain
。
现在业内卖课的,是有这么个说法,就是说LLM
+langchain
可以怎样怎样。
实际上这只是理论。是可以实现,但不是“嗖”一下就搞定。前前后后还有很多周边的东西需要处理。比如向模型扔文档资料这一步。你得先将pdf转成文字吧。pdf如何解析?带表格的,带水印的,怎么提取和剔除?pdf是照片扫描件的话,还得先走OCR识别!
想要真正落地,还需要接上很多条类似langchain
的大腿。
好了,关于langchain
就讲这么多。本文讲得很浅,就当入个门呗。你愿意学就继续研究,觉得没意思就放弃。反正,任何技术很难通过看一篇文章就能掌握。就算学做一道菜,不也得改良几次才能好吃吗?
我是TF男孩,我在做AI的科普工作,这篇文章是 全民AI计划 的第4期。
- 第1期:《尝试第一个AI程序》
- 第2期:《文本摘要实现原理》
- 第3期:《详解词向量的作用》
我是掘金@TF男孩,一个普及AI知识的民科IT男。