一、使用【Ernie Bot SDK与向量数据库等】构建Agent实现D章信息查询
1.ERNIE Bot Agent介绍
ERNIE Bot Agent
旨在为开发者提供快速搭建大模型Agent和应用的框架。该项目还在积极研发中,敬请期待我们后续的正式发版。
2.主要功能
2.1大模型 Agent 框架
ERNIE Bot Agent
将结合飞桨星河AI Studio社区,为开发者提供一站式的大模型Agent和应用搭建框架和平台。该项目还在积极研发中,敬请期待我们后续的正式发版。
2.2文心 LangChain 插件
为了让大家更加高效、便捷地结合文心大模型与LangChain进行开发,ERNIE Bot Agent
对LangChain
框架进行了功能扩展,提供了基于文心大模型的大语言模型(LLM)组件、聊天模型(ChatModel)组件以及文本嵌入模型(Text Embedding Model)组件。
3.项目简介
这是一款名为'D建法规小助手'的演示应用,它展示了如何利用LangChain的工具以及ERNIEBot的functional agent来汇聚D建知识。通过利用ERNIE Bot SDK的functional agent,我们可以根据对话的上下文以及用户提出的具体问题,让大型模型在回答问题时灵活选择是否采用检索增强方式,或是直接给出答案。这种设计思路不仅丰富了大模型的领域知识,同时也保留了大模型在领域知识之外的通用对话能力。
二、环境准备
1.erniebot sdk安装
python
# 使用最新版的 ERNIE-Bot-SDK ,该版本为我从github同步下来的。
!git clone https://gitee.com/livingbody/ERNIE-Bot-SDK --depth=1
sql
fatal: destination path 'ERNIE-Bot-SDK' already exists and is not an empty directory.
python
%%capture
%cd ~/ERNIE-Bot-SDK
!pip install -r requirements.txt
!pip install -e ./
2.Ernie Bot Agent安装
python
%%capture
!pip install -r erniebot-agent/requirements.txt
!pip install -e erniebot-agent/
3.pypdf/faiss安装
python
%%capture
!pip install pypdf
!pip install faiss-cpu
# !pip install faiss-gpu # 如果用GPU的话
注意:安装完erniebot-agent后需要重启notebook
三、项目建设
1. 导入第三方库
主要是在导入一些必要的Python库和模块,以便实现Construction Assistant的功能。
- os: Python的标准库,用于与操作系统进行交互,如读写文件、管理路径等。
- Optional, List, Type, Dict: 这些是Python类型提示(typing模块的一部分),用于增强代码的可读性和可维护性,同时也方便开发者进行静态类型检查。
- BaseModel, Field: 这些都是来自Pydantic库的类,用于数据验证和设定数据模型。Field通常用于设定模型的字段。
- SpacyTextSplitter: 一个文本分割工具,用于将文本分割为更小的部分,如句子或短语。
- FAISS: 用于向量存储的模块,可能是用于存储和检索经过嵌入处理的文本或图像的向量表示。
- PyPDFDirectoryLoader: 用于从PDF文件中加载数据的工具。
- ErnieEmbeddings: 用于文本嵌入的工具,将文本转换为可以在模型中使用的向量表示。
- Tool, ToolParameterView: 用于创建和管理工具的基类或工具参数视图的类。
- FunctionalAgent: 这个类实现function calling功能的Agent的类,如问答、对话等。
- WholeMemory: 用于存储和管理代理的记忆的类。
- ERNIEBot: 实现ERNIE Bot的主要类,包含了实现对话功能的主要逻辑。
- AIMessage, HumanMessage, Message: 用于实现消息传递和处理的类,如机器人和人类之间的消息交互。
- erniebot: 这是导入erniebot模块的语句,erniebot可能是一个包含ERNIE Bot实现的主要代码库。
python
import os
from typing import Optional, List, Type, Dict
from pydantic import BaseModel, Field
from langchain.text_splitter import SpacyTextSplitter
from langchain.vectorstores import FAISS
from langchain.document_loaders import PyPDFDirectoryLoader
from erniebot_agent.extensions.langchain.embeddings import ErnieEmbeddings
from erniebot_agent.tools.base import Tool, ToolParameterView
from erniebot_agent.agents.functional_agent import FunctionalAgent
from erniebot_agent.memory.whole_memory import WholeMemory
from erniebot_agent.chat_models.erniebot import ERNIEBot
from erniebot_agent.messages import AIMessage, HumanMessage, Message
import erniebot
2. 预处理
2.1 下载数据准备
打开D建网 www.12371.cn/special/dnf... ,另存页面为pdf,此处下载D章、D廉洁自律准则2016年、关于新形势下D内政治生活的若干准则 3个文件
2.2 配置 ERNIE BOT API
这里使用aistudio的Access_token, 申请地址请参考accessToken
python
erniebot.api_type = "aistudio"
aistudio_access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
erniebot.access_token = aistudio_access_token
3. Tool 构建
3.1 构建Schema
定义了三个类:SearchToolInputView,SearchResponseDocument,和SearchToolOutputView,它们都是ToolParameterView的子类,用于处理和描述一种特定的工具参数。这些类利用了Python的typing模块来定义字段和它们的类型,以及字段的描述。
- SearchToolInputView类定义了两个字段:query和retrieval_num。query字段是一个字符串,用于描述"规章查询语句",这可能是用户输入的查询参数。retrieval_num字段是一个整数,描述了"检索结果数目",默认值是5。
- SearchResponseDocument类定义了三个字段:document,filename和page_num。这些字段可能用于描述一个特定的搜索结果。document字段是字符串,用于存储和查询相关的规章片段。filename字段也是字符串,用于存储规章的名称。page_num字段是整数,用于描述规章的页数。
- SearchToolOutputView类定义了一个字段:documents,这是一个SearchResponseDocument对象的列表,用于描述搜索结果。这个字段的描述表明它包含的是"检索结果,内容为D章等法规中和query相关的片段"。
python
class SearchToolInputView(ToolParameterView):
query: str = Field(description='规章查询语句')
retrieval_num: int = Field(description="检索结果数目", default=5)
class SearchResponseDocument(ToolParameterView):
document: str = Field(description="和query相关的规章片段")
filename: str = Field(description="规章名称")
page_num: int = Field(description="规章页数")
class SearchToolOutputView(ToolParameterView):
documents: List[SearchResponseDocument] = Field(description="检索结果,内容为D章等法规中和query相关的片段")
3.2 构建Faiss检索工具
这段代码定义了一个名为FaissSearchTool的类,它是Tool的子类。这个工具被设计用于在住房和城乡建设部规章中寻找和给定查询(query)最相关的片段。
-
- FaissSearchTool的类属性description描述了这个工具的功能,input_type和output_type则分别指定了输入和输出的类型。
-
- 在__init__方法中,这个工具初始化了一个数据库连接。
-
- __call__方法是这个工具的核心,它是一个异步方法,接受一个查询字符串和一个检索数量,返回一个包含检索到的文档的字典。这个方法首先使用数据库的similarity_search方法获取与查询相似的文档,然后构造检索结果,最后返回一个包含检索结果的字典。
-
- examples属性返回了一个示例列表,这个列表包含一个人类消息和一个AI消息。这些消息可以用来演示这个工具的使用方法。
总的来说,这个类是一个基于Faiss库的搜索工具,用于在特定的文档数据库中找到与给定查询最相关的文档。这在信息检索、问答系统等领域有广泛的应用。
python
class FaissSearchTool(Tool):
description: str = "在D的各项法规中寻找和query最相关的片段"
input_type: Type[ToolParameterView] = SearchToolInputView
ouptut_type: Type[ToolParameterView] = SearchToolOutputView
def __init__(self, db):
self.db = db
async def __call__(self, query: str, retrieval_num: int = 5) -> Dict[str, float]:
docs = self.db.similarity_search(query)
retrieval_results = []
for doc in docs:
retrieval_results.append(
dict(SearchResponseDocument(
document=doc.page_content,
filename=doc.metadata["source"],
page_num=doc.metadata["page"],
))
)
return {"documents": retrieval_results}
@property
def examples(self) -> List[Message]:
return [
HumanMessage("D员义务是什么?"),
AIMessage(
"",
function_call={
"name": self.tool_name,
"thoughts": f"这是一个D章相关的问题,我们使用{self.tool_name}工具检索相关的信息,检索的query:'D员义务'。",
"arguments": '{"query": "D员义务", "retrieval_num": 3}',
},
)
]
4.Assistant
4.1 建索引库
这段代码主要功能是用于创建或加载一个FAISS索引来进行文档相似度匹配。首先,创建一个ErnieEmbeddings对象,用于生成文档的嵌入向量。aistudio_access_token是访问AI Studio的令牌,chunk_size是用于嵌入的文档块的数量,sleep_time是在每次请求嵌入后的休眠时间,用于限制请求的频率。
python
embeddings = ErnieEmbeddings(aistudio_access_token=aistudio_access_token,
chunk_size=16,
sleep_time=20)
接下来利用ErnieEmbeddings来抽取向量构建索引。
- 如果FAISS索引文件已经存在,就使用FAISS.load_local方法加载这个索引,这个索引文件的名字就是定义的faiss_name。
- 如果FAISS索引不存在,则需要建索引。
- 第一步,使用PyPDFDirectoryLoader来从"mydata"这个文件夹中加载PDF文档。
- 第二步,使用SpacyTextSplitter来将加载的文档分割成更小的部分,以便于生成嵌入向量。这个分割器主要用于中文文本,因为这里使用的pipeline是'zh_core_web_sm',如果是初次运行,需要安装spacy并运行
python -m spacy download zh_core_web_sm
来下载中文分句模型。 - 第三步,通过分割后的文档创建一个新的FAISS索引,并将这个索引保存为之前定义的faiss_name。
python
%%capture
%cd ~
!pip install spacy
# 由于是github下载太慢,手动下载安装
# !python -m spacy download zh_core_web_sm
!pip install zh_core_web_sm-3.7.0-py3-none-any.whl
python
faiss_name = "faiss_index"
if os.path.exists(faiss_name):
db = FAISS.load_local(faiss_name, embeddings)
else:
loader = PyPDFDirectoryLoader("./mydata")
documents = loader.load()
text_splitter = SpacyTextSplitter(pipeline='zh_core_web_sm', chunk_size=320, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
db = FAISS.from_documents(docs, embeddings)
db.save_local(faiss_name)
以下代码是使用FaissSearchTool工具进行搜索的一个例子,流程大致如下:
-
- 创建FaissSearchTool对象,并传入数据库对象db。
-
- 使用await关键字对FaissSearchTool对象进行异步调用,并传入查询字符串"城市管理执法主管部门的职责是什么?"。
-
- 将搜索结果以格式化的形式进行打印,这里使用了pprint模块进行美化打印。最终的结果存储在变量res中。
备注: 目前有bug,多次访问会提示erniebot调用过于频繁,谁遇到
python
tool = FaissSearchTool(db=db)
res = await tool(query="D员义务是什么?")
from pprint import pprint
pprint(res)
XXXXXXXXXXXXXXXXXXXXXXXXXX关键字屏蔽
4.2 构建 Assistant
Assistant可以自主决定什么时候选择调用工具,什么时候进行聊天,以下是一个自主调用工具的示例。
python
# 创建一个ERNIEBot实例,使用"ernie-bot-8k"模型。
llm = ERNIEBot(model="ernie-bot-8k")
# 创建一个WholeMemory实例。这可能是一个用于存储对话历史和上下文信息的类,有助于模型理解和持续对话。
memory = WholeMemory()
# 创建一个FunctionalAgent实例。这个代理将使用上面创建的ERNIEBot模型和WholeMemory,同时传入了一个名为tool的工具。
agent = FunctionalAgent(llm=llm, tools=[tool], memory=memory)
python
query = "D员的权利有哪些?"
response = await agent.async_run(query)
# 使用agent的async_run方法来异步执行查询。由于这是异步操作,因此需要使用'await'关键字。
messages = response.chat_history
for item in messages:
print(item.to_dict())
python
{'role': 'assistant', 'content': 'XXXXXXXXXXXXXXXXXXXXXXXXXX关键字屏蔽', 'function_call': None}
四、总结
1.ERNIE Bot Agent的LangChain插件
ERNIE Bot Agent的LangChain插件目前包含如下组件:
ErnieBot
:大语言模型,用于完成文本补全任务。ErnieBotChat
:聊天模型,用于完成对话补全任务。ErnieEmbeddings
:文本嵌入模型,用于生成文本的向量表示。
2.ErnieEmbeddings 目前问题
- 文件过大、或者多,会报访问 过于频繁错误。
- 目前仅支持aistudio token认证,qianfan ak/sk还未支持。