langchain更新初体验

前言

上一篇文章中,探讨了langchain版本中的使用,现在更新到了langchain版本,到底有哪些变化呢?

本文将以一个最基本的案例,展现当前所取消的、增加的内容。

P.S.:虽然说有删有减,但是废弃方法可能需要一段时间才能真正移除,所以短时间内也无需太在意。

目前源码已更新到了我的GitHub上,本文对应的是functions目录下的availability.py文件。

写一个基本的demo

要写的东西很简单,其实就是给一串提示词,然后提一个问题,等待一个回答就好了。

那么就还是老样子,用streamlit配置。

配置文件.streamlit/secrets.toml

由于我们还是沿用langchain+qwen的结构,因此还是需要一个qwenapi-key,这里就不多说了。

1
DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

反正也是最简单的demo罢了,就配这个就好。

获得大模型对象

为了实现多种大模型的兼容,这里采用了工厂模式。

先来一个抽象工厂。

1
2
3
4
class BaseLLMFactory(ABC):
@abstractmethod
def build(self):
...

然后构建通义千问的工厂类:

1
2
3
4
5
6
7
8
9
10
class TongyiFactory(BaseLLMFactory):
def __init__(self, api_key: str = st.secrets["DASHSCOPE_API_KEY"], model_name: str = "qwen-max", top_p: float = 0.7):
self.api_key = api_key
self.model_name = model_name
self.top_p = top_p

def build(self):
from langchain_community.llms import Tongyi
llm = Tongyi(model = self.model_name, top_p = self.top_p, api_key = self.api_key)
return llm

这样的话,我们如果需要获得一个通义千问的大模型对象,只需要这样调用:

1
llm = TongyiFactory().build()

或者也可以自定义:

1
2
3
4
5
llm = TongyiFactory(
api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
model_name = "qwen-turbo",
top_p = 0.9
).build()

由于并不会对大模型的能力要求很高,所以参数也只设置这些。后续再考虑高阶的参数,甚至tokenizer

甚至,你觉得build()这个调用太累赘了,在Python中也就直接用魔法函数直接解决掉:

1
2
3
4
def __call__(self):
from langchain_community.llms import Tongyi
llm = Tongyi(model = self.model_name, top_p = self.top_p, api_key = self.api_key)
return llm

这样,我们就可以直接使用TongyiFactory构建通义千问的大模型对象了。

Chain退场,上场的是Runnable

首先,相对于以前,也就是在版本就已经标记要废弃的,就包括LLMChainConversationChain等在内的各种Chain

先回顾一下:

  • 为了将PromptTemplate输入大模型进行处理,我们首先需要利用LLMChain构建一个基本的Chain
  • 在此基础上,为了进一步读取网络上爬取的信息,需要另外构建一个StuffDocumentChain对象用于处理网络爬取的信息。

这也就导致,如果一个应用越来越大,功能越来越多,那么所需要实例化的对象就越来越多,所需要构建的Chain对象就越来越多,代码也会越来越复杂。

那么,我们用什么呢?也就是langchain现在利用Runnable提供的各种代理类。

回到我们现在的项目中。我们刚刚自定义了一些工厂,构建了一个通义千问的大模型对象,那么,我们构建的到底是什么?

我们可以在langchain_community.llms中找到Tongyi,后来发现,其实是langchain_community.llms.tongyi的别名。没事,继续找,在langchain_community.llms.tongyi中,主要的类是继承自BaseLLMTongyi类。继续找,发现BaseLLMRunnable的子类。

虽然在功能上,TongyiRunnable这两个类已经差别太大了,但是,在使用过程中,两者还是一样的。

于是,直接调用代理方法:

1
result = llm.invoke("你好,我不是小娜,我没办法帮你。")

于是就可以获取到一个回答了:

1
2
3
4
5
你好!看来可能有些误会。
作为AI助手,我的目标是尽可能帮助所有用户。
无论您是不是小娜,如果您有任何问题或需要协助的地方,请随时告诉我,
我会竭尽全力为您提供帮助。无论是技术问题、知识查询还是日常生活的疑问,
我都愿意尝试为您解答。请随时告诉我您的需求。

P.S.:原输出没有换行,我换行纯粹是为了方便看。

这就是最基本的使用。

总结

直到目前为止,其实可以发现,除了即将删除的Chain以及Chain都有的run方法被取代掉了,其他的也都还在,所以也没有很奇怪。

不过,接下来,为了更丰富的体验,以及弥补即将删除的Chain所对应的空白,langchain提供了一个很有意思的过程,这个就在以后单独用一篇文章讲。