智能体(Agent)¶
ERNIE Bot Agent 基于文心大模型的 Function Calling 能力实现了多工具编排和自动调度功能,并且允许工具、插件、知识库等不同组件的混合编排。
除了自动调度,我们未来还将支持更多的编排模式,例如手动编排、半自动编排,为开发者提供更大的灵活性。
在开始本教程前,我们需要先获取飞桨AI Studio星河社区的access_token并且其配置成环境变量,用于对调用大模型和工具中心进行鉴权。
Function Agent介绍¶
在此教程中,主要介绍一个自动智能调度的Function Agent的运行过程,Function Agent的编排能力由集成的LLM大语言模型(此处为文心)的函数调用能力驱动。
通常由Agent将用户的自然语言输入传递请求LLM生成一个可以解析的Action,
然后Agent根据Action,调用相应的工具或插件,然后完成此操作并再次请求LLM决定是否要产生下一个Action或者终止。
一个智能体的运行大致分为以下三步:
- 创建需要调用的工具
- 创建智能体
- 调用智能体
[Optional]建议将环境变量EB_AGENT_LOGGING_LEVEL设置为info打开相关日志,以方便观察智能体具体的运行过程。
接下来将按照这三步,结合一个具体的实例进行介绍:
实例的背景为创建一个英语学习智能体,帮助用户学习英语单词,包括单词的释义、近义词、反义词和例句并将相关信息添加到单词本。
import os
os.environ["EB_AGENT_LOGGING_LEVEL"] = "INFO"
os.environ["EB_AGENT_ACCESS_TOKEN"] = "<access_token>"
from pydantic import Field
from typing import Dict, Type, Any
from erniebot_agent.chat_models import ERNIEBot
from erniebot_agent.memory import HumanMessage, SlidingWindowMemory
from erniebot_agent.tools.base import Tool
from erniebot_agent.tools.schema import ToolParameterView
from erniebot_agent.agents import FunctionAgent
from erniebot_agent.tools import RemoteToolkit
from erniebot_agent.file import GlobalFileManagerHandler
定义ChatWithEB工具¶
在智能体(Agent)中,我们创建一个名为ChatWithEB的工具,该工具用于为用户的单词提供详细的释义,其中可以通过prompt或者system的方式来控制,达成用户的相关目标(本例中为按要求获取单词相关信息)。
同时ChatWithEB工具也是一个推荐的本地工具,加载在智能体当中用于每一个Run中途的交互,从而更好地完成智能体的功能。
例如在本例中,我们通过ChatWithEB工具来获取用户输入的单词的详细信息,进而能直接添加进入单词本当中。
如果不使用这个工具,那么用户无法通过一句简单的"帮我添加单词"同时执行这三个操作:
需要先通过OCR获得单词内容,然后开启下一轮对话通过prompt获得单词相关内容,然后再通过"帮我添加单词"添加相关单词。
class ChatWithEBInputView(ToolParameterView):
word: str = Field(description="需要获取详细信息的单词")
class ChatWithEBOutputView(ToolParameterView):
response: str = Field(description="单词的详细释义")
class ChatWithEB(Tool):
description: str = "ChatWithEB是一款根据用户的提供的单词,获取一个具体的单词描述、翻译以及例句的工具"
input_type: Type[ToolParameterView] = ChatWithEBInputView
ouptut_type: Type[ToolParameterView] = ChatWithEBOutputView
def __init__(self, llm: ERNIEBot):
self.llm = llm
async def __call__(self, word: str) -> Dict[str, str]:
prompt = f"请告诉我{word}的详细信息,以下面的格式输出(其中单词翻译需要是中文,其他为英语)" "<单词翻译>:\n<近义词>:\n<反义词>:\n<例句>:\n"
response = await self.llm.chat([HumanMessage(prompt)])
return {"response": response.content}
SYSTEM_MESSAGE = "你是一个英语老师,当用户给你一个单词的时候,请你专业而通俗的返回英语的<单词翻译><近义词><反义词><例句>"
llm = ERNIEBot(model="ernie-4.0", system=SYSTEM_MESSAGE)
word_helper_tool = ChatWithEB(llm)
class AddWordInput(ToolParameterView):
word: str = Field(description="待添加的单词")
des: str = Field(description="待添加的单词的详细释义,含有<单词翻译><近义词><反义词><例句>")
class AddWordOutput(ToolParameterView):
result: str = Field(description="表示是否成功将单词成功添加到词库当中")
class AddWordTool(Tool):
description: str = "添加单词以及它的详细解释到词库当中"
input_type: Type[ToolParameterView] = AddWordInput
ouptut_type: Type[ToolParameterView] = AddWordOutput
def __init__(self) -> None:
self.word_books = {}
super().__init__()
async def __call__(self, word: str, des: str) -> Dict[str, Any]:
if word in self.word_books:
return {"result": f"<{word}>单词已经存在,无需添加"}
self.word_books[word] = des
words = "\n".join(list(self.word_books.keys()))
return {"result": f"<{word}>单词已添加成功, 当前单词本中有如下单词:{words},释义如下{des}"}
add_word_tool = AddWordTool()
从AIStudio导入RemoteTool¶
此处不做过多介绍。详见RemoteTool相关文档。
ocr_tool = RemoteToolkit.from_aistudio("highacc-ocr").get_tools()[0]
创建智能体¶
在此步骤中将展示如何创建智能体。
指定调用的文心大模型,通过
enable_multi_step_tool_call接口打开multi_tool_call功能,开启之后即可通过一个指令进行多次不同工具的调用,通过max_steps控制此Run中执行的最大的Step以免一直循环。为智能体添加默认的
ChatWithEB和AddWordTool工具。[Optional]为智能体指定特殊的
Memory,默认为WholeMemory,详见memory机制讲解。[Optional]为智能体指定
SystemMessage,设置全局的指令。
memory = SlidingWindowMemory(max_round=5)
llm_final = ERNIEBot(model="ernie-3.5", api_type="aistudio", enable_multi_step_tool_call=True)
agent_all = FunctionAgent(llm=llm_final, tools=[word_helper_tool, add_word_tool, ocr_tool], memory=memory)
调用智能体¶
在完成了智能体创建之后,通过异步run函数执行指令,并获取返回结果(如果打开了multi_tool_call,那么仅需一句指令即可同时执行图片OCR,单词解释以及添加至单词本三个动作)。
如果需要运行过程中涉及到文件,可以先通过file_manager创建File对象,再通过run的files参数传入。
!wget https://paddlenlp.bj.bcebos.com/datasets/examples/road_sign.jpeg
--2023-12-28 18:10:19-- https://paddlenlp.bj.bcebos.com/datasets/examples/road_sign.jpeg Resolving paddlenlp.bj.bcebos.com (paddlenlp.bj.bcebos.com)... 36.110.192.178 Connecting to paddlenlp.bj.bcebos.com (paddlenlp.bj.bcebos.com)|36.110.192.178|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 44056 (43K) [image/jpeg] Saving to: 'road_sign.jpeg' road_sign.jpeg 100%[===================>] 43.02K --.-KB/s in 0.06s 2023-12-28 18:10:20 (695 KB/s) - 'road_sign.jpeg' saved [44056/44056]
file_manager = GlobalFileManagerHandler().get()
file = await file_manager.create_file_from_path(r"./road_sign.jpeg")
response = await agent_all.run("帮我把图片中的第一个英语单词进行解释之后添加到单词本中", files=[file])
INFO - [Run][Start] FunctionAgent is about to start running with input: 帮我把图片中的第一个英语单词进行解释之后添加到单词本中 INFO - [LLM][Start] ERNIEBot is about to start running with input: role: user content: 帮我把图片中的第一个英语单词进行解释之后添加到单词本中 <file>file-local-4ea15200-a569-11ee-a73d-56c70f692df9</file> INFO - [LLM][End] ERNIEBot finished running with output: role: assistant function_call: { "name": "highacc-ocr/v1.8/OCR", "thoughts": "用户需要我识别图片中的文字,并把第一个英语单词添加到单词本中。我需要先使用OCR工具提取图片中的文字,然后使用ChatWithEB工具获取单词的详细信息,最后使用AddWordTool工具将单词添加到词库中。任务拆解:[sub-task1: 使用OCR工具提取图片中的文字,sub-task2: 使用ChatWithEB工具获取单词的详细信息,sub-task3: 使用AddWordTool工具将单词添加到词库中]。接下来我需要调用[highacc-ocr/v1.8/OCR]来提取图片中的文字。", "arguments": "{\"image\":\"file-local-4ea15200-a569-11ee-a73d-56c70f692df9\",\"language_type\":\"ENG\"}" } INFO - [Tool][Start] RemoteTool is about to start running with input: { "image": "file-local-4ea15200-a569-11ee-a73d-56c70f692df9", "language_type": "ENG" } INFO - [Tool][End] RemoteTool finished running with output: { "words_result": [ "BEWARE", "OF FALLING", "COCONUTS" ], "words_result_num": 3 } INFO - [LLM][Start] ERNIEBot is about to start running with input: role: function name: highacc-ocr/v1.8/OCR content: {"words_result": ["BEWARE", "OF FALLING", "COCONUTS"], "words_result_num": 3} INFO - [LLM][End] ERNIEBot finished running with output: role: assistant function_call: { "name": "ChatWithEB", "thoughts": "我已经从图片中提取出了文字,现在我需要使用ChatWithEB工具获取第一个英语单词的详细信息。", "arguments": "{\"word\":\"BEWARE\"}" } INFO - [Tool][Start] ChatWithEB is about to start running with input: { "word": "BEWARE" } INFO - [Tool][End] ChatWithEB finished running with output: { "response": "<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary, Alert\n\n<反义词>: Reckless, Careless, Negligent, Unmindful\n\n<例句>:\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\n3. Beware of the icy road, it's very slippery. (小心结冰的路面,非常滑。)\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)" } INFO - [LLM][Start] ERNIEBot is about to start running with input: role: function name: ChatWithEB content: {"response": "<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary, Alert\n\n<反义词>: Reckless, Careless, N... INFO - [LLM][End] ERNIEBot finished running with output: role: assistant function_call: { "name": "AddWordTool", "thoughts": "我已经获取到了第一个英语单词的详细信息,现在我需要使用AddWordTool工具将这个单词添加到词库中。", "arguments": "{\"word\":\"BEWARE\",\"des\":\"<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it's very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)\"}" } INFO - [Tool][Start] AddWordTool is about to start running with input: { "word": "BEWARE", "des": "<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary, Alert\n\n<反义词>: Reckless, Careless, Negligent, Unmindful\n\n<例句>:\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\n3. Beware of the icy road, it's very slippery. (小心结冰的路面,非常滑。)\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)" } INFO - [Tool][End] AddWordTool finished running with output: { "result": "<BEWARE>单词已添加成功, 当前单词本中有如下单词:BEWARE,释义如下<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary, Alert\n\n<反义词>: Reckless, Careless, Negligent, Unmindful\n\n<例句>:\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\n3. Beware of the icy road, it's very slippery. (小心结冰的路面,非常滑。)\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)" } INFO - [LLM][Start] ERNIEBot is about to start running with input: role: function name: AddWordTool content: {"result": "<BEWARE>单词已添加成功, 当前单词本中有如下单词:BEWARE,释义如下<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary,... INFO - [LLM][End] ERNIEBot finished running with output: role: assistant content: 我已经将BEWARE这个单词添加到单词本中,它的意思是当心、小心,还有其他的释义和例句。如果您还有其他问题或需要添加更多单词,请随时告诉我。 INFO - [Run][End] FunctionAgent finished running.
print(response.text)
我已经将BEWARE这个单词添加到单词本中,它的意思是当心、小心,还有其他的释义和例句。如果您还有其他问题或需要添加更多单词,请随时告诉我。
add_word_tool.word_books
{'BEWARE': "<单词翻译>: 当心、小心\n\n<近义词>: Careful, Cautious, Wary, Alert\n\n<反义词>: Reckless, Careless, Negligent, Unmindful\n\n<例句>:\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\n3. Beware of the icy road, it's very slippery. (小心结冰的路面,非常滑。)\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}
Agent其他相关方法¶
除了上述主要功能以外,接下来这个章节主要用于介绍一些其他可能会使用到的智能体功能。
AgentResponse¶
AgentResponse作为智能体返回的结果,主要包含以下内容:
text: Agent在本Run中返回的最终文本steps: Agent在本Run中执行的Step。 含有tool_name(调用工具的名称),tool_args(工具的入参),input_files(输入的文件), output_files(输出的文件)Agent在步骤中涉及到的文件将存放在Step中,包括输入文件以及输出文件
chat_history: Agent在本Run中的对话历史status: 包括FINISHED和STOPPED,其中FINISHED表示正常结束,STOPPED表示智能体因达到最大step数目强行终止
response.chat_history
[<HumanMessage role: 'user', content: '帮我把图片中的第一个英语单词进行解释之后添加到单词本中\n<file>file-local-4ea15200-a569-11ee-a73d-56c70f692df9</file>', token_count: 1110>,
<AIMessage role: 'assistant', function_call: {'name': 'highacc-ocr/v1.8/OCR', 'thoughts': '用户需要我识别图片中的文字,并把第一个英语单词添加到单词本中。我需要先使用OCR工具提取图片中的文字,然后使用ChatWithEB工具获取单词的详细信息,最后使用AddWordTool工具将单词添加到词库中。任务拆解:[sub-task1: 使用OCR工具提取图片中的文字,sub-task2: 使用ChatWithEB工具获取单词的详细信息,sub-task3: 使用AddWordTool工具将单词添加到词库中]。接下来我需要调用[highacc-ocr/v1.8/OCR]来提取图片中的文字。', 'arguments': '{"image":"file-local-4ea15200-a569-11ee-a73d-56c70f692df9","language_type":"ENG"}'}, token_count: 190>,
<FunctionMessage role: 'function', name: 'highacc-ocr/v1.8/OCR', content: '{"words_result": ["BEWARE", "OF FALLING", "COCONUTS"], "words_result_num": 3}'>,
<AIMessage role: 'assistant', function_call: {'name': 'ChatWithEB', 'thoughts': '我已经从图片中提取出了文字,现在我需要使用ChatWithEB工具获取第一个英语单词的详细信息。', 'arguments': '{"word":"BEWARE"}'}, token_count: 32>,
<FunctionMessage role: 'function', name: 'ChatWithEB', content: '{"response": "<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}'>,
<AIMessage role: 'assistant', function_call: {'name': 'AddWordTool', 'thoughts': '我已经获取到了第一个英语单词的详细信息,现在我需要使用AddWordTool工具将这个单词添加到词库中。', 'arguments': '{"word":"BEWARE","des":"<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}'}, token_count: 235>,
<FunctionMessage role: 'function', name: 'AddWordTool', content: '{"result": "<BEWARE>单词已添加成功, 当前单词本中有如下单词:BEWARE,释义如下<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}'>,
<AIMessage role: 'assistant', content: '我已经将BEWARE这个单词添加到单词本中,它的意思是当心、小心,还有其他的释义和例句。如果您还有其他问题或需要添加更多单词,请随时告诉我。', token_count: 39>]
response.status
'FINISHED'
# Step为该Run中Agent所执行的相关操作,含有tool_name(调用工具的名称),tool_args(工具的入参),input_files(输入的文件), output_files(输出的文件)
response.steps
[ToolStep(info={'tool_name': 'highacc-ocr/v1.8/OCR', 'tool_args': '{"image":"file-local-4ea15200-a569-11ee-a73d-56c70f692df9","language_type":"ENG"}'}, result='{"words_result": ["BEWARE", "OF FALLING", "COCONUTS"], "words_result_num": 3}', input_files=[<LocalFile id: 'file-local-4ea15200-a569-11ee-a73d-56c70f692df9', filename: 'road_sign.jpeg', byte_size: 44056, created_at: '2023-12-28 18:10:20', purpose: 'assistants', metadata: {}, path: PosixPath('road_sign.jpeg')>], output_files=[]),
ToolStep(info={'tool_name': 'ChatWithEB', 'tool_args': '{"word":"BEWARE"}'}, result='{"response": "<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}', input_files=[], output_files=[]),
ToolStep(info={'tool_name': 'AddWordTool', 'tool_args': '{"word":"BEWARE","des":"<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}'}, result='{"result": "<BEWARE>单词已添加成功, 当前单词本中有如下单词:BEWARE,释义如下<单词翻译>: 当心、小心\\n\\n<近义词>: Careful, Cautious, Wary, Alert\\n\\n<反义词>: Reckless, Careless, Negligent, Unmindful\\n\\n<例句>:\\n1. Beware of dogs when you enter the park. (当你进入公园时要小心狗。)\\n2. You should always beware of scams when shopping online. (在网上购物时,你应该始终小心诈骗。)\\n3. Beware of the icy road, it\'s very slippery. (小心结冰的路面,非常滑。)\\n4. When hiking in the woods, beware of snakes and other wildlife. (在树林里徒步旅行时,要小心蛇和其他野生动物。)\\n5. Beware of opening email attachments from unknown sources. (小心打开来自未知来源的电子邮件附件。)"}', input_files=[], output_files=[])]
Tool以及Memory相关用法¶
# 获取当前所有工具
agent_all.get_tools()
[<name: ChatWithEB, description: ChatWithEB是一款根据用户的提供的单词,获取一个具体的单词描述、翻译以及例句的工具>, <name: AddWordTool, description: 添加单词以及它的详细解释到词库当中>, <name: highacc-ocr/v1.8/OCR, server_url: https://tool-highacc-ocr.aistudio-hub.baidu.com/, description: 用于提取并识别图片上的文字及位置信息>]
# 查找某个工具
eb_tool = agent_all.get_tool("ChatWithEB")
# 取消某个工具
agent_all.unload_tool(eb_tool)
# 加载某个工具
agent_all.load_tool(eb_tool)
# 获取Agent的对话历史
agent_all.memory.get_messages()
[<HumanMessage role: 'user', content: '帮我把图片中的第一个英语单词进行解释之后添加到单词本中\n<file>file-local-4ea15200-a569-11ee-a73d-56c70f692df9</file>', token_count: 1110>, <AIMessage role: 'assistant', content: '我已经将BEWARE这个单词添加到单词本中,它的意思是当心、小心,还有其他的释义和例句。如果您还有其他问题或需要添加更多单词,请随时告诉我。', token_count: 39>]
# 重置Agent的对话历史
agent_all.reset_memory()
agent_all.memory.get_messages()
[]