从LangChain使用Agent的懵懵懂懂,到AutoGen的"放肆"Agents,这周的学习和写作实在太幸福了。假如您是第一次接触AugoGen,请先要查看AutoGen官方文档,或翻阅AutoGen系列的前几篇。
逐步掌握最佳Ai Agents框架-AutoGen 三 写新闻稿新方式
[逐步掌握最佳Ai Agents框架-AutoGen 四 多代理群聊实例]
前言
之前的文章,我们将AutoGen的核心概念AssistantAgent、UserProxyAgent和GroupChatManager都学习了一遍,为AutoGen非常前卫的多代理模式感到震撼!这玩意真能通过chat,组合一堆agents完成复杂任务吗?笔者目前也不确定,就让我们一起慢慢来探索AutoGen这个AI小镇吧。
相比于AutoGen的前卫,LangChain已经有很多朋友将其应用到大型项目中,不怎么存在不确定问题,而且也拥有agent特性。今天的例子,我们将结合AutoGen和LangChain一起来开发一款AI助理程序。看看新旧两派AI应用是如何协作,来各司其职的。
如果您比较喜欢我的文章,欢迎赏个点赞,关注。闭关一年为AI,各位,一起加油。
LangChain
在之前的文章中,多次提到了LangChain。如果您还不了解LangChain,建议您先去看看相关资料。我个人比较推荐吴恩达的《LLM应用程序开发的LangChain》,为避广告之嫌疑,链接我就不给了。
ChromaDB
在项目中,还会用到向量数据库ChromaDB。今天的项目,是经典的LLM专家知识库开发。我们在和知识库chat的时候,会将知识库中的资料和我们的问题都embedding,再计算出他们的相似性,从而为用户基于专业知识库回答问题。ChromaDB相比于以前我们熟悉的MYSQL或NoSQL存的是数据本身,它存储的是embedding, 是专门的embedding查询数据库。
知识库
我们使用的知识库是Uniswap Protocol,即Uniswap的白皮书。作为私有知识库的样本数据,构建一个AI代理。
构建AI助理
今天我们的应用场景,是基于uniswap 的白皮书来构建AI助理。帮助用户完成与uniswap协议知识相关的任务,即专家系统。既然我们使用AutoGen和LangChain一起协同来开发,他们又都是AI开发框架,那么各自负责什么任务呢?
- 各自优势
AutoGen善于对多代理进行调度协同工作,帮助用户完成提出的问题或执行任务;LangChain具有很强的连接外部数据和外部组件的能力。在今天的uniswap专家知识库AI助理系统打造中,正好利用各自的优势,来打造这一功能。如果您对连接外部数据库或embedding不太清楚, 建议先去看看LangChain。
- 安装依赖,使用colab。
%pip install pyautogen~=0.1.0 docker langchain openai tiktoken chromadb pypdf -q -U
其中,tiktoken
是一个由 OpenAI 开发的 Python 库,它可以用来计算一个文本字符串在 GPT-3 模型中会使用多少 tokens。chromadb
是向量数据库,用于存储文章索引,便于多次查询。 PyPDF2
是一个 Python 库,用于处理 PDF 文件。
- 拉取uniswap白皮书
!wget -O uniswap_v3.pdf https://uniswap.org/whitepaper-v3.pdf
使用wget 命令行拉取远程uniswap白皮书文件保存到当前目录下,并命名为uniswap_v3.pdf(如下图)
- 配置autogen config
import autogen # 大家可以使用gpt-4 或其它,我这里用的是3.5, 还能用。
config_list = [ { 'model': 'gpt-3.5-turbo', 'api_key': '' }]
llm_config={
"seed": 42, #为缓存做的配置
"config_list": config_list
}
- 设置openai api-key
import os
os.environ['OPENAI_API_KEY'] = ''
- 引入LangChain 加载文件,并存储embedding索引到chromadb向量数据库
# 从langchain的向量存储中导入Chroma, 可以和Chromadb 交互
from langchain.vectorstores import Chroma
# 引入langchain封装的OpenAIEmbeddings
from langchain.embeddings import OpenAIEmbeddings
# langchain读取文件后,做索引前,需要分割文本,然后embedding
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载器
from langchain.document_loaders import PyPDFLoader
#
from langchain.memory import ConversationBufferMemory
#引入OpenAI langchain 支持各种大模型
from langchain.llms import OpenAI
#
from langchain.chains import ConversationalRetrievalChain
- 将uniswpa 向量化存储到 chroma
# 使用pyPDFLoader 加载之前 wget 存到本地的uniswap_v3文件,格式是pdf的
loaders = [ PyPDFLoader('./uniswap_v3.pdf') ]
docs = [] # 初始化文档数组
for l in loaders:
docs.extend(l.load()) # 加载文件添加到数组
# 基于langchain text_splitter 提供的RecursiveCharacterTextSplitter
# 实例化一个 文本分割器,未来每个分块会单独进行ebedding计算,每块1000个字符
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
# text_splitter 接受一个docs直接分词。
docs = text_splitter.split_documents(docs)
langchian 为我们提供了文本分割器,我们这里使用的是 RecursiveCharacterTextSplitter,它接收一个文件数组。PyPDFLoader加载本地的uniswap文件,调用load方法,将其extend到docs数组中。text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000) 实例化了一个splitter, 每个切片为1000个字符,以后,用户的查询就会和这里的每个切片匹配, 从而,完成文档查询。
vectorstore = Chroma(
collection_name="full_documents",
embedding_function=OpenAIEmbeddings()
)
vectorstore.add_documents(docs)
chroma
是向量数据库,上面的代码实例化了一个名为full_documents的集合,并声明了embedding计算的大模型为OpanAIEmbeddings。如果大家还不了解什么是向量数据库,embedding又为何?建议先去了解相关概念,用户的查询会embedding, 再与向量数据库里的每个片段的embedding 做一个cosin 计算,相同似的两段就是我们要查询的。
-
LangChain QA Chain LangChain的核心概念就是Chain, 链式解决各种问题。我们的Uniswap专家知识库系统,这种项目,是LangChain的长项,ConversationalRetrievalChain 专门解决知识问答。
# 实例化ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
# temperature为0 是问答系统的需要,100%来自文档,不飘
OpenAI(temperature=0),
# 将向量数据库设置为来源
vectorstore.as_retriever(),
# 记忆 设置了key 为chat_history
memory=ConversationBufferMemory(memory_key="chat_history", return_messages=True)
)
#提问
result = qa(({"question": "What is uniswap?"}))
# 拿到结果
result['answer']
Uniswap is a decentralized cryptocurrency exchange that allows users to trade Ethereum-based tokens without the need for a centralized exchange. It is built on the Ethereum blockchain and uses automated market makers to facilitate trades.'
双击666,LangChain一顿操作猛如虎,砍瓜切菜一般完成文档加载、文本切割、向量数据库存储,及问答功能搭建, 还要什么AutoGen?
- 将任务交给
AutoGen
def answer_uniswap_question(question):
response = qa({"question": question})
return response["answer"]
llm_config={
"request_timeout": 600,
"seed": 42,
"config_list": config_list,
"temperature": 0,
"functions": [
{
"name": "answer_uniswap_question",
"description": "Answer any Uniswap related questions",
"parameters": {
"type": "object",
"properties": {
"question": {
"type": "string",
"description": "The question to ask in relation to Uniswap protocol",
}
},
"required": ["question"],
},
}
],
}
代码走到这里,看了上篇文章的同学,应该就清楚, 原来LangChain
做的工作,交给了AutoGen的agent with function calls功能调用。
# create an AssistantAgent instance named "assistant"
assistant = autogen.AssistantAgent(
name="assistant",
llm_config=llm_config,
)
# create a UserProxyAgent instance named "user_proxy"
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
code_execution_config={"work_dir": "."},
llm_config=llm_config,
system_message="""Reply TERMINATE if the task has been solved at full satisfaction.
Otherwise, reply CONTINUE, or the reason why the task is not solved yet.""",
function_map={"answer_uniswap_question": answer_uniswap_question}
)
AutoGen的工作流开启,初始化助理Agent和用户代理Agent。用户代理Agent配置了function_map
,在之后的代理工作后,会调用此函数,将工作交给LangChain来完成。
# the assistant receives a message from the user, which contains the task description
user_proxy.initiate_chat(
assistant,
message="""
I'm writing a blog to introduce the version 3 of Uniswap protocol. Find the answers to the 3 questions below and write an introduction based on them.
1. What is Uniswap?
2. What are the main changes in Uniswap version 3?
3. How to use Uniswap?
Start the work now.
"""
)
user_proxy 工作 ,message prompt 很清楚,将围绕上面提到的三个问题,想写一篇介绍uniswap协议的文章。
每个问题,assistant agent会调用proxy agent配置的function_maps中的answer_uniswap_question
函数,将由LangChain做知识库问答。集齐三个问答后,生成文章....
- AutoGen 执行流程
首先,user_proxy接收到用户的需求后,向assistant发出任务。可以开始工作了,哈哈,user_proxy就是包工头,assistant就是打工的,用户是老板。
接着,assistant告诉user_proxy可以调用answer_uniswap_question
函数完成What is Uniswap?
工作。
user_proxy调用answer_uniswap_question
拿到LangChain基于向量查询的结果。
&esmp;其它的两个问题也类似,我们拿到回答。
第二个问题 第三个问题
最后,助理Agent告诉user_proxy,它aigc生成的内容是
到这里,功能就完成了。
总结
本文结合AutoGen和LangChain,一起开发了一款基于Uniswap的智能问答助理。LangChain作为当下商用最成熟的AI框架,加载文档,向量化,模型embedding,问答chain等精细化操控整个大模型开发流程。然后,再使用AutoGen聊天协作的优势,将工作交给LangChain完成。笔者有以下两个感受:
- LangChain负责传统AI细节开发,做底层,做功能封装。
- AutoGen好理解,语义化搭建开发流程
- 如此分工协作,有利于团队协作。