前言
过去半年,随着ChatGPT的火爆,直接带火了整个LLM这个方向,然LLM毕竟更多是基于过去的经验数据而来,没法获取最新的知识,以及各企业私有的知识
-
为了获取最新的知识,ChatGPT plus版集成了bing搜索的功能,有的模型则会调用一个定位于 “链接各种AI模型、工具”的langchain的bing功能
-
为了处理企业私有的知识,要么基于开源模型微调,要么更可以基于langchain里集成的向量数据库和LLM搭建本地知识库问答(此处的向量数据库的独特性在哪呢?举个例子,传统数据库做图片检索可能是通过关键词去搜索,向量数据库是通过语义搜索图片中相同或相近的向量并呈现结果)
LangChain的整体组成架构 :LLM的外挂/功能库
通俗讲,所谓langchain (官网地址、GitHub地址),即把AI中常用的很多功能都封装成库,且有调用各种商用模型API、[开源模型]的接口,支持以下各种组件
Model
模型主要涵盖大语言模型(LLM)。大语言模型是指具有大量参数并在大规模无标签文本上进行训练的神经网络模型。科技巨头们推出了各种各样的大型语言模型,比如:
- 谷歌的 BERT
- OpenAI 的 GPT-3
- 谷歌 LaMDA
- 谷歌 PaLM
- Meta AI 的 LLaMA
- OpenAI 的 GPT-4
- ……
借助 LangChain,与大语言模型(LLM)的交互变得更加便捷。LangChain 提供的接口和功能使得将 LLM 的强大能力轻松集成到工作应用程序中成为可能,并利用 asyncio 库为 LLM 提供异步支持。
在需要并发调用多个 LLM 的网络绑定场景中,LangChain 的异步支持尤为重要。通过释放处理请求的线程,服务器可以将其分配给其他任务,直到响应准备就绪,从而最大化资源利用率。
目前,LangChain 支持 OpenAI、PromptLayerOpenAI、ChatOpenAI 和 Anthropic 等模型的异步调用,未来计划将扩展对其他 LLM 的支持。你可以使用 agenerate 方法来异步调用 OpenAI LLM,并且可以编写自定义的 LLM 包装器,超出 LangChain 默认支持的模型范围。
在我的应用程序中,我使用了 OpenAI 的多种模型,包括 Davinci、Babbage、Curie 和 Ada,以解决不同的问题。每种模型都有其独特的优点、令牌使用量和适用场景。
import os
import asyncio
from typing import Any, Dict, List
from langchain_openai import ChatOpenAI # ChatOpenAI模型
from langchain.schema import LLMResult, HumanMessage
from langchain.callbacks.base import AsyncCallbackHandler, BaseCallbackHandler
# 创建同步回调处理器
class MyFlowerShopSyncHandler(BaseCallbackHandler):
def on_llm_new_token(self, token: str, **kwargs) -> None:
print(f"获取花卉数据: token: {token}")
# 创建异步回调处理器
class MyFlowerShopAsyncHandler(AsyncCallbackHandler):
async def on_llm_start(
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
) -> None:
print("正在获取花卉数据...")
await asyncio.sleep(0.5) # 模拟异步操作
print("花卉数据获取完毕。提供建议...")
async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
print("整理花卉建议...")
await asyncio.sleep(0.5) # 模拟异步操作
print("祝你今天愉快!")
# 主要的异步函数
async def main():
flower_shop_chat = ChatOpenAI(
model=os.environ["LLM_MODELEND"],
max_tokens=100,
streaming=True,
callbacks=[MyFlowerShopSyncHandler(), MyFlowerShopAsyncHandler()],
)
# 异步生成聊天回复
await flower_shop_chat.agenerate(
[[HumanMessage(content="哪种花卉最适合生日?只简单说3种,不超过50字")]]
)
# 运行主异步函数
asyncio.run(main())
输出 正在获取花卉数据... 花卉数据获取完毕。提供建议...
- 获取花卉数据: token: 百合
- 获取花卉数据: token: ,
- 获取花卉数据: token: 寓意
- 获取花卉数据: token: 纯洁
- 获取花卉数据: token: 美好
- 获取花卉数据: token: ;
- 获取花卉数据: token: 向日葵
- 获取花卉数据: token: ,
- 获取花卉数据: token: 代表
- 获取花卉数据: token: 阳光
- 获取花卉数据: token: 乐观
- 获取花卉数据: token: ;
- 获取花卉数据: token: 康乃馨
- 获取花卉数据: token: ,
- 获取花卉数据: token: 象征
- 获取花卉数据: token: 着
- 获取花卉数据: token: 爱
- 获取花卉数据: token: 与
- 获取花卉数据: token: 尊敬
- 获取花卉数据: token: ,
- 获取花卉数据: token: 都
- 获取花卉数据: token: 很
- 获取花卉数据: token: 适合
- 获取花卉数据: token: 生日
- 获取花卉数据: token: 。
- 获取花卉数据: token:
- 整理花卉建议...
- 祝你今天愉快!
代码讲解与知识点扩展
1. 异步编程(Asyncio)
在 Python 中,异步编程通过使用 asyncio 库使得程序能够在等待某个操作(如网络请求)完成时,不阻塞主程序的运行。这里使用了 async 和 await 关键字来定义异步函数。当调用一个被标记为 async 的函数时,其执行会被挂起,直到遇到 await 语句,允许其他操作在此期间继续执行。这种方式对于高并发任务尤为重要,因为它能有效利用系统资源,提升应用的吞吐量。
代码示例:
python
await asyncio.sleep(0.5) # 模拟异步操作
以上代码模拟了一个非阻塞的延迟,允许其他任务在这个等待过程中继续执行。
2. 回调机制(Callback)
代码中定义了两个回调类:MyFlowerShopSyncHandler 和 MyFlowerShopAsyncHandler。回调是一种设计模式,允许程序在完成某个操作后执行特定的代码。在这里:
- 同步处理器 (
MyFlowerShopSyncHandler): 用于在模型生成新令牌时进行操作,比如简单打印信息。这种方式适用于需要实时反馈的场景。 - 异步处理器 (
MyFlowerShopAsyncHandler): 在模型操作的开始和结束时执行异步任务,能够更好地整合非阻塞特性。它通过await来确保异步操作的完成。
3. LangChain库
LangChain是一个用于构造应用程序的框架,特别是与大语言模型(LLM)进行交互的应用。它简化了模型的调用过程,并提供丰富的功能来管理输入、输出和后续操作。
- 模型支持:当前代码使用了
ChatOpenAI模型,该模型是OpenAI提供的,用于处理对话类任务。LangChain也支持其他模型,如PromptLayerOpenAI和Anthropic等。 - agenerate方法:这是一个异步方法,用于生成模型的响应。在调用该方法时,可以传入用户的输入(如
HumanMessage),模型会根据这些输入生成相应的回复。
代码示例:
python
await flower_shop_chat.agenerate(
[[HumanMessage(content="哪种花卉最适合生日?只简单说3种,不超过50字")]]
)
这里,用户询问以获取花卉建议,模型接收请求并生成回答。
4. 流式生成(Streaming)
在初始化 ChatOpenAI 时,将 streaming 参数设置为 True。这意味着模型的输出可以逐步接收,而不是一次性等待全部回复,有利于提升用户体验,因为用户可以在得到部分结果时就开始查看,而不是等待整个响应完成。
5. 自定义模型包装器
LangChain允许用户创建自己的模型包装器。这意味着不仅限于默认的模型接口,可以根据需求自定义行为。通过实现特定的接口和方法,开发者可以轻松扩展功能,使得库更加灵活,适用于各种不同的用例。